你应该知道,JavaScript是一门基于原型链的语言,而我们今天的主题 -- “继承”就和“原型链”这一概念息息相关。甚至可以说,所谓的“原型链”就是一条“继承链”。有些困惑了吗?接着看下去吧。
一、构造函数,原型属性与实例对象
要搞清楚如何在JavaScript中实现继承,我们首先要搞懂构造函数,原型属性与实例对象三者之间的关系,让我们先看一段代码:
function Person(name, age) {
var gender = girl // ①
this.name = name // ②
this.age = age
}
// ③
Person.prototype.sayName = function() {
alert(this.name)
}
// ④
var kitty = new Person('kitty', 14)
kitty.sayName() // kitty
让我们通过这段代码澄清几个概念:
-
Person
是一个“构造函数”(它用来“构造”对象,并且是一个函数),①处gender
是该构造函数的“私有属性”,②处的语句定义了该构造函数的“自有属性”; - ③处的
prototype
是Person
的“原型对象”(它是实例对象的“原型”,同时它是一个对象,但同时它也是构造函数的“属性”,所以也有人称它为“原型属性”),该对象上定义的所有属性(和方法)都会被“实例对象”所“继承”(我们终于看到这两个字了,但是不要心急,我们过一会才会谈论它); - ④处的变量“kitty”的值是构造函数
Person
的“实例对象”(它是由构造函数生成的一个实例,同时,它是一个对象),它可以访问到两种属性,一种是通过构造函数生成的“自有属性”,一种是原型对象可以访问的所有属性;
对以上这些概念有清楚的认识,才能让你对JavaScript的“继承”与“原型链”的理解更加深刻,所以务必保障你已经搞清楚了他们之间的关系。(如果没有,务必多看几遍,你可以找张纸写写画画,我第一次就是这么做的)
彻底搞清楚了?那让我们继续我们的主题 -- “继承”。
你是否觉得奇怪,为什么我们的实例对象可以访问到构造函数原型属性上的属性(真是拗口)?答案是因为“每一个对象自身都拥有一个隐式的[[proto]]
属性,该属性默认是一个指向其构造函数原型属性的指针”(其实我想说它是一个钩子,在对象创建时默认“勾住”了其构造函数的原型属性,但是我发现emoji居然没有钩子的图标,所以...