淺談js中的三種繼承方式及其優(yōu)缺點(diǎn)
第一種,prototype的方式:
//父類 function person(){ this.hair = 'black'; this.eye = 'black'; this.skin = 'yellow'; this.view = function(){ return this.hair + ',' + this.eye + ',' + this.skin; } } //子類 function man(){ this.feature = ['beard','strong']; } man.prototype = new person(); var one = new man(); console.log(one.feature); //['beard','strong'] console.log(one.hair); //black console.log(one.eye); //black console.log(one.skin); //yellow console.log(one.view()); //black,black,yellow
這種方式最為簡單,只需要讓子類的prototype屬性值賦值為被繼承的一個(gè)實(shí)例就行了,之后就可以直接使用被繼承類的方法了。
prototype 屬性是啥意思呢? prototype 即為原型,每一個(gè)對象 ( 由 function 定義出來 ) 都有一個(gè)默認(rèn)的原型屬性,該屬性是個(gè)對象類型。
并且該默認(rèn)屬性用來實(shí)現(xiàn)鏈的向上攀查。意思就是說,如果某個(gè)對象的屬性不存在,那么將通過prototype屬性所屬對象來查找這個(gè)屬性。如果 prototype 查找不到呢?
js會自動地找prototype的prototype屬性所屬對象來查找,這樣就通過prototype一直往上索引攀查,直到查找到了該屬性或者prototype最后為空 (“undefined”);
例如上例中的one.view()方法,js會先在one實(shí)例中查找是否有view()方法,因?yàn)闆]有,所以查找man.prototype屬性,而prototype的值為person的一個(gè)實(shí)例,
該實(shí)例有view()方法,于是調(diào)用成功。
第二種,apply的方式:
//父類 function person(){ this.hair = 'black'; this.eye = 'black'; this.skin = 'yellow'; this.view = function(){ return this.hair + ',' + this.eye + ',' + this.skin; } } //子類 function man(){ // person.apply(this,new Array()); person.apply(this,[]); this.feature = ['beard','strong']; } var one = new man(); console.log(one.feature); //['beard','strong'] console.log(one.hair); //black console.log(one.eye); //black console.log(one.skin); //yellow console.log(one.view()); //black,black,yellow
注意:如果apply參數(shù)為空,即沒有參數(shù)傳遞,則通過 new Array() 、[] 來傳遞,null 無效。
第三種,call+prototype的方式:
//父類 function person(){ this.hair = 'black'; this.eye = 'black'; this.skin = 'yellow'; this.view = function(){ return this.hair + ',' + this.eye + ',' + this.skin; } } //子類 function man(){ // person.apply(this,new Array()); person.call(this,[]); this.feature = ['beard','strong']; } man.prototype = new person(); var one = new man(); console.log(one.feature); //['beard','strong'] console.log(one.hair); //black console.log(one.eye); //black console.log(one.skin); //yellow console.log(one.view()); //black,black,yellow
call方式的實(shí)現(xiàn)機(jī)制卻要多一條 man.prototype = new person(); 為啥呢?
那是因?yàn)閏all方法只實(shí)現(xiàn)了方法的替換而沒有作對象屬性的復(fù)制操作。
google Map API 的繼承就是使用這種方式。
上面總結(jié)了三種繼承方式的實(shí)現(xiàn)。但是每種方法都有其優(yōu)缺點(diǎn)。
假如父類是這樣的:
//父類 function person(hair,eye,skin){ this.hair = hair; this.eye = eye; this.skin = skin; this.view = function(){ return this.hair + ',' + this.eye + ',' + this.skin; } }
子類應(yīng)該如何設(shè)計(jì),使子類man在創(chuàng)建對象的同時(shí)傳遞參數(shù)到父類person,prototype的繼承方式就不適用了,
必須采用apply或者call的方式了:
//apply方式 //子類 function man(hair,eye,skin){ person.apply(this,[hair,eye,skin]); this.feature = ['beard','strong']; } //call方式 //子類 function man(hair,eye,skin){ person.call(this,hair,eye,skin); this.feature = ['beard','strong']; }
但是用apply方法也還是有缺點(diǎn)的,為什么?在js中,我們有個(gè)非常重要的運(yùn)算符就是”instanceof”,該運(yùn)算符用來比較某個(gè)對向是否為某種類型。
對于這個(gè)例子,one實(shí)例除了是man類型,也應(yīng)該是person類型,但是apply方式繼承之后,one卻不屬于person類型,即(one instanceof person)的值為false。
經(jīng)此種種,最好的繼承方式就是call+prototype方式了,之后你可以試一下(one instanceof BaseClass)的值是否為true。
第三種繼承方式也有缺陷:子類new對象時(shí)要傳一遍父類所需的參數(shù),而且會重現(xiàn)父類中的屬性和方法,下面這種繼承方式才是完善的:
function Person(name){ this.name = name; } Person.prototype.getName = function() { return this.name; } function Chinese(name, nation) { Person.call(this, name); this.nation = nation; } //繼承方法 function inherit(subClass, superClass) { function F() {} F.prototype = superClass.prototype; subClass.prototype = new F(); subClass.prototype.constructor = subClass.constructor; } inherit(Chinese, Person); Chinese.prototype.getNation = function() { return this.nation; }; var p = new Person('shijun'); var c = new Chinese("liyatang", "China"); console.log(p); // Person {name: "shijun", getName: function} console.log(c); // Chinese {name: "liyatang", nation: "China", constructor: function, getNation: function, getName: function} console.log(p.constructor); // function Person(name){} console.log(c.constructor); // function Chinese(){} console.log(c instanceof Chinese); // true console.log(c instanceof Person); // true
以上這篇淺談js中的三種繼承方式及其優(yōu)缺點(diǎn)就是小編分享給大家的全部內(nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
TypeScript中d.ts類型聲明文件的實(shí)現(xiàn)
.d.ts 文件是 TypeScript 的類型聲明文件,它們的主要作用是為 JavaScript 庫提供類型支持,本文主要介紹了TypeScript中d.ts類型聲明文件的實(shí)現(xiàn),感興趣的可以了解一下2023-10-10TypeScript中type和interface的區(qū)別及注意事項(xiàng)
type的類型別用可以用戶其他的類型,比如聯(lián)合類型、元祖類型、基本類型,interface不行,下面這篇文章主要給大家介紹了關(guān)于TypeScript中type和interface的區(qū)別及注意事項(xiàng)的相關(guān)資料,需要的朋友可以參考下2022-10-10JavaScript ES6中export、import與export default的用法和區(qū)別
這篇文章主要給大家介紹了JavaScript ES6中export、import與export default的用法和區(qū)別,文中介紹的非常詳細(xì),相信對大家學(xué)習(xí)ES6會有一定的幫助,需要的朋友可以參考借鑒,下面來一起看看吧。2017-03-03zepto.js中tap事件阻止冒泡的實(shí)現(xiàn)方法
這篇文章主要介紹了zepto.js中tap事件阻止冒泡的實(shí)現(xiàn)方法,實(shí)例分析了由冒泡產(chǎn)生的click延遲解決方法,需要的朋友可以參考下2015-02-02innertext , insertadjacentelement , insertadjacenthtml , ins
innertext , insertadjacentelement , insertadjacenthtml , insertadjacenttext 等區(qū)別...2007-06-06