0%

javaScript属性描述对象整理


概述以及定义:

  • JavaScript 提供了一个内部数据结构,用来描述对象的属性,控制它的行为,比如该属性是否可写、可遍历等等。
  • 这个内部数据结构称为“属性描述对象”(attributes object)。每个属性都有自己对应的属性描述对象,保存该属性的一些元信息。

属性描述对象有以下六个元属性(一个代码块)来描述对象的属性:

1
2
3
4
5
6
7
8
{
value: 123,
writable:fasel,
enumerable: true,
configurable: false,
get: undefined,
set: undefined
}

修改属性描述符

  1. value:该属性的属性值

    1
    2
    3
    4
    5
    6
    7
    8
    var obj = {}//声明一个空对象
    obj.p = 123;//声明obj的一个属性p

    Object.getOwnPropertyDescriptor(obj, 'p').value;//通过Object.getOwnPropertyDescriptor()函数获取
    //123

    Object.defineProperty(obj,'p',{value:456});//通过Object.defineProperty()对属性value进行修改
    //456
  2. writable:布尔值,决定该属性是否可改变,默认true

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    var obj = {};

    Object.defineProperty(obj,'a',{
    value: 37,
    writable: false,//修改该属性对象描述中的writable为不可修改
    });

    obj.a//37
    obj.a = 23;
    //1.正常模式下上一行代码修改对象属性描述对象的writable值为false的操作不会报错,但是严格模式下任何赋值行为都会报错
    //2.接第一点如果,因为子对象继承该父对象,子对象将无法自定义这个属性,也就是说,在严格模式下,父对象定义好了writable的值而子对象修改writable的值会报错
    //3.接上面两点,有一个规避方法,就是通过覆盖属性描述对象

    obj.a//无法被修改,所以仍然为37

  3. enumerable:布尔值,表示该属性是否可遍历,默认为true

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    var obj = {};

    Object.defineProperty(obj, 'x', {
    value: 123,
    enumerable: false
    });

    obj.x // 123

    for (var key in obj) {
    console.log(key);
    }
    // undefined

    //enumerable为false,下面三个操作不会取到该属性。

    for..in循环(for...in循环包括继承的属性)
    Object.keys方法(Object.keys方法不包括继承的属性)
    JSON.stringify方法
  4. configurable:布尔值,表示该属性是否可遍历,默认为true,设置为false会使得某些操作(for..in…或者Object.keys())跳过该属性

    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
    //1.如果对象的属性描述对象中的configurable属性被设为了false值,那么相关的这个对象中的configurable为false时,writable、enumerable和configurable都不能被修改了。(浅不变性)

    //2.value属性的情况比较特殊。只要writable和configurable有一个为true,就允许改动value

    var obj = Object.defineProperty({}, 'p', {
    value: 1,
    writable: false,
    enumerable: false,
    configurable: false
    });

    Object.defineProperty(obj, 'p', {writable: true})
    // TypeError: Cannot redefine property: p
    //3.writable属性只有在false改为true时会报错,true改为false是允许的。

    Object.defineProperty(obj, 'p', {enumerable: true})
    // TypeError: Cannot redefine property: p

    Object.defineProperty(obj, 'p', {configurable: true})
    // TypeError: Cannot redefine property: p

    Object.defineProperty(obj, 'p', {value: 2})
    // TypeError: Cannot redefine property: p

    //4.并且可配置性决定了目标属性是否可以被删除(delete),configurable是true,就可以被删除,否则就不行

对象常量

也就是说,上面//1.的obj.p属性设置成writable:false,configurable:false后,这个对象的这个属性就变成了常量,不可修改,不可删除,不可定义

  1. 存取器:get:是一个函数,表示该属性的取值函数(getter),默认为undefined

    set:是一个函数,表示该函数的存值函数(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
    27
    var obj = Object.defineProperty({}, 'p', {
    get: function () {
    return 'getter';
    },
    set: function (value) {
    console.log('setter: ' + value);
    }
    });

    //1.或者
    var obj = {
    get p() {
    return 'getter';
    },
    set p(value) {
    console.log('setter:' + value);
    }
    };
    2.两种写法区别:第一种写法,属性p的configurable和enumerable都为false,从而导致属性p是不可遍历的;第二种写法,属性p的configurable和enumerable都为true,因此属性p是可遍历的

    3.实际开发中,第二种方法更加常用

    4.注意,取值函数get不能接受参数,存值函数set只能接受一个参数(即属性的值)

    obj.p // "getter"
    obj.p = 123 // "setter: 123"

禁止扩展

如果我们不想这个对象添加更多的属性,那么可以使用Object.preventExtensions()方法禁止扩展

1
2
3
4
var obj={a:2};
Object.preventExtensions(obj);
obj.b = 2;
obj //{a:2},已经无法添加新属了

密封

密封就是禁止扩展的升级版,Object.seal()方法使得一个对象既无法添加新属性,也无法删除旧属性:

1
2
3
4
5
6
7
8
var obj = { p: 'hello' };
Object.seal(obj);

delete obj.p;
obj.p // "hello" -->1.无法被删除-->其实质:将该属性描述对象的configurable属性设为false

obj.x = 'world';
obj.x // undefined -->2.无法添加新属性

冻结

冻结就是密封的升级版,Object.freeze方法可以使得一个对象无法添加新属性、无法删除旧属性、也无法改变属性的值,使得这个对象实际上变成了常量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var obj = {
p: 'hello'
};

Object.freeze(obj);

obj.p = 'world';
obj.p // "hello" -->1.修改无效-->其实质:把所有属性的writable给关掉(false)

obj.t = 'hello';
obj.t // undefined -->2.无法添加新属性

delete obj.p // false
obj.p // "hello -->3.无法删除属性

参考资料:

https://wangdoc.com/javascript/stdlib/attributes.html
https://juejin.cn/post/6898684702186717197

坚持原创技术分享,您的支持将鼓励我继续创作.