怎样制止JavaScript对象重写?

译者按: 运用Object.preventExtensions()、Object.seal()和Object.freeze(),能够制止重写JavaScript对象。

由于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>

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 #<Object> 
song.getLongTitle = function() // Uncaught TypeError: Cannot assign to read only property 'getLongTitle' of object '#<Object>'
{
    return "foobar";
};

主流浏览器的最新版本都支撑这些要领:

  • IE 9+
  • Firefox 4+
  • Safari 5.1+
  • Chrome 7+
  • Opera 12+
    原文作者:Fundebug
    原文地址: https://segmentfault.com/a/1190000015569357
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞