资讯专栏INFORMATION COLUMN

如何禁止JavaScript对象重写?

jubincn / 2929人阅读

摘要:译者按使用和,可以禁止重写对象。引入了一些方法,允许开发者限制对象重写。不要重写他人的对象不要重写他人的对象,这是的黄金法则。如果你修改的是对象比如,这会导致非常严重的后果。

译者按: 使用Object.preventExtensions()、Object.seal()和Object.freeze(),可以禁止重写JavaScript对象。

译者:Fundebug

原文:Preventing modification of JavaScript objects

由于JavaScript的灵活性,我们可以轻易地重写(override)一些于其他人定义的对象(object)。换句话说,任何人都可以重写我们所定义的对象。这是一个非常强大的特性,许多开发者都有兴趣试试,来拓展或者修改某些对象的行为。例如,DOM方法document.getElementById()都可以被重写。一般来讲,我们应该避免这样做,因为这会导致代码很难维护,并且会留下一些难于发现的BUG。ECMAScript 5引入了一些方法,允许开发者限制对象重写。如果你在开发一些工具库比如jQuery, fundebug等, 或者你的开发团队非常大,本文介绍的这些方法将非常有用。

不要重写他人的对象

不要重写他人的对象,这是JavaScript的黄金法则。比如,当你重写了一个方法,则很可能这会影响依赖于该方法的库,这会让其他开发者非常困惑。

// 示例代码1
window.originalAlert = window.alert;  
window.alert = function(msg) {  
    if (typeof msg === "string") {
        return console.log(msg);
    }
    return window.originalAlert(msg);
};

alert("ooh so awesome"); // 参数为字符串时,打印到控制台 
alert(3.14); // 参数为其他类型时,弹出对话框

示例代码1中,我修改了windows.alert:参数为字符串时,打印到控制台;参数为其他类型时,弹出对话框。这样的修改显然会影响其他使用alert方法的开发者。如果你修改的是DOM对象比如getElementById(),这会导致非常严重的后果。

如果你只是为对象添加新的方法,这也会导致问题。

// 示例代码2
Math.cube = function(n) {  
    return Math.pow(n, 3);
};
console.log(Math.cube(2)); // 8

这样做最大的问题是有可能在未来导致命名冲突。尽管Math对象目前并没有cube方法,下一个版本的JavaScript标准也许会增加cube方法(当然可能性不大),这就意味着我们会把原生cube方法给替代了。有一个真实的案例,Prototype库定义了document.getElementsByClassName()方法,而这个方法后来被加入了JavaScript标准。

不幸的是,我们无法阻止其他开发者重写我们定义的对象,这时我们就需要本文介绍的这些方法了:

首先,我们不妨通过一个表格对比一下Object.preventExtensions()、Object.seal()和Object.freeze():

方法 禁止增加属性 禁止删除属性 禁止修改属性
Object.preventExtensions()
Object.seal()
Object.freeze()
Object.preventExtensions()

使用Object.preventExtensions(),可以禁止给对象添加新的方法或者属性。注意,修改或者删除对象已经存在的方法或者属性是没有问题的。使用Object.isExtensible()可以查看某个对象是否可以增加方法或者属性。

// 示例代码3
var song = {  
    title: "Hope Leaves",
    artist: "Opeth"
};


console.log(Object.isExtensible(song)); //true  
Object.preventExtensions(song);  
console.log(Object.isExtensible(song)); //false  


song.album = "Damnation";
console.log(song.album);  // undefined


song.play = function() {  
    console.log("ahh soo awesome");
};
song.play(); // TypeError: song.play is not a function

示例代码3可知,执行Object.preventExtensions()之后,为song对象新增album以及play方法都失败了!

但是,当我们为song新增属性或者方法时,并没有报错。当我们使用了"use strict"采用严格模式时,情况就不一样了:

// 示例代码4
"use strict";

var song = {  
    title: "Hope Leaves",
    artist: "Opeth"
};

Object.preventExtensions(song);  

song.album = "Damnation"; // Uncaught TypeError: Cannot add property album, object is not extensible

在严格模式下,给已经Object.preventExtensions的对象新增属性时,会立即报错。广告:如果你希望实时监控应用中类似的错误,欢迎免费试用Fundebug

Object.seal()

使用Object.seal(),可以禁止给对象添加属性或者方法(这一点与Object.preventExtension()的作用一致),同时禁止删除对象已经存在的属性或者方法。

// 示例代码5
"use strict"
var song = {
    title: "Hope Leaves",
    artist: "Opeth"
};

Object.seal(song);
console.log(Object.isExtensible(song)); //false  
console.log(Object.isSealed(song)); //true  

song.album = "Damnation"; // Uncaught TypeError: Cannot add property album, object is not extensible
delete song.artist; // Uncaught TypeError: Cannot delete property "artist" of #
Object.freeze()

使用Object.freeze(),可以禁止为对象增加属性或者方法(这一点与Object.preventExtension()的作用一致),同时禁止删除对象已经存在的属性或者方法(这一点与Object.seal()的作用一致),另外还禁止修改已经存在的属性或者方法。

// 示例代码6
"use strict"
var song = {
    title: "Hope Leaves",
    artist: "Opeth",
    getLongTitle: function()
    {
        return this.artist + " - " + this.title;
    }
};

Object.freeze(song);

console.log(Object.isExtensible(song)); // false  
console.log(Object.isSealed(song)); // true  
console.log(Object.isFrozen(song)); // true  

song.album = "Damnation"; // Uncaught TypeError: Cannot add property album, object is not extensible  
delete song.artist; // Uncaught TypeError: Cannot delete property "artist" of # 
song.getLongTitle = function() // Uncaught TypeError: Cannot assign to read only property "getLongTitle" of object "#"
{
    return "foobar";
};

主流浏览器的最新版本都支持这些方法:

IE 9+

Firefox 4+

Safari 5.1+

Chrome 7+

Opera 12+

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/96023.html

相关文章

  • 前端如何定义一个常量

    摘要:很多编程语言提供了关键词声明一个常量,在中也是提供了,但是在前端的与其他编程语言不同,其并不意味着声明的变量就是一个常量。所以,在前端中到底如何实现一个常量可以冻结对象,不能新增和删除属性,同时对象已有属性都是不可枚举不可配置不可写。 很多编程语言提供了const关键词声明一个常量,在ES6中也是提供了const,但是在前端的const与其他编程语言不同,其并不意味着声明的变量就是一个...

    widuu 评论0 收藏0
  • MongoDB指南---4、MongoDB基础知识-使用MongoDB Shell

    摘要:也可以在中使用函数来执行命令行程序。注意,这种方式并不能保护数据库免受恶意用户的攻击,只能预防自己的手误。必须使用语法才能将解释为相应的变量。上一篇文章指南基础知识数据类型下一篇文章指南创建删除文档 上一篇文章:MongoDB指南---3、MongoDB基础知识-数据类型下一篇文章:MongoDB指南---5、创建、删除文档 本节将介绍如何将shell作为命令行工具的一部分来使用,如...

    mykurisu 评论0 收藏0
  • MongoDB指南---4、MongoDB基础知识-使用MongoDB Shell

    摘要:也可以在中使用函数来执行命令行程序。注意,这种方式并不能保护数据库免受恶意用户的攻击,只能预防自己的手误。必须使用语法才能将解释为相应的变量。上一篇文章指南基础知识数据类型下一篇文章指南创建删除文档 上一篇文章:MongoDB指南---3、MongoDB基础知识-数据类型下一篇文章:MongoDB指南---5、创建、删除文档 本节将介绍如何将shell作为命令行工具的一部分来使用,如...

    wujl596 评论0 收藏0
  • 从0到1使用VUE-CLI3开发实战(六):这是一个有代码洁癖的项目

    摘要:从到使用开发实战六这是一个有代码洁癖的项目一个小故事一天我路过一座桥,碰巧看见一个人想跳河自杀。配置什么是是一个开源的代码检查工具,由于年月创建。使用编写,这样既可以有一个快速的运行环境的同时也便于安装。 从0到1使用VUE-CLI3开发实战(六):这是一个有代码洁癖的项目 一个小故事 一天我路过一座桥,碰巧看见一个人想跳河自杀。我跑过去对他大喊道:别跳,别死啊。为什么不让我跳?他说。...

    genefy 评论0 收藏0
  • Cookie/Session机制详解

    摘要:要跟踪该会话,必须引入一种机制。服务器检查该,以此来辨认用户状态。提示中保存中文只能编码。不推荐使用等中文编码,因为浏览器不一定支持,而且也不支持编码。这是由的隐私安全机制决定的。隐私安全机制能够禁止网站非法获取其他网站的。会话(Session)跟踪是Web程序中常用的技术,用来跟踪用户的整个会话。常用的会话跟踪技术是Cookie与Session。Cookie通过在客户端记录信息确定用户身份...

    番茄西红柿 评论0 收藏0

发表评论

0条评论

jubincn

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<