extend
关键字继承某个类(class)以轻松实现复用。class
关键字让我么可以伪造一个“类”,但其实只是语法糖而已,本质上仍然是一个对象。ES6实现的继承,本质仍是基于原型和原型链。prototype
是函数的一个属性而已,也是一个对象,它和原型没有绝对的关系(很多书、很多网络文章都模糊地将prototype表述为原型,这是严重不对的)。JavaScript里函数也是一种对象,每个对象都有一个原型,但不是所有对象都有prototype
属性,实际上只有函数才有这个属性。__proto__
,指向他的构造函数(constructor)的prototype
属性。prototype
属性的值,因此__proto__
也即原型的代名词。__proto__
也有自己的__proto__
,层层向上,直到__proto__
为null。换句话说,原型本身也有自己的原型。这种由原型层层链接起来的数据结构成为 原型链。因为null不再有原型,所以原型链的末端是null。使用__proto__
是有争议的,也不鼓励使用它。因为它从来没有被包括在EcmaScript语言规范中,但是现代浏览器都实现了它。__proto__
属性已在ECMAScript 6语言规范中标准化,用于确保Web浏览器的兼容性,因此它未来将被支持。但是,它已被不推荐使用,现在更推荐使用Object.getPrototypeOf
/Reflect.getPrototypeOf
和Object.setPrototypeOf
/Reflect.setPrototypeOf
(尽管如此,设置对象的原型是一个缓慢的操作,如果性能要求很高,应该避免设置对象的原型)。
Object.setPrototypeOf
(类似Reflect.setPrototypeOf
)可以很方便地给对象设置原型,这个对象会继承该原型所有属性和方法。setPrototypeOf
的性能很差,我们应该尽量使用 Object.create()
来为某个对象设置原型。hasOwnProperty
方法并未在newObj
上定义,也没有在它的原型obj
上定义,是它原型链上原型Object.prototype
的方法。其原型链查找顺序如下图所示:constructor
属性。这和函数的prototype属性表现具有一致性。prototype
属性上面。同样可以通过Chrome调试验证,请自行验证。prototype
属性和__proto__
属性,因此同时存在两条继承链。__proto__
属性,表示构造函数的继承,总是指向父类。prototype
属性的__proto__
属性,表示方法的继承,总是指向父类的prototype
属性。