再讲述JS原型链继承之前,我希望大家能够先理解 《函数,函数原型和函数实例之间的关系》,这样有助于大家理解JS原型链继承的原理,下面先看一张图吧,咱们看图说话:
如果大家看完了 《函数,函数原型和函数实例之间的关系》 这篇文章,应该多少能明白原型链继承的原理了。
如上图所示: Personal
对象想要继承 Main
对象,则通过将 Main
的实例赋值给 Personal 的原型对象 :
Personal.prototype = new Main () ;
如此 Personal原型对象 就能通过 Main
对象的实例中的 [[Prototype]]
来访问到 Main原型对象 中的属性和方法了,而此时大家注意,Personal原型对象 则与 Personal函数 断开了联系,因为Personal原型对象被重新赋值了,所以还需要重新将Personal函数和Personal原型对象建立联系:
Personal.prototype.constructor = Personal ;
完整代码如下:
function Main () {
}
Main.prototype.sex = '男' ;
Main.prototype.eat = function () {
console.log('Main eat ...')
}
function Personal () {}
Personal.prototype.name = 'hwk';
Personal.prototype.sayName = function () {
console.log('Personal name')
}
// 继承
Personal.prototype = new Main();
Personal.prototype.constructor = Personal;
var p = new Personal();
console.log(p.sex ) ; // 男
console.log(p.name) ; // undefined
p.eat(); // Main eat ...
p.sayName (); // Uncaught TypeError:p.sayName is not a function
运行如上代码你会发现 p.name
为 undefined
, p.sayName
这个方法没找到,原因在于我们后面重新赋值了 Personal.prototype = new Main();
因此找不到一开始定义在 Personal.prototype 上的name
属性和sayName
方法,因此在使用原型链继承的时候,要在继承之后再去在原型对象上定义自己所需的属性和方法:
// 先继承
Personal.prototype = new Main();
Personal.prototype.constructor = Personal;
// 后定义属性和方法
Personal.prototype.name = 'hwk';
Personal.prototype.sayName = function () {
console.log('Personal name')
}
// 正确输出
console.log(p.sex ) ; // 男
console.log(p.name) ; // hwk
p.eat(); // Main eat ...
p.sayName (); // Personal name
此时 Personal的实例 已经可以访问到父类Main原型对象中的方法和属性了,这也就是原型链继承的方式,希望对大家有帮助!
PS:在原型对象上定义属性和方法,其所有的构造函数实例都能共享原型上的属性和方法,因此如果某一个构造函数实例对象修改了原型对象上的属性值和方法,则也会影响其他实例对象。