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


      在JavaScript中对象被定义为"无序属性的集合,其属性可以包含基本值、对象或函数。"通俗点讲,我们可以把对象理解为一组一组的名值对,其中值可以是数据或函数。

      创建自定义对象通常有两种方法,第一种就是创建一个Object的实例,然后再为其添加属性和方法,例如:

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

      第二种方法即对象字面量法,一般推荐使用这种方法创建对象,例如:

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

      属性类型

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

    • 数据属性

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

    1. [[Configurable]]:默认为true。表示能否通过delete删除属性从而重新定义属性,能否修改属性特性,或者能否把属性修改为访问器属性;
    2. [[Enumerable]]:默认为true。表示能否通过for-in循环返回属性;
    3. [[Writable]]:默认为true。表示能否修改属性的值。
    4. [[Value]]:默认值为undefined。表示包含属性的数据值。读写属性值都从这个位置进行。

      对于上面直接在person对象上定义的属性,它们的[[Configurable]]、[[Enumerable]]、[[Writable]]特性都被默认设置为true,而[[Value]]特性被设置为特定值。如果想要修改属性默认的特性,可以使用ES5提供的Object.defineProperty()方法,这个方法接收三个参数:属性所在对象、属性的名字和一个描述符对象。描述符对象只能包含上述四个特性的一个或多个。例子如下:

    var person = {
        name: "Scott"
    }
    Object.defineProperty(person,"name",{
        writable:false;
    })
    
    console.log(person.name);   //"Scott"
    person.name = "Evan";
    console.log(person.name);   //"Scott"

      将person对象name属性的特性writable设置为false,此属性的值为不可修改的,因此对该属性的复制操作会直接忽略。

    var person = {
        name: "Scott"
    }
    Object.defineProperty(person,"name",{
        configurable:false;
    })
    
    console.log(person.name);   //"Scott"
    delete person.name;
    console.log(person.name);   //"Scott"

      可以看到,当把name属性的特性值configurable设置为false之后,就表示不能从对象中删除属性。但需要注意的是,当把属性定义为不可配置之后,就不能把它变回可配置的了。此时修改除writable之外的其它特性都会报错,例如:

    var person = {
        name: "Scott"
    }
    Object.defineProperty(person,"name",{
        configurable:false;
    })
    Object.defineProperty(person,"name",{
        configurable:true;    //此处会抛出错误
    })

      也就是说,在把configurable特性修改为false之后,再修改其它特性就会有限制存在。

    • 访问器属性

      访问器属性不包含数据值。它包含一对getter和setter函数。当读取访问器属性时,会调用getter函数并返回有效值;当写入访问器属性时,会调用setter函数并传入新值,setter函数负责处理数据。该属性有四个特性:

    1. [[Configurable]]:默认为true。表示能否通过delete删除属性从而重新定义属性,能否修改属性特性,或者能否把属性修改为访问器属性;
    2. [[Enumerable]]:默认为true。表示能否通过for-in循环返回属性;
    3. [[Get]]:读取属性时调用的函数,默认为undefined;
    4. [[Set]]:写入属性时调用的函数,默认为undefined。

      访问器属性不能直接定义,必须通过Object.defineProperty()函数定义,例如:

    var person = {
        _name: "Scott",
        _age: 24,
        _tel: 86247
    };
    //name属性为只读的
    Object.defineProperty(person,"name",{
        get: function(){
            return this._name; 
        }
    });
    //age属性为只写不可读的
    Object.defineProperty(person,"age",{
        set: function(p){
             this._age = p;
        }
    });
    //tel属性为可读可写的
    Object.defineProperty(person,"tel",{
        get:function(){
             return this._tel;
        },
        set: function(p){
             this._tel = p;
        }
    });
    console.log(person.name);   //"Scott"
    person.name = "Evan";
    console.log(person.name);   //"Scott",对name属性的修改无效
    console.log(person.age);    //undefined,不可读属性
    person.age = 25;
    console.log(person._age);   //25,已经修改
    console.log(person.tel);    //"86247",可读属性
    person.tel = "13975";
    console.log(person.tel);    //"13975",可以修改

      属性前面的下划线表示只能通过对象方法访问的属性。当我们使用person.name时实际上调用的是name属性的getter函数,为person.name赋值时调用的是name属性的setter函数,这样属性和访问器之间的关系就很清晰了。

      定义多个属性

      实际上ES5为我们提供了为一个对象定义多个属性的方法,即Object.defineProperties(),该函数接收两个参数,属性所在的对象以及需要修改的属性及其描述符对象组成的对象,例如把上边的例子修改为一次性定义多个属性,如下:

    var person = {
        _name: "Scott",
        _age: 24,
        _tel: 86247
    };
    Object.defineProperties(person,{
        name:{
            get: function(){
               return this._name; 
            }
        },
        age:{
            set: function(p){
               this._age = p;
            }
        },
        tel:{
            get:function(){
               return this._tel;
            },
            set: function(p){
               this._tel = p;
            }
        }
    });

      读取属性的特性

      ES5提供了Object.getOwnPropertyDescripter()方法来获取给定属性的描述符。该方法接收两个参数:属性所在的对象和要读取其描述符的属性名称。结果会返回一个对象,如果是访问器属性,返回的对象有configuable、enumerable、get和set;如果是数据属性,这个返回对象的属性包括configuable、enumerable、writable和value。对于上面的例如,使用如下:

    var person = {
        _name: "Scott",
        _age: 24,
        _tel: 86247
    };
    Object.defineProperties(person,{
        name:{
            get: function(){
               return this._name; 
            }
        },
        age:{
            set: function(p){
               this._age = p;
            }
        },
        tel:{
            get:function(){
               return this._tel;
            },
            set: function(p){
               this._tel = p;
            }
        }
    });
    var descripter = Object.getOwnPropertyDescripter(person,"tel");
    console.log(descripter.value);   //undefined
    console.log(descripter.enumerable);   //false
    console.log(typeof descripter.get);   //"function"
    

      上面的代码中获取了person对象的tel属性,由于其是一个访问器属性,所以其value为undefined,enumerable为false,而get为指向getter函数的一个指针。

  • 相关阅读:
    【转】理解Ruby的4种闭包:blocks, Procs, lambdas 和 Methods
    折腾weibo开放平台
    netsh——常用命令及使用技巧
    The Enemies of Achievement
    java内存模型
    命名规则
    JS 控制加载页面对象
    点击图片弹出上传文件对话框
    ASP.NET判断用户是否在线
    ASP.Net处理QueryString函数汉字参数传递错误
  • 原文地址:https://www.cnblogs.com/neusc/p/5794650.html
Copyright © 2020-2023  润新知