之前发过一篇关于继承的博客。不过,当时理解的一般,写的也不怎么样。这次重新回头理了一下关于构造函数的继承。
因为ES5没有类的概念。所以,才会有构造函数模拟类。首先让我们用一张图来理清楚构造函数、原型、实例三者之间的关系。
代码还有关系如下:
function Parent(){
this.name = "A";
}
function.prototype.run = function(){
console.log("run");
}
let parent = new Parent();
首先。
1》每一个构造函数都有一个原型。
2》原型上有一个constructor构造器,并且指向构造函数本身。
3》每个实例上都有一个__proto__链,指向实例的构造函数的原型。
4》name是私有属性。
5》run是公有属性(方法)
证据是
Parent.prototype.constructor === Parent;
parent.__proto__ === Parent.prototype;
这里说下继承的三种情况。
一、继承私有属性的继承。一般采用call或者apply的形式。如
function Child(){
Parent.call(this); //原理就是将Parent执行时候本该指向实例的this指向了Child。所以在Child实例化的时候,实例本身就具备了name的私有属性。
this.age = 9;
}
let child = new Child();
console.log(child.name); //A
二、集成公有属性。
这里经常见到一些错误的继承方式。
如:Child.prototype = Parent.prototype;
let child1 = new Child();
child1.run();
这种确实能让child实例拿到Parent原型上的run方法。但是,这不叫继承因为这只是将Child的原型指向Parent的原型,二者共用。问题就是此时修改Child.prototype,就会造成Parent.prototype的变动。因为,此时二者就是一个空间。
那么如何正确的进行继承呢?
第一种:Child.prototype.__proto__ === Parent.prototype;这种就是给Child的原型加一个原型链,支持在自身原型找不到时会向上Parent上查找。他的等价写法是 Object.setPrototypeOf(Child.prototype,Parent.prototype);前面是ES5的写法,后面是ES6的写法。
第二种:Child.prototype = Object.create(Parent.prototype);
原理源码见MDN,地址是https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/create