javascript原型链
javascript原型链
在es6出来之前,js里没有class关键字,实现继承只能手动操作原型链。es6种新增的class也是原型链的语法糖,所以要学好js是绕不开原型链的,最少面试也要问。
首先我们看下原型链是怎么使用的。
1 | function Animal() { |
在这段代码中,在Animal上没有定义eat,但是在实例上可以调用eat方法。因为在原型上定义了eat方法,在实例上调用eat的时候找不到,会自动在原型上查找,如果原型查不到,会查原型的原型。
graph TD p(Animal) --prototype--> p2(Animal.prototype) p2--constructor--> p dog(dog) -- __proto__ --> p2 p --new-->dog p2--__proto__--> op(Object.prototype) subgraph object o(Object)--prototype-->op op--constructor--> o end op--__proto__-->null
上面的图表示原型和构造函数和实例之间的关系。构造函数创建实例,实例的__proto__指向原型,原型的constructor指向构造函数,原型通过__proto__指向原型的原型。最终会找到null
原型查找的路径
graph LR p2(Animal.prototype) dog(dog) -- __proto__ --> p2 p2--__proto__--> op(Object.prototype) op--__proto__-->null
特殊的原型
1 | Function.prototype.__proto__ === Object.prototype |
Object.create一个方便使用原型链的工具
Object.create()
方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__。示例
1 | let dog2 = Object.create(dog) |
Object.create的实现方法
1 | function create(o) { |
利用原型链实现继承, 首先我们创建一个父类。然后创建一个子类,继承的话要处理两部分的问题,第一个属性继承的问题,第二方法继承。属性的话,可以直接调用父类构造函数,然后将this绑定到子类就行,通过call方法,将父类构造函数的this替换,在父类构造函数执行完之后,构造函数里提供的属性就会添加到子类this上。方法的话使用原型来继承, 只要让Child.prototype能找到Parent.prototype的方法就行,可以使用Object.create来实现,Child.prototype = Object.create(Parent.prototype),这样Child.prototype可以根据原型找到Parent.prototype, 最后修正构造函数就行
1 | function Animal() { |
graph LR dog--__proto__--> dp[Dog.prototype]--__proto__-->Animal.prototype
es5实现的继承和es6继承的不同点
- 在调用supper之前,es6的class是不能访问this, es5的可以, es5中子类this是先构造出来的,在调用父类,es6中是父类this先构造