• JavaScript中数据属性和访问器属性


        JavaScript中创建自定义对象有两种方法。

        一种是对象字面量法,例如:

    var person ={
         name:"xiaochang",
         age:24,
         sayName:function(){
              alert(this.name);   
         }
    }

        另一种是用new运算符创建一个Object()的实例,然后再为其添加属性和方法。例如:

    var person = new Object();
    person.name = "xiaochang";
    person.age = 24;
    person.sayName = function(){
         alert(person.name);
    }

    属性类型及其特性

        JavaScript中定义了两种不同的属性:数据属性和访问器属性。数据属性一般用于存储数据值,而访问器属性一般进行get/set操作,不能直接存储数据值。在ES5中,为了描述属性(property)的各种特征,定义了4个描述其行为的特性(attribute)。在JavaScript中不能直接访问特性,要放在两对方括号中。

    数据属性:

    数据属性主要有四个特性描述其行为:

    1、[[Configurable]]:默认为true。表示能够通过delete删除属性,能否修改属性特性,或把属性修改为访问器属性;

    2、[[Enumerable]]:默认为true。表示能否通过for-in循环返回属性;

    3、[[Writable]]:默认为true。表示能否修改属性的值;

    4、[[value]]:默认为undefined。包含这个属性的数据值。读取和写入属性值时都从这个位置进行。

     直接在对象上定义的属性,其数据特性默认如下:

    1、[[Configurable]]:true

    2、[[Enumerable]]:true

    3、[[Writable]]:true

    4、[[Value]]:“xiaochang"(初始时的赋值)

        这些特性不能直接被访问,要修改属性的特性只能通过Object.defineProperty()方法。该方法包含三个参数:

    属性所在的对象,属性的名字,一个描述符对象(包含上述四个特性的一个或多个)。 

    var person = {
          age:100 ;
    }
    
    Object.defineProperty(person,"name",function{
          configurable:false;
          writable:false;
          value:"xiaochang";
    });
    
    Object.defineProperty(person,"tall",{
          value:160;
    });
    
    for (attr in perso){
                console.log(attr);   //name,age
    }
    
    console.log(person.name);//xiaochang
    person.name="CC";         //为name属性指定新值
    console.log(person.name);//xiaochang
    delete person.name;        //删除name属性
    console.log(person.name);//xiaochang
    
    console.log(person.age);   //100
    person.age=200;             //为age属性指定新值
    console.log(person.age);   //200
    delete person.age;           //删除age属性
    console.log(person.age);  //undefined
    
    console.log(person.tall);  //160
    person.tall=170;            //修改tall属性的值
    console.log(person.age); //160
    delete person.tall;          //删除tall属性
    console.log(person.tall); //160

        直接在对象上定义的属性,如age,[[Configurable]]、[[Enumerable]]、[[Writable]]特性都被设置为true。

        属性name的[[Configurable]]、[[Writable]]被设置为false。所以无法修改和删除。

        调用Object.defineProperty()方法时,如果不显示指定configurable、enumerable、writable的值,就默认为false。如属性tall。

        需注意的是,当configurable设置为false后无法再将其改为true。且除了writable之外,无法修改其他特性。在configurable为true的情况下,可多次调用Object.definePro[erty()修改同一属性。

    访问器属性:

        包含getter和setter函数。读取访问器属性时,调用getter函数,返回有效的值;在写入访问器属性时,调用setter函数传入新值。它包含了4个特性:

    1、[[Configurable]]:表示是否能通过delete删除属性从而重新定义属性,能否修改属性的特性,能否把属性修改为数据属性;

    2、[[Enumerable]]:表示能否用for-in循环返回。

    3、[[Get]]:读取属性时调用的函数,默认为undefined;

    4、[[Set]]:写入属性时调用的函数,默认为undefinef。

        getter和setter不一定要成对出现,只有getter函数表明该属性只可读不可写,只有setter函数表明该属性只可写不可读。

    访问器属性无法直接定义,必须使用Object.defineProperty()来定义。

    var person = {
          _name:"xiaochang",    //name属性只可读不可写
          _age:100,                   //age属性只可写不可读
          _tel:123456               //tel属性可读可写
    };
    Object.defineProperty(person,"name",{
          get:function(){
                return this._name;
    }
    });
    Object.defineProperty(person,"age",{
          set:function(newage){
                this._age=newage;
    }  
    }) ;
    Object.defineProperty(person,"tel",{
           get:function(){
                 return this._tel;
           },
           set:function(newtel){
           this._tel=newtel;
           }
    });
    
    console.log(person.name);   //"xiaochang"
    person.name="CC";            //尝试修改name属性
    console.log(person.name);   //"xiaochang"
    console.log(person.age);      //undefined,不可读属性
    person.age=200;                //修改age
    console.log(person._age);   //直接读取对象方法才能访问的属性。可以看到值已更新为200
    console.log(person.tel);     //123456
    person.age=654321;         //修改tel
    person.log(person.tel);       //654321

        属性前的下划线,表示只能通过对象方法访问的属性,当调用Person.name时实际调用了name属性的getter函数(直接调用person._name可得到相同的结果,这样做访问器就没有什么意义了)。为person.name赋值时调用的是name属性的setter函数。

    定义多个属性:

        ECMAScript 5还提供了一个对对象定义多个属性的方法,Object.defineProperties()。该方法接受两个参数:属性所在的对象,多个属性的名字和其描述符对象组成的对象。上面的例子可以改写成如下:

    var person = {
          _name:"xiaochang",
          _age:100,
          _tel:123456
    };
    Object.defineProperties(person,{
         name:{
                     get:function(){
                           return this._name;
                     }
         },
         age:{
                  set:function(newage){
                        this._age = newage;
                  }    
         },
         tel:{
                get:function(){
                      return this._tel;
                },
                set:function(newtel){
                      this._tel = newtel;
                }
         }
    });

    读取属性的特性:

      对于上述属性特性,ECMAScript 5给出了可以取得给定属性的描述符的方法

        Object.getOwnPropertyDescriptor(),该方法包含两个参数:属性所在的对象,要读取器描述符的属性名称。方法返回一个对象,如果是访问器属性,返回的对象有configuable、enumerable、get和set;如果是数据属性,这个返回对象的属性包括configuable、enumerable、writable和value。如:

    var descriptor = Object.getOwnPropertyDescriptor(person,"tel");
    for (attr in descriptor){
         console.log(attr+":"+descriptor[attr]);
    }
    //运行结果如下:
    get:function(){return this._tel;}
    set:function(newtel){this._tel=newtel;}
    enumerable:false
    configurable:false

    数据属性和访问器属性的作用:

    先看代码

    var obj ={name:"percy"};
    console.log(obj.name);         //percy
    boj.name = "zyj";
    console.log(obj.name);        //zyj
    
    //这里借Math对象来举例
    //首先说明一下,Math对象和上面定义的ogj对象都只是Object对象的一个实例
    console.log(Math.PI);         //3.1415926…
    Math.PI=1234;
    console.log(Math.PI);        //3.1415926…

    同样是Object的实例,obj对象的属性却可以被改写,而Math对象的属性却不能被改写。

    这是因为,通过new运算符或对象字面量直接在对象上定义的属性,它们的[[Configurable]]、[[Enumerable]]、[[Writable]]特性默认都被设置为true。[[Value]]则被设定为指定的值。

    如果要让Obj对象的属性也不能被改写,就要用到Object.defineProperty()方法。

    若不按照上面2种方法为对象添加属性,而直接通过Object.defineProperty()为对象添加属性以及值,这种情况下,该对象的这个属性的另外3个特性的默认值都是false。

    var person={};    //新建一个空对象
    Object.defineProperty(person,"name",{
              value:"perch"
    });
    console.log(Object.getOwnPropertyDescriptor(person,"name"));
    //打印:Object{value:"percy",configurable:false,enumerable:false,writable:false}

    访问器属性则是用来实现JavaScript引擎本身使用得,因此不建议开发者使用访问器属性。

  • 相关阅读:
    极速安装JumpServer
    高并发限流策略
    JDK1.8源码分析:Future和FutureTask-任务异步执行结果
    nginx 转发 header 数据丢失
    zookpeer 和 redis 集群内一致性协议 及 选举 对比
    Spring Boot 中 Druid 的监控页面配置
    eclipse使用正则表达式查找替换
    jvm 线程状态
    Redis做分布式锁
    Dubbo的异常处理
  • 原文地址:https://www.cnblogs.com/haidaojiege/p/6759796.html
Copyright © 2020-2023  润新知