zoukankan      html  css  js  c++  java
  • js

    Object.defineProperty && Object.defineProperties

    ECMAS-262第5版在定义只有内部采用的特性时,提供了描述了属性特征的几种属性。ECMAScript对象中目前存在的属性描述符主要有两种,数据描述符(数据属性)和存取描述符(访问器属性),数据描述符是一个拥有可写或不可写值的属性。存取描述符是由一对 getter-setter 函数功能来描述的属性。

    Object.defineProperty && Object.defineProperties这两个方法在js中十分重要,主要功能就是用来定义或修改内部属性,与之相对应的Object.getOwnPropertyDescriptor && Object.getOwnPropertyDescriptors就是获取这行内部属性的描述。

    数据(数据描述符)属性

    数据属性有4个描述内部属性的特性

    • [[Configurable]]
      表示能否通过delete删除此属性,能否修改属性的特性,或能否修改把属性修改为访问器属性,如果直接使用字面量定义对象,默认值为true

    • [[Enumerable]]
      表示该属性是否可枚举,即是否通过for-in循环或Object.keys()返回属性,如果直接使用字面量定义对象,默认值为true

    • [[Writable]]
      能否修改属性的值,如果直接使用字面量定义对象,默认值为true

    • [[Value]]
      该属性对应的值,默认为undefined

    访问器(存取描述符)属性

    访问器属性也有4个描述内部属性的特性

    • [[Configurable]]
      和数据属性的[[Configurable]]一样,表示能否通过delete删除此属性,能否修改属性的特性,或能否修改把属性修改为访问器属性,如果直接使用字面量定义对象,默认值为true

    • [[Enumerable]]
      和数据属性的[[Configurable]]一样,表示该属性是否可枚举,即是否通过for-in循环或Object.keys()返回属性,如果直接使用字面量定义对象,默认值为true

    • [[Get]]
      一个给属性提供 getter 的方法(访问对象属性时调用的函数,返回值就是当前属性的值),如果没有 getter 则为 undefined。该方法返回值被用作属性值。默认为 undefined

    • [[Set]]
      一个给属性提供 setter 的方法(给对象属性设置值时调用的函数),如果没有 setter 则为 undefined。该方法将接受唯一参数,并将该参数的新值分配给该属性。默认为 undefined

    创建/修改/获取属性的方法

    • Object.defineProperty()

    功能:
    方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。如果不指定configurable, writable, enumerable ,则这些属性默认值为false,如果不指定value, get, set,则这些属性默认值为undefined

    语法: Object.defineProperty(obj, prop, descriptor)

    obj: 需要被操作的目标对象
    prop: 目标对象需要定义或修改的属性的名称
    descriptor: 将被定义或修改的属性的描述符

    var obj = new Object();
    
    Object.defineProperty(obj, 'name', {
         configurable: false,
         writable: true,
         enumerable: true,
         value: '张三'
    })
    
    • Object.defineProperties()

    功能:
    方法直接在一个对象上定义一个或多个新的属性或修改现有属性,并返回该对象。

    语法: Object.defineProperties(obj, props)

    obj: 将要被添加属性或修改属性的对象
    props: 该对象的一个或多个键值对定义了将要为对象添加或修改的属性的具体配置

    var obj = new Object();
    Object.defineProperties(obj, {
        name: {
            value: '张三',
            configurable: false,
            writable: true,
            enumerable: true
        },
        age: {
            value: 18,
            configurable: true
        }
    })
    
    console.log(obj.name, obj.age) // 张三, 18
    
    • Object.getOwnPropertyDescriptor()

    功能:
    该方法返回指定对象上一个自有属性对应的属性描述符。(自有属性指的是直接赋予该对象的属性,不需要从原型链上进行查找的属性)

    语法: Object.getOwnPropertyDescriptor(obj, prop)

    obj: 需要查找的目标对象
    prop: 目标对象内属性名称

    var person = {
        name: '张三',
        age: 18
    }
    
    var desc = Object.getOwnPropertyDescriptor(person, 'name'); 
    console.log(desc)  结果如下
    // {
    //     configurable: true,
    //     enumerable: true,
    //     writable: true,
    //     value: "张三"
    // }
    
    • Object.getOwnPropertyDescriptors()

    功能:
    所指定对象的所有自身属性的描述符,如果没有任何自身属性,则返回空对象。

    语法: Object.getOwnPropertyDescriptors(obj)

    obj: 需要查找的目标对象

    var person = {
        name: '张三',
        age: 18
    }
    var desc = Object.getOwnPropertyDescriptors(person);
    console.log(desc) 
    //name: {
    //    configurable: true,
    //    enumerable: true,
    //    value: '张三',
    //    writable: true
    //}
    //age: {
           configurable: true
          enumerable: true
         value: 18
         writable: true
    }
    

    各种场景下描述符属性

    • configurable
      如果设置configurable属性为false,则不可使用delete操作符(在严格模式下抛出错误), 修改所有内部属性值会抛出错误,在《javaScript高级教程中》说只可以改变writable的值,现在改变writable的值也会抛出错误

    在对象中添加一个数据描述符属性

    var person = {};
    
    Object.defineProperty(person, 'name', {
        configurable: false,
        value: 'John'
    }) ;
    
    delete person.name   // 严格模式下抛出错误
    
    console.log(person.name)  // 'John'  没有删除
    
    Object.defineProperty(person, 'name', {
        configurable: true  //报错
    });
    
    Object.defineProperty(person, 'name', {
        enumerable: 2  //报错
    });
    
    Object.defineProperty(person, 'name', {
        writable: true  //报错
    });
    
    Object.defineProperty(person, 'name', {
        value: 2  //报错
    });
    

    在对象中添加存取描述符属性

    var obj = {};
    var aValue; //如果不初始化变量, 不给下面的a属性设置值,直接读取会报错aValue is not defined
    var b;
    Object.defineProperty(obj, 'a', {
        configurable : true,
        enumerable : true,
        get: function() {
            return aValue
        },
        set: function(newValue) {
            aValue = newValue;
            b = newValue + 1
        }
    })
    console.log(b) // undefined
    console.log(obj.a)  // undefined, 当读取属性值时,调用get方法,返回undefined
    obj.a = 2;  // 当设置属性值时,调用set方法,aValue为2
    
    console.log(obj.a) // 2  读取属性值,调用get方法,此时aValue为2
    console.log(b) // 3  再给obj.a赋值时,执行set方法,b的值被修改为2,额外说一句,vue中的计算属性就是利用setter来实现的
    

    注意:
    1.getter和setter可以不同时使用,但在严格模式下只其中一个,会抛出错误
    2.数据描述符与存取描述符不可混用,会抛出错误

    var obj = {};
    Object.defineProperty(obj, 'a', {
        value: 'a1',
        get: function() {
           return 'a2'
        }    
    });
    

    3.全局环境下

    var a = 1; // a属于window, 相当于window.a
    var d = Object.getOwnPropertyDescriptor(window, 'a');
    console.log(d)
    // {
    //     configurable: false,
    //     value: 1,
    //     writable: true,
    //     enumerable: true
    // }
    

    在来看一下另一种不适用var声明的方式初始化a变量

    a = 1; // a相当于window的一个属性, window.a
    var d = Object.getOwnPropertyDescriptor(window, 'a');
    console.log(d)
    // {
    //     configurable: true,   // 此时configurable属性值为true
    //     value: 1,
    //     writable: true,
    //     enumerable: true
    // }
    

    使用 var定义的任何变量,其configurable属性值都为false,定义对象也是一样

    var b = {
        name: 'bbb'
    }
    var d = Object.getOwnPropertyDescriptor(window, 'b');
    console.log(d)
    // {
    //     configurable: false
    //     value: 1,
    //     writable: true,
    //     enumerable: true
    // }
    

    但是这里需要说明的一点是,使用字面量定义的对象,该对象内部的属性的数据描述符属性都为true

    var b = {
        name: 'bbb'
    }
    var d = Object.getOwnPropertyDescriptor(b, 'name');
    console.log(d)
    // {
    //     configurable: true
    //     writable: true,
    //     enumerable: true
    //     value: 'bbb'
    // }
    
    • Writable

    当writable为false(并且configurable为true),[[value]]可以通过defineProperty修改, 但不能直接赋值修改

    //-----------------------------------通过defineProperty修改--------------------------------
    var obj = {};
    
    Object.defineProperty(obj, 'a', {
        configurable: true,
        enumerable: false,
        writable: false,
        value: 1
    });
    
    Object.defineProperty(obj, 'a', {
        configurable: false,
        enumerable: true,
        writable: false ,
        value: 2
    });
    var d = Object.getOwnPropertyDescriptor(obj, 'a')
    
    console.log(d); // 结果如下
    // {
    //     value: 2, 
    //     writable: false, 
    //     enumerable: true, 
    //     configurable: false
    // }
    
    
    //-------------------------------------------直接赋值修改-----------------------------------
    var obj = {}
    
    Object.defineProperty(obj, 'a', {
        configurable: true,
        enumerable: false,
        writable: false,
        value: 1
    });
    obj.a=2;
    var d = Object.getOwnPropertyDescriptor(obj, 'a')
    
    console.log(d); // 结果如下
    
    // {
    //     value: 1,  // 没有做出修改
    //     writable: false, 
    //     enumerable: true, 
    //     configurable: false
    // }
    
    • Enumerable
    var obj = {};
    Object.defineProperties(obj, {
        a: {
            value: 1,
            enumerable: false
        }, 
        b: {
            value: 2,
            enumerable: true
        },
        c: {
            value: 3,
            enumerable: false
        }
    })
    
    obj.d = 4;
    
    //等同于
    
    //Object.defineProperty(obj, 'd', {
    //    configurable: true,
    //    enumerable: true,
    //    writable: true,
    //    value: 4
    //})
    
    for(var key in obj) {
        console.log(key);  
        // 打印一次b, 一次d, a和c属性enumerable为false,不可被枚举
    } 
    
    var arr = Object.keys(obj);
    console.log(arr);  // ['b', 'd']
    
  • 相关阅读:
    <转>Npoi导入导出Excel操作<载>
    将DataTable导出为Excel C#
    错误 X “X1”不包含“XX2”的定义,并且找不到可接受类型为“X1”的第一个参数的扩展方法“XX2”(是否缺少 using 指令或程序集引用?)
    错误 1 未知的服务器标记“asp:ScriptManager”。
    分析器错误消息: 类型“test.test.testx”不明确: 它可能来自程序集“F: estProjectin est.test.DLL”或程序集“F: estProjectin estProject.DLL”。请在类型名称中显式指定程序集。
    There are no interfaces on which a capture can be done.
    基础知识系列☞GET和POST→及相关知识
    基础知识系列☞Abstract和Virtual→及相关知识
    同源策略
    26Mybatis_一级缓存及其测试
  • 原文地址:https://www.cnblogs.com/sunidol/p/11525024.html
Copyright © 2011-2022 走看看