• 你不知道的JavaScript笔记----对象


    对象:

    1、定义对象属性

    属性描述符(也称为:数据描述符)

    Object.defineProperty(Object,PropertyName,{
    
        value: 6,
    
        writable: true,
    
        configurable: true,
    
        enumerable: true
    
    })

    1.1 Writable

      writable 决定是否可以修改属性的值。

    如:

    var myObject = {};
    
         Object.defineProperty( myObject, "a", {
            value: 2,
         writable: false, // 不可写! 
         configurable: true,
         enumerable: true } ); myObject.a = 3; myObject.a; // 还是2,不可修改

      

    注:这里把 writable:false 设置成属性不可改变,相当于你定义了一个空操作 setter。严格来说,如果要和writable:false 一致的话,你的 setter 被调用时应当抛出一个 TypeError 错误。

    1.2. Configurable
    只要属性是可配置的,就可以使用 defineProperty(..) 方法来修改属性描述符。反之,则不可以使用defineProperty方法修改configurable,configurable为false的情况下writable只能从true改成false,但是value的值只受writable的影响,只要writable为true一直都可以修改。

    注意:configurable一旦设置成了false,就再也没有机会设置成true了。configurable设置成false之后,属性无法通过delete进行删除操作,不会报错,只是不起作用。

    名字起的好,真的是可配置属性,为false之后,不可配置了,writable只是个例外。

    var myObject = {
          a: 2
        };
        myObject.a = 3;
        myObject.a; // 3
        Object.defineProperty(myObject, "a", {
          value: 4,
          writable: true,
          configurable: false, // 不可配置!
          enumerable: true
        });
        console.log(myObject.a); // 4
        myObject.a = 5;
        console.log(myObject.a); // 5
        Object.defineProperty(myObject, "a", {
          value: 6,
          writable: false, 
          configurable: false, 
          enumerable: true
        }); // TypeError
        console.log(myObject.a) //确实改成了6
        myObject.a=7
        console.log(myObject.a)
        Object.defineProperty(myObject, "a", {
          value: 6,
          writable: true, 
          configurable: false, 
          enumerable: true
        }); // TypeError
        myObject.a=8
        console.log(myObject.a)  

      1.3. Enumerable

      从名字就可以看出,这个描述符控制的是属性是否会出现在对象的属性枚举中,比如说 for..in 循环。如果把 enumerable 设置成 false,这个属性就不会出现在枚举中,虽然仍 然可以正常访问它。相对地,设置成 true 就会让它出现在枚举中。


    2、对象不变性

      2.1. 对象常量
      结合 writable:false 和 configurable:false 就可以创建一个真正的常量属性(不可修改、 重定义或者删除),const关键字的实现就是这么来的,只是在window下面添加常量属性。

      2.2. 禁止扩展

      如果你想禁止一个对象添加新属性并且保留已有属性,可以使用 Object.prevent Extensions(..):

    var myObject = {};
        Object.defineProperty(myObject, "FAVORITE_NUMBER", {
          value: 42,
          writable: false,
          configurable: false
        });
        console.log(myObject)
        myObject.b='bbbb';
        Object.preventExtensions(myObject);
        myObject.c='ccccc'; // 不理会,但不报错
        console.log(myObject)
        Object.defineProperty(myObject,'d',{
          value:'ddddd',
          writable:false,
          configurable:true
        }) //  Cannot define property d, object is not extensible
        console.log(myObject)

      2.3. 密封
      Object.seal(..) 会创建一个“密封”的对象,这个方法实际上会在一个现有对象上调用 Object.preventExtensions(..) 并把所有现有属性标记为 configurable:false。

    所以,密封之后不仅不能添加新属性,也不能重新配置或者删除任何现有属性(虽然可以 修改属性的值)。

      2.4. 冻结
    Object.freeze(..) 会创建一个冻结对象,这个方法实际上会在一个现有对象上调用 Object.seal(..) 并把所有“数据访问”属性标记为 writable:false,这样就无法修改它们的值。

    你可以“深度冻结”一个对象,具体方法为,首先在这个对象上调用 Object.freeze(..), 然后遍历它引用的所有对象并在这些对象上调用 Object.freeze(..)。但是一定要小心,因为这样做有可能会在无意中冻结其他(共享)对象。

    注意:常量和冻结虽然不可写,但是如果值是引用类型的话,它的值只是一个引用地址不可变,但是地址对应的对象依然是可变的,也就是说const定义的变量如果是对象,其值依然是可以赋值进行改变的。

    var myObject = {};
        var smallobj = {a:'a',b:'b'};
        Object.defineProperty(myObject, "FAVORITE_NUMBER", {
          value: smallobj,
          writable: false,
          configurable: false
        });
        console.log(myObject);
        smallobj.c="cccc";
        console.log(myObject); // myObject.FAVORITE_NUMBER:{a: "a", b: "b", c: "cccc"}
    
        const myOK={a:'abc'}
        myOK.b='def';
        console.log(myOK) //{a: "abc", b: "def"}

    访问描述符:

    当你给一个属性定义 getter、setter 或者两者都有时,这个属性会被定义为“访问描述 符”(和“数据描述符”相对)。对于访问描述符来说,JavaScript 会忽略它们的 value 和 writable 特性,取而代之的是关心 set 和 get(还有 configurable 和 enumerable)特性。

    Object.defineProperty(Object,PropertyName,{
    
        get: function(){},
    
        set: function(){},
    
        configurable: true,
    
        enumerable: true
    
    })

    给对象定义get和set属性的时候,居然可以这样写,第一次见:

    var myObject = {
        // 给 a 定义一个 getter 
        get a() {
            return this._a_; 
        },
        // 给 a 定义一个 setter 
        set a(val) {
            this._a_ = val * 2; 
        } 
    }; 
     myObject.a = 2;
     myObject.a; // 4
    

      如果你乐意,可以往里面继续添加get b(){},set b(){}。

    上面的代码其实和下面是一模一样的:

    var myObject = {}; 
        Object.defineProperty(myObject,'a',{
          get:function(){
            console.log(this)
            return this._a_;
          },
          set:function(val){
            this._a_=val*2;
          },
          configurable:true
        })
    
     myObject.a=2;
     console.log(myObject.a); //4
    

      

    注:根据MDN描述,如果一个描述符不具有value,writable,get 和 set 任意一个关键字,那么它将被认为是一个数据描述符。如果一个描述符同时有(value或writable)和(get或set)关键字,将会产生一个异常。


    3.属性的存在性

    3.1 检查一个属性在对象中是否存在。

      可以用in,hasOwnProperty,区别是in查询属性是否在对象的原型链上,而hasOwnProperty只查询属性是否在对象自身属性中,不考虑继承因素。

    3.2 是否在遍历属性中。

      enumerable为true的属性,属于遍历属性,才会出现在for。。。in中。for...in也会查找原型链上所有可以遍历的属性,说白了for...in用的还是in的查找原型链的特性,但是for...in不查enumerable属性为假的属性,但是in会查,只要有,in就返回真。

    propertyIsEnumerable(..) 会检查给定的属性名是否直接存在于对象中(而不是在原型链 上)并且满足 enumerable:true。

    Object.keys(..) 会返回一个数组,包含所有可枚举属性,Object.getOwnPropertyNames(..) 会返回一个数组,包含所有属性,无论它们是否可枚举

    in 和 hasOwnProperty(..) 的区别在于是否查找 [[Prototype]] 链,然而,Object.keys(..) 和 Object.getOwnPropertyNames(..) 都只会查找对象直接包含的属性。

    以上内容仅作为笔记,以及一些个人的小见解,不正确之处,欢迎指出,大家一起探讨。

  • 相关阅读:
    输出流对象
    1.2最简单的c++程序
    c++的初步认识
    理想程序员
    从字符数组中删除字符
    打印杨辉三角
    旋转数组
    找出1000以内的所有完数
    计算兔子的总数
    101-200有多少个素数?
  • 原文地址:https://www.cnblogs.com/liujiekun/p/11131498.html
Copyright © 2020-2023  润新知