javascript对象的属性描述符

经常会看到一些技术文章说,可枚举不可枚举,一直很懵。其实就是对象属性描述符中的Enumerable(可枚举性)。下面来看看有哪些对象属性描述符~

描述符类型

分为两种

  1. 数据属性(data property) 包含一个数据值的位置,在这个位置可以读取和写入值,有四个特性
  2. 访问器属性(accessor poperty) 名字、值和一组属性描述符构成的。而属性值可以用一个或两个方法替代,这两个方法就是getter和setter

他们共同的特性

  • configurable(可配置性)

    可配置性决定是否可以使用delete删除属性,以及是否可以修改属性描述符的特性,默认true;

    设置为false后无法使用delete删除属性,严格模式下直接报错;并且不能使用defineProperty()方法来修改属性描述符,但可以用使用defineProperty()方法将writable的状态从true改为false(只有这一种情况可以修改);var声明变量时默认为false;

  • enumerable(可枚举性)

    可枚举性决定属性是否出现在对象的属性枚举中。

    用户定义的普通属性默认是可枚举的,而原生继承的属性默认是不可枚举的。

    • propertyIsEnumerable() 可以判断对象的属性是否可枚举

      1
      2
      3
      4
      5
      6
      var o = {a:1};
      console.log(o.propertyIsEnumerable('a'))
      //true
      Object.defineProperty(o,'a',{enumerable:false})
      console.log(o.propertyIsEnumerable('a'))
      //false

具体来说,比如

  • fon in 循环是否能遍历到该属性
  • Object.keys方法是否能取到该属性
  • JSON.stringify方法是否能取到该属性

不同的特性

数据属性 :
  • value (属性值)

    属性值包含这个属性的数据值,读取属性值的时候,从这个位置读,写入属性值的时候,把新值保存在这个位置。默认undefined。

  • writable (可写性)

    可鞋型决定是否可以修改属性的值,默认为true;设置为false后赋值语句会静默失败,严格模式赋值直接报错;

    通过Object.defineProperty()方法改变属性value的值不会受影响,因为这也意味着在重置writable的属性值为false

访问器属性:
  • getter

    在读取属性时调用的函数。默认undefined

  • setter

    在写入属性时调用的函数。默认undefined

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    // getter 和 setter 取代了数据属性中的value和writable属性
    // 只设置get方法没有set方法 对象的赋值会静默失败 严格模式下会报错
    // 只设置set方法而不设置get方法 对象的属性值为undefined
    // 所以一般都是成对出现的
    var o ={
    get a(){
    return this._a;
    },
    set a(val){
    this._a = val*2;
    }
    }
    o.a = 1;
    console.log(o.a);//2
    // 可读可取
    // 利用Object.defineProperty()对o的属性a的getter和setter进行配置
    Object.defineProperty(o,'a',{
    get: function(){
    return this._a;
    },
    set :function(val){
    this._a = val*2;
    }
    })
    o.a = 1;
    console.log(o.a);//2

描述符方法

  • Object.getOwnPropertyDescriptor()

    第一个参数是该对象,第二个参数时对象的某一个属性。用于查询一个属性的描述符,并以对象的形式返回

    1
    2
    3
    let obj = {holly: 'nice'}
    console.log(Object.getOwnPropertyDescriptor(obj, 'holly'))
    // {value: "nice", writable: true, enumerable: true, configurable: true}

  • Object.defineProperty()

    第一个参数时对象,第二个参数是对象的某一个属性,第三个参数是要修改的配置;用于创建或配置对象的一个属性的描述符,返回配置后的对象(创建时,如果不针对描述符配置,则该项描述符默认false)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    let holly = {}
    console.log(Object.defineProperty(holly, 'name', {
    value: 'holly',
    writable: true
    }))
    // {name: "holly"} 返回该对象
    console.log(Object.getOwnPropertyDescriptor(holly, 'name'))
    // {value: "holly", writable: true, enumerable: false, configurable: false}
    // 由于没有配置 enumerable和configurable 为false
  • Object.defineProperties()

    第一个参数是该对象,第二个是要修改的属性为键 特性为值组成的对象;用于创建或配置对象的多个属性的描述符,返回配置后的对象。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    let desc = {a: 1, b: 2}
    console.log(Object.defineProperties(desc, {
    a: {
    value: 3,
    enumerable: false
    },
    b: {writable: true}
    }))
    // {b: 2, a: 3}
    console.log(console.log(Object.getOwnPropertyDescriptor(desc, 'a')))
    // {value: 3, writable: true, enumerable: false, configurable: true}
    console.log(Object.getOwnPropertyDescriptor(desc, 'b'))
    // {value: 2, writable: true, enumerable: true, configurable: true}
  • Object.create()

    第一个参数指定原型,第二个参数属性和描述符对象;用于指定原型和属性来创建一个对象

    1
    2
    3
    4
    5
    6
    7
    let newOne = Object.create(Object.prototype, {
    a: {value: 'hello', enumerable: true}
    })
    console.log(newOne)
    // {a: "hello"}
    console.log(Object.getOwnPropertyDescriptor(newOne,'a'))
    // {value: "hello", writable: false, enumerable: true, configurable: false}

    参考链接: https://www.cnblogs.com/xiaohuochai/p/5743821.html

应用场景

  • 大部分是框架才会用到,比如Vue.js的双向数据绑定
------ 本文结束------
0%