继承:继承的本质就是原型链。
实现继承了几种方式:
1.构造函数继承:
function Parent1(){ this.name = 'parent1'; } Parent1.prototype.say = function(){ console.log('Parent1-say!')} function Child1(){ Parent1.call(this); //call和apply方法都是用来转移上下文的(改变this的指向),使调用call方法的函数的this指向它的参数(也就是这里的this),所以Child1拥有了name属性,并且它的值是‘parent1’。 this.sex = 'man'; call和apply方法的作用完全相同,只是他们的第二个参数不同,call的参数必须一一列举出来,而apply的参数是一个数组,也可以用arguments代替。 } var p1 = new Child1();
这种方式的缺点是不能继承父类原型链。
当我们给Parent1.prototype 添加属性或方法不会被Child1继承。
2.原型链继承:
function P1() { this.name = 'parent1'; this.friends = [1, 2, 3]; } C1.prototype= new P1; 如果不传参可以不写‘()’ function C1() { this.sex = 'man'; } var a1 = new C1, a2 = new C1; console.log(a1, a2); a1.friends.push(4);
我们在最后一行只是给a1实例对象的friends属性添加了4,但是打印出的a2的friends也拥有这个4,这是因为他们的原型对象都指向了P1的同一个实例对象。那么这就不能满足每个实例都是独立的这个思想。
组合方式继承:
function P1() { this.name = 'parent1'; this.friends = [1, 2, 3]; } C1.prototype= new P1; function C1() { P1.call(this); this.sex = 'man'; } var a1 = new C1, a2 = new C1; console.log(a1, a2); a1.friends.push(4);
这种方式虽然实现了每个实例之间相互隔离,但是执行了两次构造函数P1。
优化继承:
function P1() {
this.name = 'parent1';
this.friends = [1, 2, 3];
}
C1.prototype= P1.prototype;
C1.prototype.constructor = C1;
function C1() {
P1.call(this);
this.sex = 'man';
}
var a1 = new C1, a2 = new C1;
console.log(a1, a2);
a1.friends.push(4);
这种方式是最优化的继承方式。不仅继承了父类的原型链,同时也明确了自己的构造函数。