继承与原型链

继承与原型链

对于有基于类的语言经验(如Java或C++)的开发人员来说,JavaScript有点令人困惑,因为它是动态的,并且本身不提供一个class实现。(在ES2015/ES6中引入了class关键字,但只是语法糖,JavaScript仍然是基于原型的)。

当谈到继承时,JavaScript只有一种结构:对象。每个实例对象(object)都有一个私有属性(称之为proto)指向它的原型对象(prototype)。该原型对象也有一个自己的原型对象,层层向上直到一个对象的原型对象为null。根据定义,null没有原型,并作为这个原型链中的最后一个环节。

几乎所有JavaScript中的对象都是位于原型链顶端的Object的实例。

尽管这种原型继承通常被认为是JavaScript的弱点之一,但是原型继承模型本身实际上比经典模型更强大。例如,在原型模型的基础上构建经典模型相当简单。

基于原型链的继承

JavaScript对象是动态的属性“包”(指其自己的属性)。JavaScript对象有一个指向一个原型对象的链。当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾。

给对象设置属性会创建自有属性。获取和设置属性的唯一限制是内置getter或setter的属性。

继承方法

JavaScript并没有其他基于类的语言所定义的“方法”。在JavaScript里,任何函数都可以添加到对象上作为对象的属性。函数的继承与其他的属性继承没有差别,包括上面的“属性遮蔽”(这种情况相当于其他语言的方法重写)。

当继承的函数被调用时,this指向的是当前继承的对象,而不是继承的函数所在的原型对象。