记录一下我对于原型链继承的理解:
继承属性
JavaScript 对象是动态的属性“包”(指其自己的属性)。JavaScript
对象有一个指向一个原型对象的链。当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾。
遵循ECMAScript标准,someObject.[[Prototype]] 符号是用于指向 someObject 的原型。从
ECMAScript 6 开始,[[Prototype]] 可以通过 Object.getPrototypeOf() 和
Object.setPrototypeOf() 访问器来访问。这个等同于 JavaScript 的非标准但许多浏览器实现的属性
proto。但它不应该与构造函数 func 的 prototype 属性相混淆。被构造函数创建的实例对象的 [[prototype]] 指向 func
的 prototype 属性。Object.prototype 属性表示 Object 的原型对象
上述引用MDN,意思就是实例对象他会继承属性prototype。Pprototype相当于一个指针,它会指向创建对象的构造函数原型。
- 这里我使用了一个情景,Teacher教Student数学(math)。如下代码:
//创建一个Teacher构造函数
function Teacher(name,age,gender){
this.name = name;
this.age = age;
this.gender = gender;
}
//创建一个math方法。
Teacher.prototype.math = function(){
console.log('我会解几何题');
}
//创建Teacher对象tea
var tea = new Teacher('tom',30,'male');
console.log(tea);
//tea对象可以直接调用math方法
tea.math();
//创建一个Student构造函数
function Student(name,age,gender){
this.name = name;
this.age = age;
this.gender = gender;
}
//创建Student对象stu,没有给Student创建math方法,此时stu还不能调用math方法
var stu = new Student('xiaoming',10,'male');
console.log(stu);
这段代码在内存中的指向如下图所示:
- 接下来将stu实例直接指向tea实例(stu.prototype = tea.prototype);
代码及指向图如下:
function Teacher(name,age,gender){
this.name = name;
this.age = age;
this.gender = gender;
}
Teacher.prototype.math = function(){
console.log('我会解几何题');
}
var tea = new Teacher('tom',30,'male');
console.log(tea);
tea.math();
function Student(name,age,gender){
this.name = name;
this.age = age;
this.gender = gender;
}
/*原型链继承*/
//Student实例指向Teacher
Student.prototype = new Teacher();
var stu = new Student('xiaoming',10,'male');
console.log(stu);
输出结果:
此时,stu相当于是Teacher的实例对象了,所以stu的类类型为Teacher,明显这不是我们要的结果。
- 所以需要stu实例指回Student构造函数:
任何JavaScript函数都可以用作构造函数,并且调用构造函数是需要用到一个prototype属性的,因此,每个JavaScript函数(ECMAScript5中的Function.bind()方法返回的对象除外)都自动拥有一个prototype属性,这个属性的值是一个对象,这个对象包含唯一一个不可枚举的属性constructor。构造函数的原型中预先定义了constructor属性,对象通常继承的constructor均指代他们的构造函数。由于构造函数是类的“公共标识”,因此这个constructor属性为对象提供了类。这就是能使stu实例能重新指向Student的原因。
这样就实现了构造函数的继承。最终结果: