欢迎关注本人的微信公众号“前端小填填”,专注前端技术的基础和项目开发的学习。
本节内容对应《JavaScript高级程序设计》的第六章内容。
1、面向对象(Object-Oriented, OO)的语言有一个标志,那就是它们都有类的概念,而通过类可以创建任意多个具有相同属性和方法的对象。前面提到过,ECMAScript中没有类的概念,因此它的对象也与基于类的语言中的对象有所不同。
ECMA-262把对象定义为:“无序属性的集合,其属性可以包含基本值、对象或者函数。”严格来讲,这就相当于说对象是一组没有特定顺序的值。对象的每个属性或方法都有一个名字,而每个名字都映射到一个值。正因为这样(以及其他将要讨论的原因),我们可以把ECMAScript的对象想象成散列表:无非就是一组名值对,其中值可以是数据或函数。
每个对象都是基于一个引用类型创建的,这个引用类型可以是前面讨论的原生类型,也可以是开发人员定义的类型。
2、属性类型:ECMA-262第5版在定义只有内部才用的特性时,描述了属性的各种特征。ECMA-262定义这些特性是为了实现JavaScript引擎用的,因此在JavaScript中不能直接访问它们。为了表示特性是内部值,该规范把它们放在了两对方括号中,例如[[Enumerable]]。
要修改属性默认的特性,必须使用ECMAScript5的Object.defineProperty()方法。这个方法接收三个参数:属性所在的对象、属性的名字和一个描述符对象。其中,描述符对象的属性必须是:configurable、enumerable、writable和value。设置其中的一或多个值,可以修改对应的特性
var person = {
name:"Nicholas",
age:29,
toString:function(){
return "[name=" + this.name + "; age=" + this.age + "]";
}
};
Object.defineProperty(person , "name",{
writable:false
});
person.name="goskalrie";//修改无效
alert(person);//[name=Nicholas; age=29]
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;
alert(book.edition);//2
var book = {};
Object.defineProperties(book , {
_year:{
value:2004
},
edition:{
value:1
},
year:{
get:function(){
return this._year;
},
set:function(newValue){
if(newValue > 2004){
this._year = newValue;
this.edition += newValue - 2004;
}
}
}
});
var descriptor =Object.getOwnPropertyDescriptor(book , "_year");
alert(descriptor.value);//2004
alert(descriptor.configurable);//false
alert(typeof descriptor.get);//"undefined"
3、创建对象:虽然Object构造函数或对象字面量都可以用来创建单个对象,但这些方式有个明显的缺点:使用同一个接口创建很多对象,会产生大量的重复代码。下面介绍多找种创建对象的方法:
function createPerson(name , age){
var obj = new Object();
obj.name = name;
obj.age = age;
obj.sayName = function(){
alert(this.name);
};
return obj;
}
var person1 = createPerson("Nicholas" , 29);
var person2 = createPerson("Greg" , 21);
function Person(name , age){
this.name = name;
this.age = age;
this.sayName = function(){
alert(this.name);
};
}
var person1 = new Person("Nicholas" , 29);
var person2 = new Person("Greg" , 21);
//当作构造函数使用
var person = new Person("Nicholas" , 29);
person.sayName();//"Nicholas"
//作为普通函数调用
Person("Greg" , 21);//添加到window
window.sayName();//"Greg"
var o = new Object();
Person.call(o , "goser" , 24);
o.sayName();//"goser"
function Person(){}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.sayName = function(){alert(this.name);};
var person1 = new Person();
person1.sayName();//"Nicholas"
var person2 = new Person();
person2.sayName();//"Nicholas"
person1.name = "Greg";
alert(person1.name);//"Greg"——来自实例
delete person1.name;
alert(person1.name);//"Nicholas"——来自原型
alert(person1.sayName == person2.sayName);//true
function Person(name , age){
this.name = name;
this.age = age;
this.friends = ["goser" , "greg"];
}
Person.prototype = {
constructor : Person,
sayName : function(){alert(this.name);},
};
var person1 = new Person("Nicholas" , 29);
var person2 = new Person("Greg" , 21);
person1.friends.push("gat");
alert(person1.friends);//"goser,greg,gat"
alert(person2.friends);//"goser,greg"
alert(person1.friends == person2.friends);//false
alert(person1.sayName == person2.sayName);//true
function Person(name , age){
this.name = name;
this.age = age;
-----------------------------------------//
if(typeof this.sayName != "function"){
Person.prototype.sayName = function(){
alert(this.name);
};
}
-----------------------------------------//
}
var p = new Person("Nicholas" , 29);
p.sayName();
function Person(name , age){
var obj = new Object();
obj.name = name;
obj.age = age;
obj.sayName = function(){
alert(this.name);
};
return obj;
}
var p = new Person("Nicholas" , 29);
p.sayName();