你真的理解对象吗?

154 阅读4分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。 本文已参与「掘力星计划」,赢取创作大礼包,挑战创作激励金。

前言

吃饱饭才有力气写代码~

今天聊一聊对象,这个对象不是你想象的那个对象,而是ECMAScript里的对象!

ECMA-262 把对象定义为一组属性的无需集合,也就是说对象就是一组没有特定顺序的值,对象中的每个属性或者方法都由一个名称来标识,这个名称映射到一个值,因此可以把ECMAScript里的对象想象成一张散列表,其中的内容就是一组名/值对,这个值可以是数据或者函数~

理解对象

创建自定义对象的常用方法就是创建Object的一个实例,然后再给它添加属性和方法,如下所示:

let person = new Object();
person.name = "Tom";
person.age = 18;
person.job = "Software Engineer";
person.sayName = function(){
    console.log(this.name);
}

上面这个例子创建了一个名为person的对象,而且有三个属性(name、age、job)和一个方法(sayName()),sayName()方法会显示this.name的值,这个属性会解析为person.name。这种写法是早期的写法,后来更多的是对象字面量:

let person = {
    name = "Tom";
    age = 18;
    job = "Software Engineer";
    sayName() {
        console.log(this.name);
    }
};

这个例子中的person对象跟前面例子中的person对象是等价的,它们的属性和方法都一样,这些属性有自己的特征,而这些特征决定了它们在JavaScript中的行为。

属性类型

什么是属性类型呢?在ECMA-262中使用一些内部特征来描述属性的特征,开发者不能在JavaScript中直接访问这些特征,这是JavaScript实现引擎的规范定义的,为了把它们标识为内部特性,规范会用中括号把特性的名称括起来,比如[[Enumerable]]

数据属性

数据属性包含一个保存数据值的位置,值会从这个位置读取,也会写入这个位置,数据属性有四个特性描述其行为:

  • [[Configurable]] 表示属性是否可以通过delete删除并重新定义,是否可以修改它的特性以及是否可以把它改为访问器属性,默认情况下所有直接定义在对象上的属性的这个特性都是true。
  • [[Enumerable]] 表示属性是否可以通过for-in循环返回,默认情况下所有直接定义在对象上的属性的这个特性都是true。
  • [[Writable]] 表示属性的值是否可以被修改,默认情况下所有直接定义在对象上的属性的这个特性都是true。
  • [[Value]] 包含属性实际的值,就是前面提到的那个读取和写入属性值的位置,它默认的值为 undefined。 像前面那个例子,把那些属性显示地添加在对象上之后, [[Configurable]] , [[Enumerable]] , [[Writable]] 值都设为true, [[Value]] 被设为指定的值,比如:
let person = {
    name = "Tom";
};

name的属性赋值为"Tom",那么 [[Value]] 特性也会被设置为"Tom",之后对这个值的任何修改都会保存在这个位置。
想要修改属性的这些默认的特性的值,需要使用Object.defineProperty()方法,如下:

let person = {};
Object.defineProperty(person,"name",{
    writeable: false;
    value: "Tom";
});
console.log(person.name)//"Tom"
person.name = "Jack";
console.log(person.name)//"Tom"

这个方法接收三个参数,将要添加属性的对象、属性的名称、描述符对象;描述符对象上的属性跟是上面四种特性名称一一对应,根据要修改的特性,可以修改一个或多个;

注意:

上述规则也可以用于创建不可配置的属性,特性名为configurable,把它设置为false后意味着这个属性不能从对象上删除,而且一旦被设置为不可配置后,就不能再变回可配置的了。

let person = {};
Object.defineProperty(person,"name",{
    configurable : false;
    value: "Tom";
});
console.log(person.name)//"Tom"
delete person.name;
console.log(person.name)//"Tom"没删掉


Object.defineProperty(person,"name",{
    configurable : true;
    value: "Tom";
});//抛出错误

总结

除了上述四类数据属性,还有一种访问器属性,这个下次再谈。虽然我们多数情况下并不会直接用到Object.defineProperty()方法,但是想要理解JavaScript对象,这些东西需要有个概念!