原型链继承
原型链继承的思想是利用原型让一个引用类型去继承另一个引用类型的属性和方法。
每个构造函数都有一个prototype
属性,这个属性是一个对象,包含实例可以共享的属性和方法。如果A构造函数的prototype
属性被赋值为B构造函数的实例,那么A的实例就继承了B的实例上所有能够访问的属性和方法,这就是原型链继承。
function B() {
this.name = "James"
}
B.prototype.sayHi = function(){};
function A(age) {
this.age = age
}
A.prototype = new B;
let a = new A(28);
a.name //James
原型链继承的缺点是,父类的引用值将会在子类实例间共享,一个子类实例修改了引用值,这个修改会反应到其他实例上。
借用构造函数继承
借用构造函数继承的思想是在子类的构造函数内,使用
call()
或apple()
以新创建的对象为上下文来调用父类构造函数,从而继承父类的属性和方法。
借用构造函数继承解决了原型链继承中父类引用值被子类实例共享的问题;而且在借用构造函数中,也可以为父类构造函数传参。
借用构造函数继承的不足之处是父类中的方法不能被复用。
function Foo(name) {
this.name = name;
this.hobby = ['sing']
this.sayHi = function() {};
}
function Bar(age) {
Foo.call(this, 'James');
this.age = age;
}
let bar = new Bar;
let baz = new Bar;
bar.hobby.push('reading')
bar.name //James
bar.hobby // ['sing', 'reading']
baz.hobby //['sing']
组合继承
组合继承结合了原型链继承和借用构造函数继承的优点。
组合继承的思想是使用原型链的继承原型的属性和方法,使用借用构造函数实现实例属性的继承。这使得子类实例拥有了自己的属性,又实现了函数的复用。
function Foo(name) {
this.name = name;
}
Foo.prototype.sayHi = function() {};
function Bar(age) {
Foo.call(this, 'James');
this.age = age;
}
Bar.prototype = new Foo;
Bar.prototype.constructor = Bar; //使对象类型指回原来的构造函数
组合继承的不足之处在于父类构造函数需要被调用两次,使得子类原型上多了些不必要的属性。
原型式继承
原型式继承的思想是基于已有对象来创建新对象。
原型式继承是如何实现的呢?
方法是往一个函数中传入一个对象,然后返回以这个对象为原型的对象。Object.create()
方法就是原型式继承的实现。
function inherit(o){
function Foo() {};
Foo.prototype = o
return new Foo();
}
原型式继承的不足之处与原型链继承一样,都是父类的引用值会在所有实例间共享。
寄生式继承
寄生式继承的思想是使用原型式继承生成一个对象,然后增强这个对象。
function inherit(o) {
let foo = Object.create(o);
foo.sayHi = function() {};//给foo对象添加方法。
return foo;
}
寄生组合式继承
寄生组合式继承的思想是以原型式继承来继承父类的方法,以借用构造函数来继承属性。
其优点是继承了父类原型,而不需要调用父类构造函数,确保了子类原型上不必添加非必要属性。
function inherit(child,parent) {
let prototype = Object.create(parent.prototype);
prototype.constructor = child;
child.prototype = prototype;
}
function Parent(name) {
this.name = name;
}
Parent.prototype.sayHi = function() {};
function Child(age) {
Parent.call(this,'James')
this.age = age;
}
inherit(Child,Parent);
网友评论