JavaScript的封装和继承
Posted lijianming180
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaScript的封装和继承相关的知识,希望对你有一定的参考价值。
提到javascript“面向对象编程”,主要就是封装和继承,这里主要依据阮一峰及其他博客的系列文章做个总结。
继承机制的设计思想
所有实例对象需要共享的属性和方法,都放在这个对象里面;那些不需要共享的属性和方法,就放在构造函数里面。
由于所有的实例对象共享同一个
prototype
对象,那么从外界看起来,prototype
对象就好像是实例对象的原型,而实例对象则好像”继承”了prototype
对象一样。
封装
主要介绍了如何”封装”数据和方法,以及如何从原型对象生成实例。
(1) 封装:把属性和方法封装成一个对象。
(2)如何根据某一规格(原型)生成对象:构造函数。相较于原始方法(用字面量一个一个手动生成对象),其优点在于:
减少代码重复,将对象普遍具有的属性先用构造函数定义好,使用构造函数生成对象时传参即可为产生的对象的属性赋值;
体现生成的对象与原型对象之间的联系。
构造函数具有的
prototype
属性的优点:将所有对象具有的值相同的属性,挂在prototype
上,无论生成多少个对象,它们都共用这一份prototype
,在内存中只有一份,减少不必要的资源浪费。isPrototypeOf
,hasOwnProperty()
检测是本地属性还是原型属性,in
遍历对象的所有属性,包括原型属性。
【注意】:构造函数中的属性是本地属性,每个对象都维护各自的值,prototype
中的属性是引用属性,所有对象共有一份。原型属性与实例属性同名时,原型属性会被实例属性覆盖
构造函数的继承 (五种方法)
方法一:构造函数绑定
在子对象构造函数Cat()
中加一行:
|
|
优点:可以实现多继承(call/apply
多个对象);并且,创建子类实例时,可以向父类传递参数。
缺点:只能继承父类的实例属性和方法,不能继承父类的原型属性/方法。(这里引申出【组合继承】:在本方法基础上,加上方法二的原型继承,即call
+prototype
方法,组合继承既可以继承原型属性/方法,又可以继承实例属性/方法,而且还可传参)。
方法二:prototype
模式(又称原型链继承,注意需要对constructor
修正)
将父类的实例作为子类的原型:如果”猫”的prototype对象,指向一个Animal的实例,那么所有”猫”的实例,就能继承Animal了。
|
|
【注意】:
任何一个
prototype
对象(cat.prototype
)都有一个constructor
属性,指向它的构造函数。更重要的是,每一个实例(
cat1
)也有一个constructor
属性,默认调用prototype
对象的constructor
属性。
=>
【普适性的规则】:如果替换了prototype
对象,下一步必然是为新的prototype
对象加上constructor
属性,并将这个属性指回原来的构造函数:
|
|
缺点:无法实现多继承;创建子类实例时,无法向父类构造函数传参。
方法三:直接继承prototype
优点是 效率比较高(不用执行和建立Animal
的实例了),比较省内存。
缺点是 Cat.prototype
和Animal.prototype
现在指向了同一个对象,那么任何对Cat.prototype
的修改,都会反映到Animal.prototype
。
|
|
方法四:利用空对象作为中介 (又称寄生组合继承,对方法三的改良):完美
|
|
方法五:拷贝继承:把Parent.prototype
的所有属性和方法,拷贝进Child.prototype
|
|
拷贝继承支持多继承。
非构造函数的继承
继承某个具体的对象。
方法一:object()
(实质上还是原型继承)
|
|
方法二:浅拷贝(只能拷贝数据全是基本类型的对象)
存在问题:如果父对象的属性等于数组或另一个对象,那么实际上,子对象获得的只是一个内存地址,而不是真正拷贝,因此存在父对象被篡改的可能。
方法三:深拷贝
递归调用浅拷贝
|
|
优点:支持多继承。
缺点:效率较低,内存占用高(因为要拷贝父类的属性);无法获取父类不可枚举的方法(不可枚举方法,不能使用for in 访问到)。
以上是关于JavaScript的封装和继承的主要内容,如果未能解决你的问题,请参考以下文章