Person.prototype.friends = ['wangwu']; //Person添加一个数组类型
zhangsan.friends.push('zhaoliu'); //张三修改会对李四造成影响
alert(zhangsan.friends); //wangwu,zhaoliu
alert(lisi.friends); //wangwu,zhaoliu李四也多了个
3、组合使用构造函数模式和原型模式
这种模式是使用最广泛、认同度最高的一种创建自定义类型的方式。构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性。这样,每个实例都有自己的一份实例属性的副本,同时有共享着对方法的引用,最大限度的节省了内存。
原型模式改造后的如下:
复制代码 代码如下:
function Person(name, age) {
this.name = name;
this.age = age;
this.friends = ['wangwu'];
}
Person.prototype.country = 'chinese';
Person.prototype.sayCountry = function() {
alert(this.country);
}
var zhangsan = new Person('zhangsan', 20);
var lisi = new Person('lisi', 20);
zhangsan.friends.push('zhaoliu');
alert(zhangsan.friends); //wangwu,zhaoliu
alert(lisi.friends); //wangwu
二、继承
继承基本概念
ECMAScript主要依靠原型链来实现继承(也可以通过拷贝属性继承)。
原型链基本思想是,利用原型让一个引用类型继承另外一个引用类型的属性和方法。构造函数、原型、示例的关系是:每个构造函数都有一个原型对象,原型对象都包含了一个指向构造函数的指针,而实例都包含了一个指向原型的内部指针。所以,通过过让原型对象等于另外一个类型的实例,此时原型对象将包含一个指向另一个原型的指针,相应地,另一个原型中也包含这一个指向另一个构造函数的指针。假如另外一个原型又是另一个类型的实例,那么上述关系依然成立,如此层层递进,就构成了实例和原型的链条。这就是原型链的基本概念。
读起来比较绕,不容易理解。直接通过实例说明验证。
1、原型链继承
复制代码 代码如下:
function Parent() {
this.pname = 'parent';
}
Parent.prototype.getParentName = function() {
return this.pname;
}
function Child() {
this.cname = 'child';
}
//子构造函数原型设置为父构造函数的实例,形成原型链,让Child拥有getParentName方法
Child.prototype = new Parent();
Child.prototype.getChildName = function() {
return this.cname;
}
var c = new Child();
alert(c.getParentName()); //parent
图解:
原型链的问题,如果父类中包括了引用类型,通过Child.prototype = new Parent()会把父类中的引用类型带到子类的原型中,而引用类型值的原型属性会被所有实例共享。问题就回到了[一、2]节了。
2、组合继承-最常用继承方式
组合继承(combination inheritance),是将原型链和借用构造函数(apply, call)的技术组合到一块。思路是使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。这样既可以在原型上定义方法实现了函数的复用,又能保证每个实例都有它自己的属性。
复制代码 代码如下:
function Parent(name) {
this.name = name;
this.colors = ['red', 'yellow'];
}
Parent.prototype.sayName = function() {
alert(this.name);
}
function Child(name, age) {
Parent.call(this, name); //第二次调用Parent()
this.age = age;
}
Child.prototype = new Parent(); //第一次调用Parent(),父类的属性会
Child.prototype.sayAge = function() {
alert(this.age);
}
var c1 = new Child('zhangsan', 20);
var c2 = new Child('lisi', 21);
c1.colors.push('blue');
alert(c1.colors); //red,yellow,blue
c1.sayName(); //zhangsan
c1.sayAge(); //20
alert(c2.colors); //red,yellow
c2.sayName(); //lisi
c2.sayAge(); //21
组合继承的问题是,每次都会调用两次超类型构造函数:第一次是在创建子类型原型的时候,另一次是在子类型构造函数内部。这样就会造成属性的重写 ,子类型构造函数中包含了父类的属性,而且子类的原型对象中也包含了父类的属性。
3、寄生组合继承-最完美继承方式
所谓寄生组合继承,即通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。 其背后的基本思路是:不必为了指定子类的原型而调用超类型的构造函数,我们所需要的无非就是超类型原型的一个副本
复制代码 代码如下: