美文网首页
面向对象--内部属性类型

面向对象--内部属性类型

作者: 小泡_08f5 | 来源:发表于2019-05-27 23:19 被阅读0次
    • ECMA-262在第五版定义了只有内部才用的特性(attribute)来描述属性(property)的各种特性。
    • ECMA-262定义这些特性是为了实现Javascript引擎用的, 因此在Javascript中不能直接访问他们
    • 为了表示特性是内部值,将它们放在两对方括号内,例如:[[Prototype]]
    • 有俩种属性:数据属性和访问器属性
    数据属性

    数据属性包含一个数据值的位置
    [[ configurable ]]: 表示能否通过 delete 删除属性然后重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。直接在对象上定义的属性,它们这个特性的默认值为 true;
    [[ enumerable ]]: 表示能否通过 for-in 循环返回属性。直接在对象上定义的属性,它们这个特性的默认值为 true;
    [[ writable ]]: 表示能否修改属性的值。直接在对象上定义的属性,它们这个特性的默认值为 true;
    [[ value ]]: 包含这个属性的数据值。读取属性值的时候,从这个位置读;写入属性的时候,把新值保存在这个位置。这个特性的默认值为 undefined ;


    7224081-ad5a2ce940f1d308.png

    要修改属性的特性,必须使用 ES5 的 Object.definePrototype()方法。这个方法接受三个参数:
    1、属性所在的对象。
    2、属性的名字。
    3、描述符对象。属性必须是:configurableenumerablewritablevalue中的一个或多个。

    var obj = {};
    Object.defineProperty(obj, 'name', {
        writable: false,  // 不能修改值
        value: '张三'
    })
    console.log(obj.name); // 张三
    obj.name = '李四';
    console.log(obj.name); // 张三,  writable设为 false 后,值就没法修改了。
    var person = {
        name: '李四',
        age: 24
    }
    delete person.name;
    console.log(person); // {age: 24}
    Object.defineProperty(person, 'age', {
        configurable: false
    })
    delete person.age; 
    console.log(person);// {age: 24} configurable特性设为 false 后,就没法使用 delete 删除了。
    
    
    • 把 configurable 设置为 false 后,就不能用 delete 删除属性,而且,也不能修改 除 writable 外的特性。
    var obj = {};
    Object.defineProperty(obj, "name", {
        configurable: false,
        value: '张三'
    })
    
    // 会抛出错误
    Object.defineProperty(obj, "name", {
        configurable: true,
        value: '张三'
    })
    
    
    image.png

    也就是说,可以多次调用 Object.defineProperty()方法修改同一个属性,但在把 configurable特性设置为 false 后就有限制了。
    在调用Object.defineProperty()方法创建一个新的属性时,如果不指定,configurableenumerablewritable 特性的默认值都是 false,如果是修改已存在的属性,就不会有这个限制。

    访问器属性

    访问器属性没有数据值,有getset函数。读取访问器属性时,会调用 get函数,在写入值时会调用set函数

    image.png

    访问器属性有如下四个特性:
    [[ configurable ]]: 表示能否通过 delete 删除属性,从而重新定义属性。能否修改属性的特性,或者能否把属性修改为数据属性。直接在对象上定义的属性,它们这个特性的默认值为 true;
    [[ enumerable ]]: 表示能否通过 for-in 循环返回属性。直接在对象上定义的属性,它们这个特性的默认值为 true;
    [[ get ]]: 读取属性时,调用的函数。默认值为 undefined;
    [[ set ]]: 写入属性时,调用的函数。默认值为 undefined;

    访问器属性不能直接定义,必须通过Object.defintProperty()来定义。

    "use strict"
    let person = {
        name: '张三',
        age: 25
    }
    Object.defineProperty(person, 'oldAge', {
        get: function () {
            return this.age + 1;
        },
        set: function (newValue) {
            if (newValue > this.age) {
                this.age = newValue - 1;
                this.name = '李四'
            } else {
                this.age = newValue + 1;
                this.name = "王五"
            }
        }
    })
    
    person.oldAge = 28;
    console.log(person); // {name: '李四', age: 27};
    
    //还有种古老的方式
    let person = {
        name: '张三',
        age: 25
    }
    person.__defineGetter__('oldAge',function(){
        return return this.age + 1;
    });
    person.__defineSetter__('oldAge',function(newValue){
        if (newValue > this.age) {
                this.age = newValue - 1;
                this.name = '李四'
            } else {
                this.age = newValue + 1;
                this.name = "王五"
            }
    });
    age.year = 2017;
    age.nowAge;
    >>>21
    

    上面定义了一个 person 对象。默认有两个属性, "name"、"age"。新增了一个访问器属性 "oldAge"。它包含了两个函数。
    get 函数用来返回值。set函数,当为 "oldAge"写入值的时候,会调用。把 oldAge 设置为 27 后,调用 set 函数,改变了 person 对象的 "name" 和 "age" 属性值。
    不一定非要同时指定 set、get函数。只指定 get函数,意味着属性不能写,严格模式会报错。只指定了set函数,属性就不能读取,严格模式同样会报错。


    image.png image.png
    定义多个属性

    ES5 定义了一个 Object.defineProperties() 方法,可以通过描述符一次定义多个属性。这个方法,接受两个对象参数:第一个是要添加和修改其属性的对象,第二个就是要设置的属性的对象。

    let car = {};
    Object.defineProperties(car, {
        createYear: {
            writable: false,
            value: 2010
        },
        color: {
            writable: true,
            value: 'block'
        },
        severalYear: {
            get: function () {
                return parseInt(new Date().getFullYear()) - this.createYear
            },
            set: function (newValue) {
                if (newValue > 2010) {
                    this.color = 'red';
                }
            } 
        }
    })
    console.log(car.createYear); // 2010
    console.log(car.color);  // 'block'
    console.log(car.severalYear); // 9
    car.severalYear = 2015;
    console.log(car.createYear); // 2010
    console.log(car.color);  // 'red'
    console.log(car.severalYear);  // 9
    
    读取属性的特性

    使用 ES5 的 Object.getOwnPropertyDescriptor()方法,可以取得给定属性的描述符。这个方法接受两个参数:
    1、属性所在的对象。
    2、属性名称。
    返回值是一个对象,如果是数据属性,这个对象的属性有:configurableenumerablewritablevalue
    如果是一个访问器属性,对象的属性有:configurableenumerablegetset

    let car = {};
    Object.defineProperties(car, {
        createYear: {
            writable: false,
            value: 2010
        },
        color: {
            writable: true,
            value: 'block'
        },
        severalYear: {
            get: function () {
                return parseInt(new Date().getFullYear()) - this.createYear
            },
            set: function (newValue) {
                if (newValue > 2010) {
                    this.color = 'red';
                }
            } 
        }
    })
    
    let descriptpor = Object.getOwnPropertyDescriptor(car, "createYear");
    console.log(descriptpor);
    // { value: 2010,
    //   writable: false,
    //   enumerable: false,
    //   configurable: false }
    
    let fangdescriptpor = Object.getOwnPropertyDescriptor(car, "severalYear");
    console.log(fangdescriptpor); // 看下图
    
    
    image.png
    在 JavaScript 中可以针对任何对象-----包括 DOM 和 BOM 对象使用 Object.getOwnPropertyDescriptor()方法。

    相关文章

      网友评论

          本文标题:面向对象--内部属性类型

          本文链接:https://www.haomeiwen.com/subject/jznftctx.html