对象属性和方法

创建对象

var a1 = new Object();
a1.name = "a1";
a1.age = 20;
a1.job = 'IT';
a1.sayName = function(){
    console.log(this.name);
};

var a2 = {
   name:'a2',
   age:20,
   job:'IT',
   sayName:function(){
       console.log(this.name);
   }
};

数据属性

数据属性包含一个数据值的位置,在这个位置可以读取和写入值,数据属性有四个描述其行为的特性。

  • Configurable:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性,像上面例子中那样直接在对象上定义的属性,它们的这个特性默认值为true。
  • Enumerable:表示能否通过for-in循环 返回属性,像上面例子中那样直接在对象上定义的属性,它们的这个特性默认值为true。
  • Writable:表示能否修改属性的值,像上面例子中那样直接在对象上定义的属性,它们的这个特性默认值为true。
  • Value:包含这个属性的数据值,读取属性值的时候,从这个位置读;写入属性值的时候,把新值保存在这个位置,这个特性的默认值为undefined。

在上面的例子中,都含有一个名为age的属性,并为它指定的值是20,也就是说[[Value]]特性被设置为20,而对这个值的任何修改都将反映在这个位置,要修改属性默认的特性,必须使用Object。defineProperty()方法,这个方法接收三个参数:属性所在的对象、属性的名字和一个描述符(descriptor)对象。其中,描述符对象的属性必须是:configurable,enumerable,writable和value。设置其中的一个或多个值,可以修改对应的特性值。

var b = {};
Object.defineProperty(b,'name',{
    writable:false,
    value:'Nicholas'
});
console.log(b.name);   //Nicholas
b.name = "Greg";
console.log(b.name);   //Nicholas

上面的例子中创建了一个name属性,他的属性值“Nicholas”是只读的,这个属性的值是不可修改的,如果尝试修改,在非严格模式下,赋值操作将被忽略,在严格模式下,赋值操作会导致抛出错误。类似的规则也适用于不可配置的属性。

var c = {};
Object.defineProperty(c,'name',{
    configurable:false,
    value:'Nicholas'
});
console.log(c.name);   //Nicholas
delete c.name;
console.log(c.name);   //Nicholas

把configurable设置为false,表示不能从对象中删除该属性,如果这个属性调用delete,在非严格模式下什么也不会发生,而在严格模式下会导致错误。而且,一旦把属性定义为不可配置的,就不能再把它变回可配置了。此时,再调用Object.defineProperty()方法修改除writable之外的特性,都会导致错误。

var d = {};
    Object.defineProperty(d,'name',{
    configurable:false,
    value:'Nicholas'
});
Object.defineProperty(d,'name',{  //Uncaught TypeError: Cannot redefine property: name
    configurable:true,
    value:'Nicholas'
});

也就是说,可以多次调用Object.defineProperty()方法修改同一个属性,但在把configurable特性设置为false之后就会有限制了。
 在调用Object.defineProperty()方法时,如果不指定,configurable,enumerable和writable特性的默认值都是false。

访问器属性

访问器属性不包含数据值,由一对getter和setter函数(均非必须)构成,在读取访问器属性时,会调用getter函数,这个函数负责返回有效的值;在写入访问器属性时,会调用setter函数并传入新值,这个函数负责决定如何处理数据。访问器属性有如下4个特性:

  • configurable:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为数据属性,对于直接在对象上定义的属性,这个特性的默认值为true。
  • enumerable:表示能否通过for-in循环返回属性。对于直接在对象上定义的属性,这个特性的默认值为true。
  • get:在读取属性时调用的函数,默认值为undefined。
  • set:在写入属性时调用的函数,默认值为undefined。

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

var e = {
    _year:2016,
    edition:1
};
Object.defineProperty(e,"year",{
    get:function(){
      return this._year;
    },
    set:function(newValue){
        if(newValue > 2016){
            this._year = newValue;
            this.edition += newValue - 2016;
        }
     }
});
c.year = 2018;
console.log(c.edition);  //3

上面的例子中创建了一个对象,并给它定义了两个默认的属性:_year和edition。_year前面的下划线是一个记号,用于表示只能通过对象方法访问的属性,而访问器属性year则包含一个getter函数和一个setter函数。getter函数返回_year的值,setter函数通过计算来确定正确的版本,因此把year属性修改为2018会导致_year变成2018,而edition变为3,这是使用访问器属性的常见方式,即设置一个属性的值会导致其他属性发生变化。

不一定非要同时指定getter和setter,只指定getter以为着属性是不能写,尝试写入属性会被忽略。在严格模式下,尝试写入只指定了getter函数的属性会抛出错误。类似低,没有指定setter函数的属性也不能读,否则在非严格模式下会返回undefined,而在严格模式下会抛出错误。

toString

toString() 表示的含义是把这个对象表示成字符串形式, 并且返回这个字符串形式. 首先,在Object.prototype中它对toString()方法的默认实现是"[object Object]"

  

当我们在自己的对象或者原型上对toString()进行重写覆盖后,在访问这个对象的toString()方法时,就会沿着原型链上查找,刚好在自身对象上就找到了toString(),这是就不用再去找原型链上的顶端Object.prototype的默认的toString()了。

  

继续看方法重写:

   

首先是第一个打印,输出的是标准时间,也就是说,Date这个构造函数的原型其实是有toString()方法的,也就是js引擎已经在Date原型对象中重写了toString()方法,这样,就不会再继续到Object.prototype里面去寻找了。第二个打印中就能看到构造函数的原型中的toString()方法。

从第三个和第四个打印中可以知道,js引擎在Number对象上重写了toString()方法,用于将数字转为字符串。

valueOf()

valueOf() 返回这个对象表示的基本类型的值!在Object.prototype.valueOf 中找到, 默认返回的是this。当需要在对象上重写valueOf()时,应该是返回一个基本数据类型的值。 先看一个默认返回的值的情况。(也就是说它是去这个对象的原型链的顶端Object.prototype.valueOf 找的valueOf方法 )
  

在上面例子中,p1.valueOf是在Object.prototype.valueOf找到的,返回值默认this。此时this就是p1的这个对象。故结果返回true。

valueOf()也能进行重写

    

前面三个都是重写了valueOf()的,而第四个的打印就说明这个时候正则对象上没有valueOf,是在Object.prototype.valueOf找的,返回this,this指的就是regExp正则对象。

 

posted on 2018-06-11 20:25  紅葉  阅读(442)  评论(0编辑  收藏  举报