视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
如何禁止JavaScript对象重写
2020-11-27 19:34:03 责编:小采
文档


这篇文章主要介绍了关于如何禁止JavaScript对象重写,有着一定的参考价值,现在分享给大家,有需要的朋友可以参考一下

译者按: 使用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>

    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+

  • 下载本文
    显示全文
    专题