对象的基本概念
面向对象(Object-Oriented,OO),的语言最大的特征就是它们都有类的概念,通过类可以创建任意多个具有相同属性和方法的对象。
创建自定义对象最简单的方式就是创建一个Object 的实例,然后再给他添加属性和方法。如:
var math = new Object();
math.π = function pi(){
return Math.PI;
};
document.write(math.π());
这里借用了Math.PI,最后的结果是无论调用的是math.π
还是Math.PI
都会返回圆周率的值。其中,前者就是我们自己自定义的对象。又如:
var person = new Object();
person.name = "Oliver";
person.age = 18;
person.job = "Software Engineer";
person.sayName = function(){
alert(this.name);
};
上面这个对象可以用下面的结构化图像解释清楚:
Object => person
|-name
|-age
|-job
|-sayName()
|-this.name
这里面person 是对象,又是Object 的实例,其中他有三个属性和一个方法,这个方法用于显示this.name,会被解析为person.name。
上面的例子又可以用字面量的语法写成这样:
var person = {
name: "Oliver",
age: 18,
job: "Software Engineer",
sayName: function(){
alert(this.name);
}
};
属性类型
根据ECMA-262 第五版,ECMAScript 中有两种属性(内部值):数据属性和访问器属性。为了表示特性的内部值,该规范把它们放在了两对方括号中,如[[Enumerable]]。
数据属性
数据属性有4 个描述其行为的特性:
[[Configurable]]:表示能否通过delete 删除属性;
[[Enumerable]]:表示能否通过for-in 循环返回属性;
[[Writable]]:表示能否修改属性的值;
[[Valu]]:包含这个属性的数据值;
其中,前三个默认都是true,最后一个默认为undefined。
如何修改数据属性默认的特性呢?这就要用到ECMAScript 5 的Object.defineProperty()
方法。这个方法接收三个参数:属性所在的对象,属性的名字和一个描述符对象。描述符对象就是上面提到的4 个描述其行为的特性:configurable、enumerable、writable 和value。
修改方式如下:
var person = {};
Object.defineProperty(person, "name", {
writable: false,
value: "Oliver"
});
console.log(person.name); //Oliver
person.name = "Niko";
console.log(person.name); //Niko
又如:
var person = {
name: "Troy",
age: 18
};
Object.defineProperty(person, "name", {
writable: false,
value: "Oliver",
enumerable: false
});
for (x in person){
console.log(x); //age
}
如:
var person = {
name: "Troy",
age: 18
};
Object.defineProperty(person, "name", {
value: "Oliver",
configurable: false
});
delete person.name;
console.log(person.name) //Oliver
要注意的是,一旦把属性定义为不可配置的,就不能再把它变回可配置的了。
不要在IE8 中使用Object.defineProperty()
方法。
访问器属性
该属性不包含数据值,只有一对getter 和setter 函数(两者为可选);4个 特性如下:
[[Configurable]]
[[Enumerable]]
[[Get]]:在读取属性时调用的函数;默认undefined;
[[Set]]:在写入属性时调用的函数;默认undefined;
同样,必须使用Object.defindProperty()
来定义。如:
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 = 2006;
console.log(book.edition);
两个默认的属性:_year 和edition。year 前面的下划线是一种常用的记号,用于表示只能通过对象方法访问的属性。
对于上面的下划线不太明白的,可以参考下面一种写法:
var book = {
year: 2004,
edition: 1
};
Object.defineProperty(book, "setYear", {
get: function(){
return this.year;
},
set: function(newValue){
if(newValue > 2004){
this.year = newValue;
this.edition += newValue - 2004;
}
}
});
book.setYear = 2007;
console.log(book.edition);
console.log(book.year)
两者功能相同,实际上该方法是给book 对象又设置了另一个属性即第一段代码中的_year 和第二段代码中的setYear。
另外,一般在这个方法之前,要创建访问器属性,一般都是使用两个非标准的方法:__defineGetter__()
和__defineSetter__()
。如:
var book = {
name: "hello"
};
book.__defineGetter__("name",function(){
return "world";
});
document.write(book.name);
定义多个属性
ECMAScript 5 又定义了一个Object.defineProperties()
方法。利用这个方法可以通过描述符一次定义多个属性。如:
var book = {};
Object.defineProperties(book, {
_year:{
value: 2004,
writable: true
},
edition:{
value: 1,
writable: true
},
year:{
get: function(){
return this._year;
},
set: function(newValue){
if(newValue > 2004){
this._year = newValue;
this.edition += newValue - 2004;
}
}
}
});
book.year = 2006;
console.log(book.year + " " + book.edition);
还真是奇葩,不知是否浏览器的问题,数据属性还是要加上为true 的writable 访问器属性才能起作用。不是默认为true 么。真是奇怪
读取属性的特征
使用ECMAScript 5 的Object.getOwnPropertyDescriptor()
方法,可以取得给定属性的描述符。接收两个参数:所在的对象和要读取其描述符的属性名称。如:
var cars = {};
Object.defineProperties(cars, {
name: {
value: "Benz",
writable: false
},
_color: {
value: "White",
writable: true
},
price: {
value: 300000,
writable: true
},
color: {
get: function(){
return this._color;
},
set: function(newValue){
if(newValue == "Black"){
this._color = "Black";
this.price = 280000
}else if(newValue == "White"){
this._color = "White";
this.price = 300000
}
}
}
});
function selectColors(colorValue){
cars.color = colorValue;
document.write(cars.name + ": " + cars.color + "款 " + "(" + cars.price + "元人民币" + ")");
}
selectColors("Black"); //Benz: Black款 (280000元人民币)
selectColors("White"); //Benz: White款 (300000元人民币)
var descriptor = Object.getOwnPropertyDescriptor(cars, "name");
document.write(descriptor.value + descriptor.writable + descriptor.configurable + descriptor.enumerable); //Benzfalsefalsefalse
var descriptor2 = Object.getOwnPropertyDescriptor(cars, "color");
document.write(descriptor2.get + descriptor2.set + descriptor2.configurable + descriptor2.enumerable + descriptor2.value); //function () { return this._color; }function (newValue) { if(newValue == "Black"){ this._color = "Black"; this.price = 280000 }else if(newValue == "White"){ this._color = "White"; this.price = 300000 } }falsefalseundefined
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。