zoukankan      html  css  js  c++  java
  • js知识梳理1:理解对象的属性特性

    1.数据属性

    数据属性的4个特性:

    • Configurable:①表示能否通过delete删除属性从而重新定义,②能否修改属性的特性,③能否把属性修改为访问器属性。对象直接量里默认值true。
    • Enumerable:表示能否通过for-in循环返回属性。对象直接量里默认值true。
    • Writable:表示能否修改属性的值。对象直接量里默认值true。
    • Value:包含这个属性的数据值。对象直接量里默认值undefined。
    //查看对象直接量的属性的属性特性默认值
    var people = {
        name:'jaychou',
        sayName:function () {
            console.log(this.name);
        }
    };
    /**{value: "jaychou", writable: true, enumerable: true, configurable: true}*/
    console.log(Object.getOwnPropertyDescriptor(people,'name'));
    /**{value: ƒ, writable: true, enumerable: true, configurable: true}*/
    console.log(Object.getOwnPropertyDescriptor(people,'sayName'));
    //getOwnPropertyDescriptor对于继承属性和不存在的属性,返回undefined

    要修改属性默认的特性,使用Object.defineProperty()方法,接收3个参数:对象,属性名字和描述符对象。

    //修改属性默认特性:
    Object.defineProperty(person,'job',{
        emumerable:false,//不可枚举
        value:'singer',
        writable:false,//不可写
        configurable:true
    });
    /**{name: "jaychou", sayName: ƒ, job: "singer"}*/
    console.log(person);
    for(var prop in person){
        //打印name,sayName
        console.log(prop);
    }
    //会报错
    try{
        person.job = 'director';
    }catch (e) {
        //Cannot assign to read only property 'job' of object
        console.log(e);
    }

    可以多次调用Object.defineProperty()方法修改同一个属性,但在把configurable特性设置为false之后就会有限制了:

    Object.defineProperty(person,'height',{
        configurable:false,//不可配置
        writable:true,
        value:172
    });
    try{
        Object.defineProperty(person,'height',{
            configurable:true,//出错
            enumerable:true,//出错
            value:175,//正常
            writable:false,//writable从true变false可以,false变true也会出错
        });
    }catch (e) {
        //Cannot redefine property: height at Function.defineProperty
        console.log(e);
    }
    try{
        delete person.height;
    }catch (e) {
        //设置成不可配置后也不可删除:Cannot delete property 'height' of #<Object>
        console.log(e);
    }

    另外,调用 Object.defineProperty()方法时,如果不指定,configurable、enumerable 和 writable 特性的默认值都是 false。如果是修改已有属性,则无此限制。

    2.存储器属性

    存储器属性不包含数据值,只包含包含 getter 和 setter 函数(非必需)。 在读取存储器属性时,会调用 getter 函数,这个函数负责返回有效的值;在写入存储器属性时,会调用 setter 函数并传入新值,这个函数负责决定如何处理数据。4个属性特性如下:

    • Configurable:①表示能否通过delete删除属性从而重新定义,②能否修改属性的特性,③能否把属性修改为数据属性。对象直接量的默认值true
    • Enumerable:表示能否通过for-in循环返回属性。对象直接量的默认值true
    • Get:在读取属性时调用的函数。对象直接量默认值undefined
    • Set:在写入属性时调用的函数。对象直接量的默认值undefined

    定义存储器属性最简单的方法是使用对象直接量语法的拓展写法:

    var p = {
        x:3.0,
        y:4.0,
        //r是可读写的存取器属性
        get r(){return Math.sqrt(this.x*this.x+this.y*this.y);},
        set r(newValue){
            var oldvalue = Math.sqrt(this.x*this.x+this.y*this.y);
            var ratio = newValue/oldvalue;
            this.x *= ratio;
            this.y *= ratio;
        },
        //theta是只读存取器属性
        get theta(){return Math.atan2(this.y,this.x);}
    }
    console.log(p.r);
    p.r = 25;

    使用Object.defineProperty()方法定义存储器属性:

    var book = {
        _year:2004,
        edition:1
    };
    Object.defineProperty(book,"year",{
        get:function () { return this._year; },
        set:function (newValue) {
            if(newValue>2004){
                this._year = newValue;
                this.edition += newValue - 2004;
            }
        }
    })
    /**{get: ƒ, set: ƒ, enumerable: false, configurable: false}*/
    console.log(Object.getOwnPropertyDescriptor(book,'year'));

    如例子所示,使用存储器属性的常见方式,即设置一个属性的值会导致其他属性发生变化。还有一种常见就是现在流行的类似于Vue的响应式原理,就是把data中的属性都使用defineProperty修改为存储器属性,可以监听到数据的变化。

    3.定义多个属性

    经常要创建或修改多个属性,这时候可以使用Object.defineProperties()方法,它接收2个参数,要添加或修改属性的对象和一个映射表,包含名称和属性描述符。

    var book1 = {};
    Object.defineProperties(book1,{
       _year:{
           value:'2008'
       },
       editor:{
           enumerable:true,
           value:'2'
       },
       year:{
           get:function () {
               return this._year;
           },
           set:function (newValue) {
               this._year = newValue;
               this.edition += newValue - 2004;
           }
       }
    });

    4.对象的可扩展性

    对象的可拓展性表示是否可以给对象添加新属性。所有内置对象和自定义对象都是显式可扩展的,宿主对象的可扩展性是由Javascript引擎定义的。

    1.查询对象可拓展性
    var teacher = {age:25};
    //true:代表可拓展
    console.log(Object.isExtensible(teacher));
    2.转换为不可拓展(“锁定对象”)
    Object.preventExtensions(teacher);
    //false
    console.log(Object.isExtensible(teacher));
    try{
        teacher.subject = 'math';
    }catch (e) {
        //TypeError: Cannot add property subject, object is not extensible
        console.log(e);
    }

    转换成不可拓展的操作是不可逆的,而且只能影响到对象本身的可拓展性,如果给一个不可拓展对象的原型添加属性,这个不可拓展对象同样会继承这些新属性。

    5.密封对象

    密封对象比锁定对象更高一层,除了不可拓展以外,对象的所有自身属性都设置成了不可配置的。同样密封对象操作是不可逆的。

    var tea1 = {subject:'math'};
    //false:代表未密封
    console.log(Object.isSealed(tea1));
    Object.seal(tea1);
    try{
        Object.defineProperty(tea1,'subject',{
            //enumerable:false,//出错
            //configurable:true,//出错
            writable:false//和上面说的一样,writable从true变成false可以,false变成true则出错
        });
    }catch (e) {
        console.log('出错..');
        console.log(e);
    }
    //true:已密封
    console.log(Object.isSealed(tea1));

    6.冻结对象

    冻结比密封对象多的效果是:可以将它自有的所有数据属性设置为只读(如果对象的存取器属性具有setter方法,存取器属性将不受影响,仍可以通过给属性赋值调用它们)。

    var tea2 = {subject:'Chinese'};
    //false:代表未冻结
    console.log(Object.isFrozen(tea2));
    Object.freeze(tea2);
    try{
        tea2.subject = 'math';
    }catch (e) {
        //TypeError: Cannot assign to read only property 'subject' of object
        console.log(e);
    }
    //true:已冻结
    console.log(Object.isFrozen(tea2));

    7.属性特性规则总结

    • 如果对象是不可拓展的,则可以编辑已有的自有属性,但不能给它添加新属性。
    • 如果属性是不可配置的,则不能修改它的可配置性和可枚举性。
    • 如果存取器属性是不可配置的,则不能修改其getter和setter方法,也不能将它转换为数据属性。
    • 如果数据属性是不可配置的,则不能将它转换为存取器属性。
    • 如果数据属性是不可配置的,则不能将它的可写性从false修改为true,但可以从true修改为false。
    • 如果数据属性是不可配置且不可写的,则不能修改它的值。然而可配置但不可写属性的值是可以修改的(做法:先将它标记为可写的,然后修改它的值,最后转换为不可写的)。
  • 相关阅读:
    VSCode搭建golang环境
    Jmeter之连接数据库
    Jmeter之『如果(If)控制器』
    mysql时间SQL
    正则表达式查找“不包含XXX字符串”
    Jmeter5.3源码编译
    Log4j源码分析
    12 个 JS 技巧
    高效学习很重要
    IntelliJ IDEA自动导入包去除星号(import xxx.*)
  • 原文地址:https://www.cnblogs.com/dujishi/p/9717095.html
Copyright © 2011-2022 走看看