Menu

ECMAScript中面向对象之理解对象

2018年2月17日 - php

学过ECMAScript的同志都知道,创建对象的简单方式就是使用new Object()语句,然后再给它添加属性。

var perosn= new Object();

person.name=”Nicholas”;

person.age=29;

person.job=”Software Engineer”;

person.sayName=function(){

console.log(this.name);

}

可以明显的看出来,这种创建方式和一般的类语言创建的对象的方式既有相似又有不同。

上面的示例创建了一个名为person的对象,并为它添加了三个属性(name、age、job)和sayName方法。早期的前端开发人员经常使用这种模式创建新对象。后来,逐渐使用对象字面量方式创建对象,即

var person={

name:”Nicholas”,

age:29,

job:”Software Engineer”

sayName:function(){

console.log(this.name)

}

}

接下来聊聊属性类型

1、数据属性

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

[[Configurable]]:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。对象字面量方式定义的属性,它们的默认值true。

[[Enumerable]]:表示能否通过for-in循环返回属性。直接在对象字面量上定义的属性,它们的默认值true。

[[Writable]]:表示能否修改属性的值。直接在对象字面量上定义的属性,它们的默认值true。

[[Value]]:包含这个属性的数据值。读取属性值的时候,从这个位置读;写入属性值的时候,把新值保存在这个位置。直接在对象字面量上定义的属性,它们的默认值true。

要修改属性默认的特性,必须使用ECMAScript 5 的Object.defineProperty()方法。这个方法接收三个参数:属性所在的对象、属性的名字、描述符对象(descriptor)。其中,描述符对象的属性必须是:configurable、enumerable、writable、value。设置一个或者多个,可以修改对应的特性值。示例如下,

var person={};

Object.defineProperty(person,”name”,{

writable:false,

value:”Nicholas”

});

console.log(person.name);//”Nicholas”

person.name=”Greg”;

console.log(person.name);//”Nicholas”

运行结果如下,

这个例子创建了一个名为name的属性,它的值“Nicholas”是只读的。这个属性的值是不可修改的,如果尝试为它指定新值,则在严格模式下,赋值操作将会被忽略;在严格模式下,赋值操作将会导致抛出错误。

类似的规则也适用于不可配置的属性,

“use strict”;
var person={};
Object.defineProperty(person,”name”,{
configurable:false,
value:”Nicholas”
});

console.log(person.name);
delete person.name;
console.log(person.name);

这里就不给出贴图了,和上面的结论一致。

把configurable属性设置为false,表示不能从对象中删除属性。如果对这个属性调用delete,则在非严格模式下什么也不会发生,而在严格模式下会导致错误。而且一旦把属性定义为不可配置的,那么就不能再把它变回可配置了。

也就是说,可以多次调用Object.defineProperty()方法修改同一个属性,但在把configurable属性修改为false后就会有限制了。

在调用Object.defineProperty()方法创建一个新的属性时,如果不加指定这四个特性,那么configurable、enumerable、writable特性的默认值都是false。如果调用Object.defineProperty()方法只是修改已经定义的属性的特性,则无此限制(这里的限制,高程给的很笼统,我自己测试了一番,结论是:一旦指定新属性的configurable的值为false,那么就不能再使用Object.defineProperty()修改该属性的所有特性了,这里不知道有没有问题,我自己测试的结论是这样子的)。

ps:多数情况下,可能都没有必要利用Object.defineProperty()方法提供的这些高级功能,不过理解这些概念对于理解JavaScript对象却非常有用。IE8是第一个实现Object.defineProperty()的浏览器版本。然而,这个版本的实现存在诸多限制:只能在DOM对象上使用在个方法,而且只能创建访问器属性。由于实现并不彻底,建议读者不要在IE8中使用Object.defineProperty()方法。

着实有点汗颜,折腾了这么久居然建议不用。

2、访问器属性

访问器属性不包含数据值:它们包含一对儿getter和setter函数(不过,这两个函数并非必须)。在读取访问器属性时,会调用getter函数,这个函数负责返回有效的值;在写入访问器属性时,会调用setter函数并传入新值,这个函数负责决定如何处理数据。访问器属性也要四个特性:

[[Configurable]]:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改数据属性。对于使用对象字面量方式创建的属性,默认值是true。

[[Enumerable]]:表示能否通过for-in循环返回属性。对于使用对象字面量方式创建的属性么默认值是true。

[[Get]]:在读取属性时调用函数。默认值是undefined。

[[Set]]:在写入属性时调用的函数。默认值是undefined。

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

var book={
_year:2004,
edition:1
};
Object.defineProperty(book,”year”,{
get:function(){
return this._year;
},
set:function(newValue){
if(newValue>2004){
this._year=newValue;
this.edition+=newValue-2004;
}
}
});
book.year=2005;
book._year=2000;

console.log(book.edition);//2

这是使用访问其属性的常见方式,即设置一个属性的值会导致其他属性的=发生变化。

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

支持ECMAScript5的这个方法的浏览器有IE9(IE8只是部分实现)、Firefox4+、Safari5+、Opera12+和chrome。在这方法之前,需要创建访问器属性,一般都是使用两个非标准方法,__defineGetter__()和__defineSetter__()。这两个方法最初是由firefox引人的,后来其他浏览器也给出了实现。使用这个两个遗留的方法,可以向下面这样子重写前面的示例。

var book={

_year=2004,

edition:1

};

//定义访问器的旧方法

book.__defineGetter__(“year”,function(newValue){\

return this._year;

});

book.__defineSetter__(“year”,funciton(newValue){

if(newValue>2004){

this._year=newVlaue;

this.edition+=newValue-2004;

}

});

book.year=2005;

console.log(edition);

运行结果,

打字完毕,累死了。代码搬运工。

分享

发表评论