-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
JavaScript常用八种继承方案 #7
Comments
👍 |
第一个原型继承图错啦,应该是构造函数SubType |
6、寄生组合式继承中最后一行代码写错了,应该是instance2 |
谢谢提醒 |
已更改 |
老哥,寄生组合式继承也有 原型链继承多个实例的引用类型指向相同,存在篡改可能的缺点吧。好像并不是是那么完美呢,js继承不是还有一个圣杯模式吗?圣杯模式不是继承里的最优吗? |
有吗 |
老哥,组合继承最后一句“组合模式的缺点就是在使用子类创建实例对象时,其原型中会存在两份相同的属性/方法。”改成“....,其原型中会存在一份相同的属性”感觉更合适,只重复了一次且是属性重复。 |
封装一个 |
我是菜鸟,弱弱的问一句,最后extends中 function _inherits中,“subType.prototype = ...” 不是已经设置了subType的原型了吗,为什么还要“if (superType) { Object.setPrototypeOf... ”再设置subType的原型啊? |
@jcz1206 设置subType.prototype,只有通过new生成的subType实例才会继承superType.prototype上的方法。 |
第6种继承方式,子类继承父类原型上的引用类型,还是存在篡改的可能,只是优化了组成继承中实例创建两次的问题 |
这里你要区分开一个概念,就是函数也是对象,作为函数有prototype,这个可以称为【函数原型】,作为对象有__proto__,这个可以称为【对象原型】,这是两个原型概念,不要混了,Object.setPrototypeOf(x,y),的意思就是设置【对象x】的原型为【y】,正是因为有了这句,才能继承父类的【类方法】,比如Array.isArray(),形如这样的方法,你就要把【Array】理解成是一个对象,这种方法也是我们俗称的【类方法】 |
好像还没改吧,我说怎么看这个图不对劲。。 |
总而言之,最舒服的还是ES6的extends。。。TS也是同样的写法。这东西也是其他高级语言早实现的。JS啊JS。。就这些还经常有面试会问。有什么好问的,服了。 |
醍醐灌顶! 感谢木易杨大佬的文章! |
[TOC]
1、原型链继承
构造函数、原型和实例之间的关系:每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个原型对象的指针。
继承的本质就是复制,即重写原型对象,代之以一个新类型的实例。
原型链方案存在的缺点:多个实例对引用类型的操作会被篡改。
2、借用构造函数继承
使用父类的构造函数来增强子类实例,等同于复制父类的实例给子类(不使用原型)
核心代码是
SuperType.call(this)
,创建子类实例时调用SuperType
构造函数,于是SubType
的每个实例都会将SuperType中的属性复制一份。缺点:
3、组合继承
组合上述两种方法就是组合继承。用原型链实现对原型属性和方法的继承,用借用构造函数技术来实现实例属性的继承。
缺点:
SuperType()
:给SubType.prototype
写入两个属性name,color。SuperType()
:给instance1
写入两个属性name,color。实例对象
instance1
上的两个属性就屏蔽了其原型对象SubType.prototype的两个同名属性。所以,组合模式的缺点就是在使用子类创建实例对象时,其原型中会存在两份相同的属性/方法。4、原型式继承
利用一个空对象作为中介,将某个对象直接赋值给空对象构造函数的原型。
object()对传入其中的对象执行了一次
浅复制
,将构造函数F的原型直接指向传入的对象。缺点:
另外,ES5中存在
Object.create()
的方法,能够代替上面的object方法。5、寄生式继承
核心:在原型式继承的基础上,增强对象,返回构造函数
函数的主要作用是为构造函数新增属性和方法,以增强函数
缺点(同原型式继承):
6、寄生组合式继承
结合借用构造函数传递参数和寄生模式实现继承
这个例子的高效率体现在它只调用了一次
SuperType
构造函数,并且因此避免了在SubType.prototype
上创建不必要的、多余的属性。于此同时,原型链还能保持不变;因此,还能够正常使用instanceof
和isPrototypeOf()
这是最成熟的方法,也是现在库实现的方法
7、混入方式继承多个对象
Object.assign
会把OtherSuperClass
原型上的函数拷贝到MyClass
原型上,使 MyClass 的所有实例都可用 OtherSuperClass 的方法。8、ES6类继承extends
extends
关键字主要用于类声明或者类表达式中,以创建一个类,该类是另一个类的子类。其中constructor
表示构造函数,一个类中只能有一个构造函数,有多个会报出SyntaxError
错误,如果没有显式指定构造方法,则会添加默认的constructor
方法,使用例子如下。extends
继承的核心代码如下,其实现和上述的寄生组合式继承方式一样总结
1、函数声明和类声明的区别
函数声明会提升,类声明不会。首先需要声明你的类,然后访问它,否则像下面的代码会抛出一个ReferenceError。
2、ES5继承和ES6继承的区别
ES5的继承实质上是先创建子类的实例对象,然后再将父类的方法添加到this上(Parent.call(this)).
ES6的继承有所不同,实质上是先创建父类的实例对象this,然后再用子类的构造函数修改this。因为子类没有自己的this对象,所以必须先调用父类的super()方法,否则新建实例报错。
交流
本人Github链接如下,欢迎各位Star
http://github.com/yygmind/blog
我是木易杨,网易高级前端工程师,跟着我每周重点攻克一个前端面试重难点。接下来让我带你走进高级前端的世界,在进阶的路上,共勉!
如果你想加群讨论每期面试知识点,公众号回复[加群]即可
The text was updated successfully, but these errors were encountered: