首页 > 代码库 > JavaScript高级 面向对象的程序设计 (一)

JavaScript高级 面向对象的程序设计 (一)

  • 创建对象
  • 继承
面向对象的语言都有一个表示---类。通过类我们可以创建多个具有相同属性的对象。但是,在JS中并没有类的概念,所以JS的对象也和其他语言的对象不同。
对象的定义:无序的属性集合,其属性可以包含基本值,对象,函数。(所以我们又可以把JS对象看成散列表,一组键值对。)
一、创建对象
 
1.1工厂模式
function createPerson(name,age){
var o =newObject();
o.name = name;
o.age= age;
o.sayName =function(){
alert(this.name);
}
  return o;
}
 
var person1 =createPerson(‘zzz‘,15);
var person2 =createPerson(‘jjj‘,14);
此种方式无法判断它的类型,只能知道是Object类型。
1.2构造函数模式
functionPerson(name,age){
this.name = name;
this.age = age;
this.sayName =function(){
alter(this.name);
};
}
var per =newPerson();
此种方式解决了可以判断它为Person类型同时也是Object类型。
但是,这个方式每次创建一个新的对象都会 讲对象的中的方法重新创建一遍。        
1.3原型模式
每个函数都有个属性--prototype。prototype是一个指针,指向一个对象,这个对象的用途是 包含 特定类型的所有实例  共享 的属性和方法。
functionPerson(){};
Person.prototype.name =‘zjh‘;
Person.prototype.age =15;
Person.prototype.getName =function(){
alert(this.name);
};
var per =newPerson();
alert(per.__proto__ ==Person.prototype)//true
1.3.1理解原型对象
只要创建了一个函数,那么就会根据一组特定的规则为该函数创建一个prototype属性,这个属性指向该函数的原型对象。在默认情况下,所有的原型对象都会获得一个constructor(构造函数)属性,这个属性是一个指针,指向拥有该prototype的函数。所以Person.prototype.constructor = Person  ,这是一个循环。
当构造函数创建了一个实例,那么这个实例自动就会含有一个属性(__proto__),这个属性指向创建这个对象的构造函数的原型对象。(  per.__proto__ == Person.prototype  
技术分享
也就是实例和构造函数没有直接关系。虽然在创建的person1中没有任何属性和方法,但是根据原型链规则,他会自动查找它的原型链上的所有属性。
1.3.2原型与in操作符
functionPerson(){};
Person.prototype.name =‘zjh‘;
Person.prototype.age =15;
Person.prototype.getName =function(){
alert(this.name);
};
var per =newPerson();
per.daddy =‘zyj‘
for(var a in per){
alert(a)
}
1.3.3简洁的原型语法
functionPerson(){};
Person.prototype ={
name :‘zjh‘,
age :15,
getName :function(){
alert(this.name);
}
}
这种方式存在一个问题:当Person.prototype指向一个字面量时,这个字面量会生成一个对象,那么Person.prototype.constructor就是这个新生成对象的constructor,而这个对象的constructor一般都是Object.
解决这个问题可以通过下面这个技巧:
functionPerson(){};
Person.prototype ={
constructor :Person,
name :‘zjh‘,
age :15,
getName :function(){
alert(this.name);
}
}
var p =newPerson();
alert(p.constructor);
但是这种方式会使constructor属性变成可遍历的
技术分享
这种方式可以使其隐藏。
1.3.4原型的动态性
因为对象查找值是在原型链上查找的,所以一旦在对象的原型上添加或删除属性或者方法,就会在对象上生效,即使是以前的对象。
但是如果构造函数的原型被重新创建(比如说像上面直接用字面量方式写原型),那么实例的原型仍然指向最初的内存位置,而此时该位置已经不存在了。
技术分享
1.3.5原生对象的原型
可以对原生的构造函数原型修改,但一般不推荐这样做。
技术分享
技术分享
1.3.6原型对象的问题
其一就是无法在构造对象时就添加初始化参数,而必须预先定义值。
其二是一些由共享性导致的问题:
 
functionPerson(){};
Person.prototype ={
constructor :Person,
name :‘zjh‘,
age :15,
pie :[‘a‘,‘b‘],
getName :function(){
alert(this.name);
}
}
var p =newPerson();
p.pie.push(‘c‘);
alert(p.hasOwnProperty("pie"))//false
alert(p.pie)//a,b,c
var pp =newPerson();
alert(pp.pie)//a,b,c
所以通常都不会单独使用原型模式。
1.3.7组合使用构造函数和原型模式
创建自定义类型最常见的方式就是组合使用构造函数模式和原型模式。构造函数模式用于定义实例属性,原型模式用于定义方法和共性的属性。这样就让每个实例都有一份自己的属性副本,但同时又共享方法的引用,极大的节省了内存。同时还支持向构造函数内传参。
技术分享
这是写法也是一种认同度最高的创建方式。
1.3.8动态原型模式
functionPerson(name,age){
this.name = name;
this.age = age;
if(typeof(this.getName)!=‘function‘){
alert(‘s‘)
Person.prototype.getName =function(){
alert(this.name);
}
}
};
var p1 =newPerson(1,2);
var p2 =newPerson(1,2);
只会在创建p1的时候弹出s,之后就不会再执行if内语句了。
1.3.9寄生构造函数模式
一般在前几种方式都不适用的情况下,使用寄生构造函数模式。
在特殊情况下我们要使用这种方式:
技术分享
这种方法的局限性在于创建的对象和构造函数在原型上没有关系,也不能更具instanceOf来确定类型。所以,在可以用以上类型的情况下,不要使用这种情况。
1.3.10稳妥构造函数模式
所为稳妥对象,指的是没有公共属性,而且其方法也不用引用this对象。稳妥对象最适合在一些安全的环境中(这些环境会禁止使用this、new),或者在防止数据被其他应用程序改动时使用。
它与上面的寄生构造函数模式类似。两点不同:一是新创建对象的实例方法不引用this,二是不使用new操作符调用构造函数。
functionPerson(name,age){
var o =newObject();
var name =‘zjh‘;
o.getName =function(){
alert(name);
}
return o;
};
var p1 =Person(1,2);
p1.getName();
同样和寄生构造函数模式一样,这样创造出的对象和构造函数之间没有关系。

 

JavaScript高级 面向对象的程序设计 (一)