整个原型链大体可以用下图来表示
当我们写下 let fn = new Fn()的时候,会发生什么呢?
1. let fn = {}
2. fn.__proto__ = Fn.prototype
3. Fn.call(this) //调用Fn的构造函数并指向fn对象
使用原型链来实现继承有两种写法
1:A.prototype.__proto = Fn.prototype。
每一个原型对象中都有一个指针.__proto__,指向的是父类的prototype对象,即默认是指向Object.prototype, 如果想让A继承Fn,只需改变该指针的指向即可:A.prototype.__proto = Fn.prototype。
这种方法
1.保留A自身的原型变量(方法)
2.可以继承Fn的原型方法
3.不能继承Fn中的实例变量(方法)。
function Fn(){
this.name = 'i am Fn';
}
function A(){ }
Fn.prototype.prototype_Fn = 'i am prototype_Fn'
A.prototype.prototype_A = 'i am prototype_A'
//1 原型链第一种.保留B自身的原型变量(方法),可以继承A的原型方法 ,不能继承A中的实例变量(方法)。
A.prototype.__proto__ = Fn.prototype;
let a = new A();
console.log(a)
console.log(a.prototype_A); // i am prototype_A 保留A的原型变量
console.log(a.prototype_Fn); //i am prototype_Fn 继承Fn的原型变量
console.log(a.name); //undefine 无法继承Fn的实例变量
console.log(A.prototype.constructor) //还是A的构造函数
顺带一提,es6 class中的继承好像就是这种方式。
2:A.prototype = new Fn()
这种方法,相当于创建了一个Fn实例对象,然后覆盖A的原型对象;
1.不能保留A自身的原型变量(方法)
2.可以继承Fn的原型方法
3.继承Fn中的实例变量(方法)。
function Fn(){
this.name = 'i am Fn';
}
function A(){ }
Fn.prototype.prototype_Fn = 'i am prototype_Fn'
A.prototype.prototype_A = 'i am prototype_A'
A.prototype = new Fn();
let a = new A(); //相当于创建了一个Fn对象,然后赋值给a
console.log(a)
console.log(a.prototype_A); // undefine 不能保留A自身的原型变量
console.log(a.prototype_Fn); //i am prototype_Fn 继承Fn的原型变量
console.log(a.name); //i am Fn 可以继承Fn的实例变量,因为就是把一个Fn实例覆盖掉A的原型对象
console.log(A.prototype.constructor) // 变成了Fn的构造函数
3:使用call/apply借用父类的构造函数
function ChinaPerson(name){
this.china_walk = 'i am ' + name+ ' can walk in china way';
}
function UkPerson(name){
this.uk_walk = 'i am ' + name+ ' can walk in uk way';
}
ChinaPerson.prototype.proto_Walk = 'prototype walk china'
function Man(){
// 这里的this就是实例man
// ChinaPersib.call意思是调用父类的构造函数,并传入该实例进行构造
// 可以调用多个call多继承
ChinaPerson.call(this,'刘嘉鹏');
UkPerson.call(this,'liuj4');
}
Man.prototype.proto_man = 'proto_man';
let man = new Man();
console.log(man.china_walk); //i can walk in china way 继承父类的实例变量
console.log(man.uk_walk); // i can walk in UK way //继承父类的实例变量
console.log(man.proto_Walk) //undefined 获取不到父类的原型成员
console.log(man.proto_man) //proto_man 保留自身的原型成员
// Man.prototype.__proto__ = ChinaPerson.prototype //加上这句即可继承父类的原型成员
总结一下:
1.A.prototype.__proto__ = Fn.prototype: 原型链继承,无法继承父类的实例成员;
2.A.prototype = new Fn(): 用父类实例对象来覆盖A的原型对象,会丢失A本身的原型成员;
3.使用call来调用父类的构造函数实现继承,无法继承父类的原型成员;
4. 使用1+3 / 2+3组合,但只要使用了A.prototype = new Fn(),就必定会丢失A本身的原型成员;
以上纯属个人学习经验,若有错误,还望指出~