使用js实现继承,主要是依靠原型链实现的
原型链
想要知道原型链是什么,先了解构造函数,原型,与实例之间的关系
- 构造函数:可用来创建特定类型的对象。
构造函数与其他函数的区别是在于调用方式的不同。
使用new操作符来调用的函数都是构造函数,函数名默认以大写字母开头 - 实例:以构造函数的初始化对象,通过用new操作符
- 原型:每个函数一旦被创建就有一个prototype属性(原型),是实例的原型对象
构造函数,原型,与实例之间的关系就是:每个构造函数都有一个原型对象,而实例又指向原型对象
现在我们再来看,什么是原型链?
把一个A类型原型对象等于B类型的实例。此时,A类型原型对象指向B类型原型对象,B类型原型对象指向B构造函数,当实例化一个A构造函数时,他们之间的关系就是:
实例A->A构造函数->A原型对象->B实例->B构造函数->B原型对象
这样的层级递进就是原型链,同时我们也可以看到A继承了B。代码如下:
function Aclass() {
this.Aname = "a";
}
Aclass.prototype.getAName = function() {
alert(this.Aname);
}
function Bclass() {
this.Bname = "b";
}
Bclass.prototype = new Aclass();
Bclass.prototype.getBName = function() {
alert(this.Bname);
}
var newObj = new Bclass();
newObj.getAName() ;//a
newObj.getBName() ;//b
console.log(newObj)
如此可见,原型链实现了继承,但是它也有缺点
一个是还记得上一章使用原型模式实现类中,原型包含像array这样引用类型值的原型属性时会被共享,例如:
…
Aclass.prototype.arr = [“A”];
…
var newObj1 = new Bclass();
newObj1.arr.push(“B”);
console.log(newObj1.arr);//[“A”,“B”]
var newObj2 = new Bclass();
console.log(newObj2.arr);//[“A”,“B”]
二是在创建B类型(子类)实例时,无法向A类型(父类)构造函数中传递参数
借用构造函数(伪造对象 || 经典继承)
在B类型(子类)构造函数内部调用A类型(父类)构造函数
function Aclass(name) {
this.Aname = [name];
}
function Bclass() {
Aclass.call(this,"a")
}
var newObj = new Bclass();
newObj.Aname.push("newObj");
console.log(newObj.Aname) // ["a","newObj"]
var newObj2 = new Bclass();
console.log(newObj2.Aname) // ["a"]
这个例子中我们通过call"借调"了Aclass(父类)的构造函数(也可以用apply)。
优点:解决了原型上共享引用类型属性的问题,能够传递参数
缺点:无法共享方法,每次实例化重新创建
组合继承(伪经典继承)
将原型链和借用构造函数组合到一块,发挥两者之长。使用原型链实现对原型属性和方法的继承,使用借用构造函数实现对实例属性的继承。组合达到既可以实现函数复用,又能在每个实例有自己的属性。看下面的例子:
function Aclass(name) {
this.name = name;
this.arr = ["A"];
}
Aclass.prototype.sayName = function() {
alert(this.name);
}
function Bclass(name,s) {
Aclass.call(this,name);
this.string = s;
}
Bclass.prototype = new Aclass();
Bclass.prototype.constructor = Bclass;
Bclass.prototype.sayString = function() {
alert(this.string)
}
var newObj = new Bclass("newObj", "Hello");
newObj.arr.push("B");
console.log(newObj.arr) //["A","B"]
newObj.sayName(); //"newObj"
newObj.sayString() //"Hello"
var newObj2 = new Bclass("newObj2 ", "Bye");
newObj2 .arr.push("C");
console.log(newObj2 .arr) //["A","C"]
newObj2 .sayName(); //"newObj2 "
newObj2 .sayString() //"Bye"