JavaScrtip关于对象的相关知识

95 阅读4分钟

这是我参与「第四届青训营 」笔记创作活动的第3天

总体知识

ECMA-262使用一些内部特性来描述属性的特征。开发者不能在 JavaScript 中直接访问这些特性。为了将某个特性标识为内部特性,规范会用两个中括号把特性的名称括起来,比如[[Enumerable]]。

属性有两种:数据属性和访问器属性。

数据属性

  • [[Configurable]]:表示属性是否可以通过 delete 删除并重新定义,是否可以修改它的特性,以及是否可以把它改为访问器属性。默认情况下,所有直接定义在对象上的属性的这个特性都是 true,如前面的例子所示。

  • [[Enumerable]]:表示属性是否可以通过 for-in 循环返回。默认情况下,所有直接定义在对象上的属性的这个特性都是 true,如前面的例子所示。

  • [[Writable]]:表示属性的值是否可以被修改。默认情况下,所有直接定义在对象上的属性的这个特性都是 true,如前面的例子所示。

  • [[Value]]:包含属性实际的值。这就是前面提到的那个读取和写入属性值的位置。这个特性的默认值为 undefined。

这里我们可以写一个例子

用Object..defineProperty(),可以修改默认的属性,参数有三个:对象、属性的名称和一个描述符对象,描述符对象就是上面所提到的四个数据属性

let person2 = {};
Object.defineProperty(person2, 'name', {writable: false/*重点!*/, value: 'MikuScallion'});
// 一旦设置为不可配置以后,就不能设置为可配置了。
Object.defineProperty(person2, 'age', {configurable: false, value: 21});
// 会报错
Object.defineProperty(person2, 'age', {configurable: true, value: 21});

console.log(person2.name);
person2.name = 'wq';
console.log(person2.name);

console.log(person2.age);
// 无法删除掉,下面的console还会继续运行。
delete person2.age;
console.log(person2.age);
  1. 这里把person2对象中的name属性的writable属性设置为false,也就是不可以被修改的。然后把value属性设置为‘MikuScallion’,也就是name的值时多少。

  2. 我们试图把person2.name的值设置为‘wq’。我们可以看看最后的结果

  3. 值没有改变!

  4. 下面我们讲configurable设置为false并试着删除,发现无法删除。

  5. configurable设置为true报错。

  6. 在调用 Object.defineProperty()时,configurable、enumerable 和 writable 的值如果不指定,则都默认为 false。

访问器属性

个人理解:访问器属性最重要的两个方法就是get()方法和set方法。这两个是决定对象中对那个值进行修改和读取的。对某个属性设置时,如果只设置了get()方法,证明了此属性时不可以修改值的。如果只设置了set()方法,证明此属性时不可访问读取的。对于设置set和get的方法也时使用Object.defineProperty。

 let book = 
        {
            year_: 2017,
            edition: 1
        };

        // 对year属性设置get和set函数,这样时无法直接访问
        Object.defineProperty(book, 'year',{
                get()
                {
                    return this.year_;
                }
                set(newValue)
                {
                    if (newValue > 2017)
                    {
                        this.year_ = newValue;
                        this.edition += newValue - 2017;
                    }
                } 
            }
        )

        book.year = 2018;
        console.log(book.edition);
  • 对于属性带下划线year_表示的时不希望外部可以访问到此属性,但是可以通过一些方法来设置此属性。

  • 我们设置了一个新的year属性来代替year_

  • 如果我们想要获得year_的值,我们直接打印就好,因为给year设置了get方法。

  • 如果我们想要设置year_ 的值,我们直接赋值就好,因为我们给year也设置了set方法。

  • 因为我们设置了year = 2018,我们最后edtion的值就变成了2。

定义多个属性

使用的是 Object.defineProperties

 let book1 = {};
        Object.defineProperties(book1,
            {
                year_: {
                    value: 2017
                },
                edition: {
                    value: 1
                },
                year: {
                    get(){
                        return this.year_;
                    },
                    set(newValue){
                        if (newValue > 2017)
                        {
                            this.year_ = newValue;
                            this.edition += newValue - 2017;
                        }
                    }
                }
            }
        )

        book1.year = 5000;
        console.log(book1.edition);

这段代码在 book 对象上定义了两个数据属性 year_和 edition,还有一个访问器属性 year。最终的对象跟上一节示例中的一样。唯一的区别是所有属性都是同时定义的,并且数据属性的configurable、enumerable 和 writable 特性值都是 false

所以可以增加一些设置让程序可以跑起来,例如给year_和edition设置writable: true,这样就可以读写了。

读取属性

使用 Object.getOwnPropertyDescriptor()方法可以取得指定属性的属性描述符。这个方法接

收两个参数:属性所在的对象和要取得其描述符的属性名

descript = Object.getOwnPropertyDescriptor(book1, 'year');
console.log(descript.value);        // undefined 
console.log(descript.configurable); // false 
console.log(typeof descript.get);   // function
descript1 = Object.getOwnPropertyDescriptor(book1, 'year_');
console.log(descript1.value);       // 2018
console.log(descript1.configurable);// false
console.log(typeof descript1.get);  // undefined        // undefined console.log(descript.configurable); // false console.log(typeof descript.get);   // functiondescript1 = Object.getOwnPropertyDescriptor(book1, 'year_');console.log(descript1.value);       // 2018console.log(descript1.configurable);// falseconsole.log(typeof descript1.get);  // undefined

ECMAScript 2017 新增了 Object.getOwnPropertyDescriptors()静态方法。这个方法实际上

会在每个自有属性上调用 Object.getOwnPropertyDescriptor()并在一个新对象中返回它们。

  console.log(Object.getOwnPropertyDescriptors(book1));
        /* 
            edition: {value: 2, writable: true, enumerable: false, configurable: false}
            year: {enumerable: false, configurable: false, get: ƒ, set: ƒ}
            year_: {value: 2018, writable: true, enumerable: false, configurable: false}
            [[Prototype]]: Object
         */