• 深入理解对象的数据属性与访问器属性


    创建对象的方式有两种:第一种,通过new操作符后面跟Object构造函数,第二种,对象字面量方式。如下

    var person = new Object();
    person.name = 'Nicy';
    person.age = 21;
    person.sayName = function() {
        console.log(this.name);
    };
            
    var person = {
        name: 'Nicy',
        age: 21,
        sayName: function() {
            console.log(this.name);
        }
    }

    这两种方式创建出来的对象是一样的,有相同的属性和方法。这些属性内部都有描述其行为的属性描述符。

    Object.defineProperty() 

    通过Object.defineProperty() 可以直接在对象上创建一个属性,也可以修改已有的属性。

    Object.defineProperty(obj, prop, descriptor) 接收三个参数:

      obj:属性所在的对象  

      prop:要访问的属性名

      descriptor:描述符对象

    描述符对象包含六个属性:configurable、enumerable、writable、value、get、set ,要修改属性的特性,必须使用Object.defineProperty()方法。

    通过以上两种方式添加的对象属性,其布尔值特性默认值是true,通过Object.defineProperty来修改属性特性时,只设置需要修改的特性即可;而通过Object.defineProperty创建的属性,其布尔值特性默认值是false。

    ECMAScript中属性分为两种:数据属性和访问器属性。

    数据属性

    数据属性包含四个属性描述符:

    [[Configurable]] : 表示能否通过delete删除属性从而重新定义属性,能否修改属性特性,能否把属性修改为访问器属性。通过以上方式添加的对象属性,默认为true。

    [[Enumerable]] : 表示能否通过for-in 循环访问属性。通过以上方式添加的对象属性,默认为true。

    [[Writable]] : 表示能否修改属性的值。通过以上方式添加的对象属性,默认为true。

    [[Value]] : 包含这个属性的数据值,可读取写入。通过以上方式添加的对象属性,默认为undefined。

    Writable

    var person = {};
    
    Object.defineProperty(person, "name", {
        value: 'Nicy'
    })
    person.name = 'Lee';  
    console.log(person.name)    // 'Nicy'
    
    Object.defineProperty(person, "name", {
        writable: true
    })
    person.name = 'Lee';
    console.log(person.name)    // 'Lee'

    Object.defineProperty直接创建的属性writable默认为false,value值不可修改,此时修改name为Lee,在非严格模式下不会报错,但操作被忽略,在严格模式下会报错。

    Configurable

    var person = {
        name: 'Nicy',
        age: 21,
        sayName: function() {
            console.log(this.name);
        }
    }
    
    Object.defineProperty(person, "name", {
        configurable: false
    })
    
    delete person.name;    // 操作被忽略,无法通过delete删除属性
    Object.defineProperty(person, "name", { // throw error configurable:true })
    Object.defineProperty(person,
    "name", { // throw error enumerable: false })
    Object.defineProperty(person,
    "name", { // 由于writable为true,所以可以修改value value: 'Lucy' })
    console.log(person.name)
    // Lucy

    Object.defineProperty(person, "name", { // writable可进行true -> false的单向修改 writable: false })
    Object.defineProperty(person,
    "name", { // throw error value: 'Lee' })
    Object.defineProperty(person,
    "name", { // throw error,此时writable不可以false -> true writable: true })

    总结一下configurable:当configurable设为false时,

      1、不可以通过delete去删除该属性从而重新定义属性;

      2、不可以转化为访问器属性;

      3、configurable和enumerable不可被修改;

      4、writable可单向修改为false,但不可以由false改为true

      5、value是否可修改根据writable而定。

    当configurable为false时,用delete删除该属性,在非严格模式下,不会报错,但操作被忽略,在严格模式下会报错;其他不可被修改的特性修改时会报错。

    Enumerable

    enumerable表示对象属性是否可以在for...in和Object.keys()中被枚举。

    var person = {};
    Object.defineProperty(person, "a", { value : 1, enumerable:true });
    Object.defineProperty(person, "b", { value : 2, enumerable:false });
    Object.defineProperty(person, "c", { value : 3 }); // enumerable defaults to false
    person.d = 4; // 如果使用直接赋值的方式创建对象的属性,则这个属性的enumerable默认为true
    
    for (var i in person) {    
      console.log(i);  
    }  //  'a' 和 'd' 
    
    Object.keys(person); // ["a", "d"]

    访问器属性

    访问器属性包含四个属性描述符:

    [[Configurable]] : 表示能否通过delete删除属性从而重新定义属性,能否修改属性特性,能否把属性修改为数据属性。直接在对象上定义的属性,默认为true。

    [[Enumerable]] : 表示能否通过for-in 循环访问属性。直接在对象上定义的属性,默认为true。

    [[Get]] : 读取属性时调用的函数,默认为undefined。

    [[Set]] : 写入属性时调用的函数,默认为undefined。

    var person = {
        name: 'Nicy',
        _age: 21,
        year: 1997,
        _year: 1997,
        sayName: function() {
            console.log(this.name);
        }
    }
    
    Object.defineProperty(person, "age", {
        get: function() {
            return this._age;
        },
        set: function(value) {
            this._age = value;
                    // ...
        }
    })

    用Object.defineProperty()定义的访问器属性,其configurable和enumerable默认为false。

    数据属性与访问器属性的相互转换

    Object.getOwnPropertyDescriptor 读取属性的特性

    使用Object.getOwnPropertyDescriptor可以获取到属性的描述符:

    Object.getOwnPropertyDescriptor(obj, prop)

      obj:属性所在的对象;

      prop:要访问的属性名。

    数据属性 -> 访问器属性

    属性的特性只能是访问器描述符和数据描述符中的一种,给已有的数据属性加get或set转换为访问器属性时,其属性的value、writable就会被废弃。

    如下代码,将对象原有的数据属性year转换为访问器属性:

    *注:在访问器属性的get和set中,不可以使用this访问属性本身,否则会无限递归而导致内存泄漏。

    // 设置get和set其中任意一个即可转换为访问器属性
    Object.defineProperty(person, "year", {
        get: function() {
    //        return this,year;    // error
            return this._year;    
        },
        set: function(value) {
    //             this.year = value;  // error
            this._year= value;
        }
    })
    
    var descriptor = Object.getOwnPropertyDescriptor(person, 'year');
    console.log(descriptor);    // {get: ƒ, set: ƒ, enumerable: true, configurable: true}

    在原有的数据属性year中,使用Object.defineProperty()为属性设置get 或 set,都可以将其转换为访问器属性。

    访问器属性 -> 数据属性

    将访问器属性转换为数据属性,只需要给现有访问器属性设置value或writable这两个属性描述符中的任意一个即可,其原有的get和set就会被废弃,从而转换为数据属性。

    上面为person定义的访问器属性age,通过Object.defineProperty()只设置了get和set,所以configurable默认为false,不可以将其转换为数据属性。可以在访问器属性和数据属性间相互转化的属性其configurable特性值必须为true。

    如下代码,我们为person新定义一个访问器属性job,将其configurable设置为true ,并将其转换为数据属性:

    Object.defineProperty(person, "job", {
        configurable: true,
        enumerable: true,
        get: function() {
            return this._job;
        },
        set: function(value) {
            this._job = value;
        }
    })
    
    // 设置value和writable其中任意一个即可转换为数据属性        
    Object.defineProperty(person, "job", {
        value: 'worker',
        writable: true
    })
    
    var descriptor = Object.getOwnPropertyDescriptor(person, 'job');
    console.log(descriptor);    // {value: "worker", writable: true, enumerable: true, configurable: true}

    数据描述符value、writable 和访问器描述符get、set不能同时设置,否则会报错。

    Object.defineProperties()

    通过Object.defineProperties()可以一次性为对象定义多个属性。

    var person = {};
    Object.defineProperties(person, {
      name: {
        value: 'Nicy',
        writable: true
      },
      _age: {
        value: 21,
        enumerable: true,
        writable: true,
        configurable: true
      },
       age: {
        get: function() {
        return this._age;
        },
        set: function(value) {
        this._age = value;
        }
      }
    });
  • 相关阅读:
    ACM Dance Recital(dfs+剪枝)
    矩阵快速幂
    分页实现复选框的选中状态
    MemCached 和redis的区别
    调用存储过程传值
    实现js中的时间格式中的T
    实现下载完成
    模态框实现功能后刷新父类页面
    JSON.parse()、JSON.stringify()和eval()的作用
    全选反选珍藏班版
  • 原文地址:https://www.cnblogs.com/shiningly/p/9482283.html
Copyright © 2020-2023  润新知