前言
最近在学习继承的一些东西,写这篇文章也是为了让自己的学习更加贯彻一下吧!
学习过程是通过 死磕36JS手写题这篇文章来学习的,所以有些代码可能应用了上面的,感兴趣的可以去看一下那篇文章!
原型链继承
先来看一下代码吧!
function Animal() {
this.colors = ['black', 'white']
}
Animal.prototype.getColor = function() {
return this.colors
}
function Dog() {}
Dog.prototype = new Animal()
let dog1 = new Dog()
dog1.colors.push('brown')
let dog2 = new Dog()
console.log(dog2.colors) // ['black', 'white', 'brown']
我知道光看这代码可能有点蒙,所以根据自己的理解我画了一下里面的“恩爱情仇”,如有不足的地方希望大家帮我指出
我就就着图给大家简单的解释一下吧!
- Animal的原型Animal.prototype的getColor属性等于function()函数,就相当于Animal的原型获得了返回colors的能力
- Animal的实例化对象等于Dog.prototype,相当于Dog的原型继承了Animal的属性
- Dog的实例化对象dog1在colors数组了新加入了一个颜色brown,所以Dog里面也有了brown属性
- Dog再一次实例化了一个对象dog2,所以dog2里面的colors数组有了三种颜色。
- 原型链继承存在的问题:
问题1:原型中包含的引用类型属性将被所有实例共享;
问题2:子类在实例化的时候不能给父类构造函数传参;
借用call
老规矩,先看代码!
function Parent1(){
this.name = 'parent1';
}
function Child1(){
Parent1.call(this);
this.type = 'child1'
}
console.log(new Child1); //parent1,child1
什么是call()?
call() 方法是预定义的 JavaScript 方法。
它可以用来调用所有者对象作为参数的方法。
通过 call(),您能够使用属于另一个对象的方法。
所以这就是为什么call可以实现继承的原因。
但是还有个问题:这样写的时候子类虽然能够拿到父类的属性值,但是问题是父类原型对象中一旦存在方法那么子类无法继承
组合继承
组合继承结合了原型链和盗用构造函数,将两者的优点集中了起来。基本的思路是使用原型链继承原型上的属性和方法,而通过call继承实例属性。这样既可以把方法定义在原型上以实现重用,又可以让每个实例都有自己的属性。
先看代码!
function Animal(name) {
this.name = name
this.colors = ['black', 'white']
}
Animal.prototype.getName = function() {
return this.name
}
function Dog(name, age) {
Animal.call(this, name)
this.age = age
}
Dog.prototype = new Animal()
Dog.prototype.constructor = Dog
let dog1 = new Dog('奶昔', 2)
dog1.colors.push('brown')
let dog2 = new Dog('哈赤', 1)
console.log(dog2)
// { name: "哈赤", colors: ["black", "white"], age: 1 }
- Dog函数里 Animal.call(this,name)继承Animal()函数的name属性
- Dog.prototype = new Animal()让Dog继承了Animal的colors属性以及getName方法
- Dog.prototype.constructor = Dog 让Dog.prototype的构造函数是Dog。
- 这样就实现了继承
寄生式组合继承
组合继承虽然解决了问题,已经算是比较完善了,但是它也产生了新的问题,就是调用了2次父类构造函数,第一次是new Animal(),第二次是在Animal.call()这里,所以我们可以再优化一下。 解决办法就是我们不让父构造函数给子类原型赋值,而是创建一个第三方,让第三方函数获取父类原型的副本
function Parent5 () {
this.name = 'parent5';
this.play = [1, 2, 3];
}
function Child5() {
Parent5.call(this);
this.type = 'child5';
}
Child5.prototype = Object.create(Parent5.prototype);
Child5.prototype.constructor = Child5;
这种方法可以说是最完美的啦(撒花),所有的问题都被完美解决了
在这里我们小小的解释一下
Child5.prototype = Object.create(Parent5.prototype);
这句代码的意思就是:基于Parent5.prototype创建一个新的原型(此原型会有Parent5原型的所有属性)赋值给Child5.prototype。
在这里,我们就成功的把两次调用父类构造函数变成了一次。
class 实现继承
先上代码!
class Animal {
constructor(name) {
this.name = name
}
getName() {
return this.name
}
}
class Dog extends Animal {
constructor(name, age) {
super(name)
this.age = age
}
}
class继承其实和原型链继承没啥区别,但是它可比原型链要香一点(在我看来)!
香在哪里呢?
- 极大地简化了原型链代码。 看见了上面原型链继承有时候是不是有点绝望啊?我也是,但是没关系,我们有class,它大大的简化了原型链代码,是不是有点拨云见日的感觉啊,哈哈!
- class应用起来也是非常方便的,它在定义对象和方法的时候就可以用extends来实现继承。(香香)
总结
老师告诉我,学习必须要想苦行僧般的徒步旅行,每一步要走踏实,每一次都不能停下!加油,自己。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!