前言
今天在复习原型的知识点时,发现有些对原型继承有点模糊。上网查了一下ES5原型继承的方法,各种继承方法看的有点小晕。大家比较认可的应该是 寄生组合式继承 。我在知乎上看到一篇文章,让我受益良多,这篇文章是我自己做的学习总结。JS的继承 - 若川
原型
首先复习一下原型,我画了个图
当寻找一个对象的属性是,如果对象本身没有这个属性,则在对象的原型链上一层一层往上找(原型链是靠隐式原型
__proto__
链接起来的)。
关于继承
引用大佬的一句话:
继承对于JS来说就是父类拥有的属性和原型方法、静态方法等,子类也要拥有。
之前我一直以为,只要Child.prototype.__proto__ = Parent.prototype
就可以了。但是看了若川大佬的文章,我才发现,这样只能让子类继承父类的实例属性和实例方法(在我看来,原型方法也叫实例方法)。
要拿到父类的静态属性和静态方法,还需要注意构造器的原型链继承 Child.__proto__ = Parent;
代码
// 父亲
function Parent(num) {
this.num = num;
}
// 原型属性和原型方法
Parent.prototype.type = 'human';
Parent.prototype.sayNum =function(){
console.log('num:' + this.num);
}
// 静态属性和静态方法
Parent.staticType = 'staticHuman';
Parent.sayHello = function () {
console.log('Hello')
}
// 儿子
function Child(num,age) {
// 相当于super
// 子类构造器里调用父类构造器,继承父类的属性。
Parent.call(this,num);
this.age = age;
}
Child.prototype.sayAge = function () {
console.log('age:' + this.age);
}
继承
// 子类构造函数的prototype的__proto__指向父类构造器的prototype,继承父类的方法。
Child.prototype.__proto__ = Parent.prototype;
// 子类构造函数的__proto__指向父类构造器,继承父类的静态方法
Child.__proto__ = Parent;
测试
const parent = new Parent(1);
console.log(parent.type); //human
console.log(Parent.staticType); //staticHuman
parent.sayNum(); //1
Parent.sayHello(); //Hello
const child = new Child(2,18);
console.log(child.type); //human
console.log(Child.staticType); //staticHuman
child.sayNum(); //2
child.sayAge(); //18
Child.sayHello(); //Hello
Object.setPrototypeOf()
其中__proto__
是浏览器自己的实现,也可以用Object.setPrototypeOf()
的方法设置隐式原型
Child.prototype.__proto__ = Parent.prototype
// 等同于
Object.setPrototypeOf(Child.prototype, Parent.prototype)
小结
我也用ES6的语法写了一遍,测试结果是一样的。虽然ES6的class、extends语法糖真的很香,但是我觉得理解一下ES5的原型继承也是很有必要的。如果有大佬发现哪里有问题,欢迎评论指出~