继承模式
原型链实现继承时,将对象实例视作一个子类原型创建对象实例时,其本身从构造函数中继承的实例属性,此时成为了原型属性,原型属性中包含了”引用类型值”,导致子类原型的属性会被所有实例共享。
function SuperType(){
this.color = ['red', 'blue' , 'yellow'];
}
function SubType(){}
SubType.prototype = new SuperType()
var instance1 = new SubType();
instance1.color.push ('white');
alert(instance1.color); // red,blue,yellow,white
var instance2 = new SubType();
alert(instance2.color); // red,blue,yellow,white
单独借用构造函数也并未解决这问题
1. 组合继承
模式:原型链+借用构造函数
- 使用原型链实现对原型属性和方法的继承;
- 借用构造函数来实现对实例属性的继承。
function SuperType(name){
this.name = name;
this.color = ['red', 'blue' , 'yellow'];
}
SuperType.prototype.sayName = function(){
alert(this.name);
}
function SubType(name, age){
//继承属性 超类
//获得name和color属性
SuperType.call(this, name);
this.age= age;
}
//继承方法
SubType.prototype = new SuperType();
SubType.prototype.sayAge = function(){
alert(this.age)
}
var instance1 = new SubType("Nicholas", 29);
instance1.color.push("black");
console.log(instance1.color); //["red", "blue", "yellow", "black"]
instance1.sayName();
instance1.sayAge();
var instance2 = new SubType("Greg", 27);
console.log(instance2.color); //["red", "blue", "yellow"]
instance2.sayName();
instance2.sayAge();
SubType构造函数,通过call()方法调用SuperType构造函数是传入name参数,此时获得name与color属性;(借用构造函数)
将SuperType的实例赋值给SubType的原型;(原型链)
instanceof 和 isPrototypeof()能够识别基于组合继承创建的对象。
2.原型式继承
借助原型可以基于已有的对象创建新对象,同时还不必因此创建自定义类型。多用于让一个对象与另一对象保持类型的情况,不必在创建构造函数。
function object (o) {
// 创建临时构造函数
function F(){}
// 将传入的对象作为构造函数的原型
F.prototype = o;
// 返回临时构造函数的实例
return new F();
}
//基础对象
var person = {
name : "Nicholas",
friends : ["Shelby", "Count", "Van"]
};
// 返回新对象,以person为原型
var anotherPerson = object(person);
anotherPerson.name = "Greg";
anotherPerson.friends.push("Rob");
console.log(anotherPerson.friends); //["Shelby", "Count", "Van", "Rob"]
var yetAnotherPerson = object(person);
yetAnotherPerson.name = "Linda";
yetAnotherPerson.friends.push("Barbie");
console.log(yetAnotherPerson.friends); //["Shelby", "Count", "Van", "Rob", "Barbie"]
console.log(person.friends); //["Shelby", "Count", "Van", "Rob", "Barbie"]
基本类型值 :
- Undefined、Null、Boolean、Number和String
- 引用时是对实际原型进行了一次复制,通过引用值对基本类型值进行修改的结果,并不会被共享。每次引用就像对实际值进行了一次克隆,但克隆值得修改并不会影响被克隆原型。
引用类型值 :Object 、 Array 、 Date 和 RegExp
- 对象实例中的引用类型属性是一个指向对象实际位置的指针,所有实例都指向同一个位置,当其中一个实例对指针地址中的属性进行修改后,会影响之后所创建的变量。
//判断对象类型
function isArray(o) {
return Object.prototype.toString.call(o) === '[object Array]';
//Array可以换成其它类应用以验证
}
var str = "string";
alert(isArray(str)); //false
ES5新增: Object.create( ) 原型式继承
- Object.create() 方法接收两个参数:
- 用作新对象原型的对象(必选) ,仅一个参数时与Object( )方法类似;
- 为新对象定义额外属性的对象(可选),第二参数与Object.defineProperties(obj, props)方法第二参数格式相同:每个属性都是通过自己的描述符定义的。
var person = {
name : "Nicholas",
friends : ["Shelby", "Count", "Van"]
};
var anotherPerson = Object.create(person,{
name:{
value:"Grey"
},
age:{
value:15
}
});
console.log(anotherPerson.name ); // Grey
console.log(anotherPerson.age); // 15
3.寄生式继承
创建一个用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后返回该对象。
// 寄生式构造函数
function createAnother(o){
// Object()函数可换成其他返回新对象的函数
var clone = Object(o);
clone.sayName = function(){
alert('name');
};
return o;
}
var o = {
name:'Grey',
age:16
};
// 返回的新对象,具有基础对象的方法和属性,并拥有自己的sayName方法
var person =createAnother(o);
person.sayName();
寄生式继承为对象添加的函数不能复用
4.寄生组合式继承
JavaScript最常用的继承模式
通过创建一个过渡对象,作为超类型和子类型的桥梁,减少超类的调用次数,
// 组合继承实例
function SuperType(name){
this.name = name;
this.color = {"red", "blue", "green"};
};
SuperType.prototype.sayName = function(){
alert(this.name);
};
function SubType(name, age) = function(){
// 第二次调用SuperType()
SuperType.call(this, name);
this.age = age;
}
// 第一次调用SuperType()
SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function(){
alert(this.age);
}
inheritPrototype()函数接受两个参数: 子类型构造函数和超类型构造函数。
创建步骤:① 创建超类型原型的副本;
② 为副本指定constructor属性方向;
③ 将副本赋值给子类型的原型。
// 寄生组合式继承的最简单形式
function inheritPrototype(subType, superType){
// 创建对象 作为超类原型的副本
var prototype = object (superType.prototype);
// 修改副本的constructor属性的指向
prototype.constructor = superType;
// 将prototype中存放的副本赋值给子类的原型
subType.prototype = prototype;
}
function SuperType(name){
this.name = name;
this.color = {"red", "blue", "green"};
}
SuperType.prototype.sayName = function(){
alert(this.name);
};
function SubType(name, age){
//调用了一次SuperType
SuperType.call(this.name);
this.age = age;
};
//替换前面为子类型原型赋值的语句
inheritPrototype(SubType, SuperType);
SubType.prototype.sayAge = function(){
alert(this.age);
};
避免了在SubType.prototype上面创建不必要的、多余的属性;
原型链保持不变,能够正常使用instanceof 和isPrototypeOf();
寄生组合式继承是引用类型最理想的继承范式。