JavaScript对象深入理解(defineProperty、get/set)

JavaScript 中的众生平等,万物皆对象:字符串、数值、数组、函数...  另外,   JavaScript 允许自定义对象。

对象的本质可以理解为属性的集合,对象的属性包括:

       命名属性 : 可直接通过“.”访问到的属性
         数据属性 : 专门保存一个值的属性
         访问器属性 : 保护数据属性的特殊属性
       内部属性 : 不能通过“.”直接访问的属性 (比如 : class   __proto__)
 
下面重点分析一波, 数据属性 访问器属性

1.数据属性: 专门存储数据的属性

数据属性的四大特性:

{
          value : 值,
          writable : true/false, (默认true)
          enumerable : true/false,(默认true)
          configurable : true/false (默认true)
}

  • writable  ——  是否为可写,改为false,当前属性变为只读。
  • enumerable  ——  是否为可枚举,改为false,for in时不会被遍历,但使用 "."依然可访问。
  • configurable  ——  是否为可配置的,改为false之后,不能删除修改(不可逆)


/*****************************************/                     
"use strict";

var bob={id:101,name:"Bob",salary:1000};

//访问对象bob的id属性
console.log(Object.getOwnPropertyDescriptor(bob,"id"));

//修改bob对象id属性为只读,不可枚举,不可配置
Object.defineProperty(bob,"id",{
writable:false,
configurable:false,
enumerable:false
})

Object.defineProperty( bob, "id", {
    configurable : true,                  //报错
} );

for( var i in bob){
    console.log( i + '--' + bob[i] ); // name--Bob salary--1000
}

/*****************************************/         

writable为false的时候,如果对这个属性name进行重新赋值(修改)在非严格模式下,赋值会被忽略,在严格模式下会报错.

configurable为false的时候,如果删除name属性,在非严格模式下,删除操作会被忽略,在严格模式下会报错,而且如果对一个设置了configurable为false的属性,想把它重新改为true,会报错。

enumerable的值为false,那么这个属性是不能被for...in遍历(循环/枚举)



1) Object.getOwnPropertyDescriptor()

Object.getOwnPropertyDescriptor(obj,"属性名");

可以得到给定属性的特性, 返回值为一个对象。


2) Object.defineProperty()

Object.defineProperty(obj , 属性名 , { 特性 })

注意: 如果obj中包含指定属性,则修改现有属性的值,如果obj中不包含指定属性,则在obj中自动添加新属性
 
     特性的默认值:
       1. 属性在创建对象时就定义好了,所有特性的默认值都为true
       2. 而当使用defineProperty添加的属性,特性的默认值都为false。

没有使用Object.defineProperty定义对象:

var obj1= {
                name : 'ajun',
                age : 18,
};
         var ajun1= Object.getOwnPropertyDescriptor( obj1, "name" );
        console.log( ajun1.configurable ); //true
        console.log( ajun1.enumerable ); //true
        console.log( ajun1.writable ); //true
        console.log( ajun1.value ); //ajun

使用Object.defineProperty定义的对象:

var obj2 = { }
Object.defineProperty( obj2 , "name", {
        value : 'ajun'
});
    var ajun2= Object.getOwnPropertyDescriptor( obj2 , "name" );

    console.log( ajun2.configurable ); //false
    console.log( ajun2.enumerable ); //false
    console.log( ajun2.writable ); //false
    console.log( ajun2.value ); //ajun


所以,在使用defineProperty添加属性时,必须显式定义属性的特性为true,否则默认为false。


2.访问器属性: 专门保护数据属性的特殊属性,不实际存储数据

getter/setter访问器:
      1.get方法负责读取变量的值
      2. set方法负责修改变量的值

注意:当使用了getter或setter方法,不允许使用writable和value这两个属性?     

何时调用get/set:
          试图通过访问器属性取值时,自动调用get特性的函数
          试图通过访问器属性设置值时,自动调用set特性的函数
          一般在set中设置对要设置的新值得验证
         特殊: 如果省略set特性,则该属性为只读

              四大特性:{
                get : function(){return 局部变量},
                set : function(value){局部变量=value},
                 enumerable : 同数据属性 ,
                configurable : 同数据属性
              }
          
注意: 使用访问器属性,必须有一个受保护的局部变量都要通过闭包来添加访问器属性:
           
单独添加访问器属性:

             (function(){
                var 局部变量 = 值 ;
                Object.defineProperty(obj,"属性名",{
                 get : function(){return 局部变量},
                   set : function(value){局部变量=value},
                    enumerable : true,
configurable : true
                })
            })();
           

在构造函数中添加访问器属性:

            function(属性参数){
                this.公有属性=参数,
                ...
                Object.defineProperty(obj,"属性名",{
                  get:function(){return 属性参数},
                    set:function(value){属性参数=value},
                    enumerable:true,
configurable:true
                })
            }

定义命名属性:

           1. 只定义一个命名属性:
               Object.defineProperty(obj,"属性名",{
                    四大特性
                })
           2. 同时定义多个属性:
                Object.defineProperties(obj,{
                   属性名1 : {
                     四大特性
                  },
                    ... : {...}
                })

          如果指定名称的属性存在,则修改现有属性
         如果指定名称的属性不存在,则自动创建同名属性

重要的事再说一遍,非defineProperty定义的属性,四大特性默认值都是true。defineProperty添加的属性,四大特性默认值都是false。

实际用处

何时修改四大特性: 只要保护属性,就用四大特性控制
   何时使用数据属性: 只想控制只读,遍历或删除
   何时使用访问器属性: 希望用自定义逻辑保护变量




你可能感兴趣的:(javascript)