一个你能够没有注意到的关于JavaScript属性设置的学问

本日看《你不知道的JavaScript》第五章——原型的时刻,注意到一个关于JavaScript属性设置的有意思的处所。(P145

之前,我认为除了对象被设置为不可扩大的状况,其他状况下给对象增加新属性都邑胜利。但没想到,另有其他不能增加新属性的状况。我所说的这类状况,就是原型链上有与你将要增加的属性同名的属性的时刻。

分类

原型链上有与你将要增加的属性同名的属性的状况,还要分红三种状况:

  • 原型链上有同名的数据属性而且没有被标记为只读,即writable: true

  • 原型链上有同名的数据属性,但它被标记为只读,即writable: false

  • 原型链上有同名的存取器属性,且最少设置了setter

划定规矩

这里以设置myObject.foo = 'my'为例。

同名数据属性、可读

假如在[[Prototype]]链上层存在名为foo的一般数据接见属性而且没有被标记为只读(wirtable: false),那末就会在myObject中增加一个名为foo的新属性,它就是屏障属性。

这类状况是最常见的,下面贴一个简朴的例子。

var proObject = {
    foo: 'pro'
}
var myObject = Object.create(proObject)
myObject.foo = 'my'
myObject.foo                      // 'my'
myObject.hasOwnProperty('foo')    // true

同名数据属性、只读

假如在[[Prototype]]链上层存在foo,然则它被标记为只读(writable: false),那末没法修正已有属性或许在myObject上建立屏障属性。假如运行在严厉形式下,代码会抛出一个毛病。不然,这条赋值语句会被疏忽。

var proObject = {}
Object.defineProperty(proObject, 'foo', {
    value: 'pro',
    wirtable: false
})
var myObject = Object.create(proObject)
myObject.foo = 'my'
myObject.foo                      // 'pro'
myObject.hasOwnProperty('foo')    // false

'use strict'
myObject.foo = 'my'    // Uncaught TypeError: Cannot assign to read only property 'foo' of object '#<Object>'

同名的存取器属性

假如在[[Prototype]]链上层存在foo而且它是一个setter,那就一定会挪用这个setter。foo不会被增加到(或许说屏障于)myObject,也不会从新定义foo这个setter。

var proObject = {}
Object.defineProperty(proObject, 'foo', {
    set: function(val) {
        this.s = val
    },
    get: function() {
        return this.s
    }
})
myObject.foo = 'my'
myObject.hasOwnProperty('foo')    // false

// 能够看到存取器属性没有被从新定义
Object.getOwnPropertyDescriptor(proObject, 'foo') 

解决方案

假如你愿望在上述的第二和第三中状况下为myObject增加新属性的话,你须要运用Object.defineProperty或许Object.getOwnPropertyDescriptors来增加新属性。

结语

终究在周日完成了这周的博客文章了(虽然很无耻地“水了一篇”,但好歹也算一篇文章嘛。)

正派一点!!!JavaScript中另有许多让我们出人意料的处所,虽然日常平凡很少碰到这些方面学问的运用,但一旦踩了这些坑,照样会耗掉我们挺多时候和精神的。所以,我们日常平凡应当多注意这些学问,并积聚下来。那末当我们碰到关于这些学问的bug的时刻,就会很快将问题解决了。

    原文作者:chenBright
    原文地址: https://segmentfault.com/a/1190000007399312
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞