对于面向对象的程序设计的理解
理解对象
对象的定义:无序属性的集合,其属性可以包含基本值、对象或者函数。
如:
var Person = {
name : “Nicholas”,
}
ECMAScript中有两种属性:数据属性和访问器属性。
数据属性有四个特性:
[[Configurable]]:表示能否通过 delete 删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。默认值为 true。
[[Enumerable]]:表示能否通过 for-in 循环返回属性。默认值为 true。
[[Writable]]:表示能否修改属性的值。默认值为 true。
[[Value]]:包含这个属性的数据值。读取属性值的时候,从这个位置读;写入属性值的时候,把新值保存在这个位置。这个特性的默认值为 undefined。
要修改默认属性,需使用ES5中的Object.defineProperty(),如:
Object.defineProperty(Person,“name”,{
writable:false,
value:“Nicholas”
})
访问器属性的四个属性:
[[Configurable]]: 同上
[[Enumerable]]:同上
[[Get]]:在读取属性时调用的函数,默认值为undefined
[[Set]]:在写入属性时调用的函数,默认值为undefined
访问器函数不能直接定义,必须使用Object.defineProperty()来定义,如:
var book={
_year:2004,
edition:1
};
Object.defineProperty(Person,“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
Object.getOwnPropertyDescriptor()方法获取给定属性的描述符,如:
var des=Object.getOwnPropertyDescriptor(book,”_year”);
alert(des.value) //2004
创建对象
工厂模式
function createPerson(name){
var o=new Object();
o.name=name;
return o;
}
var person1=createPerson(“Grey”)
2.2 构造函数模式
function Person(name){
this.name=name;
this.sayName=function(){
alert(this.name)
}
}
var person1=new Person(“Grey”)
var person2=new Person(“Nicholas”)
(1)person1.constructor == Person 实例的构造函数指向对象
(2)person1.sayName != person2.sayName
person1和person2的sayName()方法不是同一个Function的实例,ES中函数也是对象,因此每定义一个函数,就是实例化一个对象。
原型模式
function Person(){}
Person.prototype.name=“Nicholas”;
Person.prototype.sayName=function(){
alert(this.name)
};
var person1=new Person()
var person1=new Person()
(1)对象中的所有属性和方法都是由所有实例共享的。
(2)默认情况下,所有原型对象都自动获得一个constructor。
Person.prototype指向原型对象,Person.prototype.constructor指向Person
(3)每个实例对象中包含一个指针[[Prototype]](无法访问),即_proto_,可以通过isPrototypeOf()来确定对象与实例是否存在这种关系。
alert(Person.prototype.isPrototypeOf(person1)) //true
(4)ES5中的Object.getPrototypeof()方法返回[[Prototype]],实际上就是对象的原型。
alert(Object.getPrototypeof(person1) == Person.prototype)
(5)hasOwnProperty()方法检测一个属性是存在于实例中,还是存在原型中。
(6)ES5中Object.keys()方法,接收一个对象作为参数,返回一个包含所有可枚举属性的字符串数组。
Object.keys(Person.prototype) //name,sayName
更简单的原型语法(对象字面量)
function Person(){}
Person.prototype={
name:“Nicholas”;
sayName:function(){
alert(this.name)
};
}
var frined=new Person();
alert(friend instanceof Person) //true
alert(friend.constructor == Person) //false
constructor属性不再指向Person,因为这里的语法本质上完全重写了默认的prototype对象。
继承
原型链
基本思想:利用原型让一个引用类型继承另一个引用类型的属性和方法。
function Animal(){
this.species = "动物";
}
Animal.prototype.getValue=function(){
return this.species;
}
function Cat(name,color){
this.name = name;
this.color = color;
}
Cat.prototype = new Animal();
Cat.prototype.getfood=function(){
return this.name
}
var cat1 = new Cat("大毛","黄色");
console.log(cat1.prototype.getValue) //动物
console.log(Animal.prototype.isPrototype(cat1)) //true
通过原型链继承时,不能使用对象字面量创建原型方法,因为这样会重写原型链。
原型链的主要问题:包含引用类型值的原型属性会被所有实例共享。
借用构造函数
基本思想:在子类型构造函数内部调用超类型构造函数
function Animal(){
this.colors=["red","blue"]
}
function Cat(name,color){
//继承了Animal
Animal.call(this);
this.name = name;
this.color = color;
}
var cat1 = new Cat("大毛","黄色");
cat1.colors.push("black"); //["red", "blue", "black"]
var cat2=new Cat("小苗","黑色");
console.log(cat2.colors) //["red", "blue"]
Cat的每个实例都会具有自己的colors属性副本。
问题:方法都在构造函数中定义,因此函数复用性无从谈起。
组合继承
基本思想:使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。
function Animal(){
this.species = "动物";
this.colors=["red","blue"]
}
Animal.prototype.getValue=function(){
return this.species;
}
function Cat(name,color){
Animal.call(this);
this.name = name;
this.color = color;
}
Cat.prototype = new Animal();
Cat.prototype.constructor=Cat;
Cat.prototype.getfood=function(){
return this.name
}
var cat1 = new Cat("大毛","黄色");
cat1.colors.push("black");
console.log(cat1.colors) //["red", "blue", "black"]
console.log(cat2.name) //大毛
var cat2=new Cat("小苗","黑色");
console.log(cat1.colors) //["red", "blue"]
console.log(cat2.name) //小苗
最常用的继承模式
原型式继承
利用一个空对象作为中介
function extend(Child, Parent) {
var F = function(){};
F.prototype = Parent.prototype;
Child.prototype = new F();
Child.prototype.constructor = Child;
Child.uber = Parent.prototype;
}
extend(Cat,Animal);
var cat1 = new Cat("大毛","黄色");
alert(cat1.species); // 动物
```