可能很多人都知道最近很火的MVVM(model-view-virtualModel)框架,如Vue/Angular/React,如果你不知道的话,就要抓紧学习了,它能够把你从高频复杂的DOM解析中解脱出来。
MVVM框架的最主要的特性就是双向数据绑定,其中使用了ES5的getter/setter函数,而他们就是对象的访问器属性,如果你不清楚它们的具体用法,那就不算是真正了解Javascript的基础知识对象的属性,现在让我们一起回顾和总结下对象的属性。

对象

让我们先看下对象的定义:

无序属性的集合,其属性可以包含基本值,对象或者函数。   ------ ECMA-262

也就是我们可以定义的对象属性只能是下面三种:

var person = {
    // 属性
    name: 'Nicholas',
    // 对象
    job: {
        name: 'teacher',
        salary: 10000
    },
    // 函数
    greet: function () {
        alert('hello');
    }
};

对象的属性

JavaScript中只包含有两种属性:数据属性和访问器属性,并包含不同的特征。

数据属性包含数据值的位置,可以在该位置对其进行读写。其包含4个特征:

   configurable: 布尔值,表示能否通过delete属性来删除属性或修改属性的特性。
   enumerable: 布尔值,是否能通过`for-in`循环或`Object.keys()`返回属性。
   writable: 布尔值,属性值是否可以修改。
   value: 属性的数据值,实质指向的是读写数据的位置。默认为undefined。

数据属性可以通过属性访问器(即点运算符和方括号计算表达式)来设置属性,也可以通过Object.defineProperty() 或 Object.defineProperties()设置(下面统一用defineProperty代指两者)。而区别在于为布尔值的特征的默认值,通过属性访问器设置的默认都是true,而通过定义属性设置的默认都是false。

访问器属性不包含数据值,包含一对儿getter/setter函数(非必须),在读取访问器属性时,调用getter函数,负责返回有效的值;在写入属性时,调用setter函数并传入新值,负责决定如何处理数据。其包含4个特征:

    configurable: 布尔值,表示能否通过delete属性来删除属性或修改属性的特性,默认为false。
    enumerable: 布尔值,是否能通过`for-in`循环或`Object.keys()`返回属性,默认为false。
    get: 读取属性时调用的函数,默认为undefined。
    set: 写入属性时调用的函数,接收唯一参数,默认为undefined。

访问器属性只能通过defineProperty来定义。

如果属性已经存在,我们可以用defineProperty再次修改该属性的特征,也可以通过Object.getOwnpropertyDescriptor() 或 Object.getOwnpropertyDescriptors()来查看其特征列表。对于configurable = true的属性我们也可以使用delete操作符进行删除,如果设置成了不可配置的,我们就再也不能把它变回可配置的了。

属性访问器

有时我们会通过getter/setter来代理一个属性的读取操作,即实现一个伪属性,但是这个属性不能与真实属性重名,否则会覆盖真实属性的值,变成动态获取,这可能不是你想要的结果。

// 实例:保存当前值变化的日志记录
var o = {
    set current (str) {
        this.log[this.log.length] = str;
    },
    get current () {
        return this.log.join(',');
    },
    log: []
};

这样我们就代理current,用于保存实时日志,每次对log的更新也变成了一个操作历史档案,方便实时查看我们的所有改动。
同样我们可以在configurable配置为true的时候删除该属性的代理:delete o.current

关于delete,如果我们删除了一个var/let/const属性,在其声明的作用域下会返回false,如果是严格模式,则会抛出语法错误。删除一个不可配置的属性同理会失败或报错。
删除数组的下标时,length并不会变小,遍历到该下标时会跳过执行。

影响configurable的方法

另外,存在一些Object的方法会影响到对象属性的可配置性:

  1. Object.freeze()
    该方法可以冻结一个对象,冻结指的是不能向这个对象添加新的属性,不能修改其已有属性的值,不能删除已有属性,以及不能修改该对象已有属性的可枚举性、可配置性、可写性。也就是说,这个对象永远是不可变的。该方法返回被冻结的对象。
    冻结指的是表层属性的浅冻结,如果需要冻结嵌套的属性,则需要遍历并递归冻结子属性。
  2. Object.preventExtensions()
    该方法让一个对象变的不可扩展,也就是永远不能再添加新的属性。需要注意的是不可扩展的对象的属性通常仍然可以被删除,同时会阻止一个对象将__proto__属性重新指向另一个对象。
  3. Object.seal()
    该方法可以让一个对象密封,并返回被密封后的对象。密封对象将会阻止向对象添加新的属性,并且会将所有已有属性的可配置性(configurable)置为不可配置(false),即不可修改属性的描述或删除属性。但是可写性描述(writable)为可写(true)的属性的值仍然被修改。

参考资料

  1. MDN - Object: https://developer.mozilla.org...
  2. JavaScript高级编程 - 对象类型

赵帅强
3.3k 声望380 粉丝

前端打工人