淺析JavaScript原型繼承的陷阱
JavaScript默認(rèn)采用原型繼承。雖然沒有類(class)的概念,它的函數(shù)(function)可以充當(dāng)構(gòu)造器(constructor)。構(gòu)造器結(jié)合this,new可以構(gòu)建出類似Java的類。因此,JavaScript通過擴(kuò)展自身能模擬類式(class-based)繼承。
JavaScript和其它面向?qū)ο笳Z言一樣,對象類型采用引用方式。持有對象的變量只是一個地址,而基本類型數(shù)據(jù)是值。當(dāng)原型上存儲對象時,就可能有一些陷阱。
先看第一個例子
var create = function() {
function Fn() {}
return function(parent) {
Fn.prototype = parent
return new Fn
}
}()
var parent = {
name: 'jack',
age: 30,
isMarried: false
}
var child = create(parent)
console.log(child)
create工具函數(shù)實(shí)現(xiàn)了一個基本的原型繼承,每次調(diào)用create都會根據(jù)parent對象去復(fù)制一個新對象,新對象全部的屬性都來自于parent。這里parent有三個屬性,都是基本數(shù)據(jù)類型:字符串,數(shù)字,布爾。
這時修改child看看會不會影響parent
child.name = 'lily'
child.age = 20,
child.isMarried = true
console.log(child)
console.log(parent)
結(jié)果如下

即修改child不會影響到parent。
再看看另外一個例子
var create = function() {
function Fn() {}
return function(parent) {
Fn.prototype = parent
return new Fn
}
}()
var parent = {
data: {
name: 'jack',
age: 30,
isMarried: false
},
language: ['Java']
}
var child = create(parent)
child.data.name = 'lily'
child.data.age = 20
child.data.isMarried = true
child.language.push('javascript')
console.dir(child)
console.dir(parent)
注意這里的parent的兩個屬性data,language都是引用類型,一個是對象,一個是數(shù)組。child仍然繼承與parent,隨后修改了child,結(jié)果如下

可以看到,此時parent也被修改了,和child的name,age等都一樣了。這是使用原型繼承時需要注意的。
使用繼承時比較好的方式是:
1,數(shù)據(jù)屬性采用類式繼承(掛在this上),這樣new時也可以通過參數(shù)配置
2,方法采用原型繼承,這樣能節(jié)省內(nèi)存,同時子類重寫方法也不會影響父類
下面是一個滿足以上2點(diǎn)的寫類工具函數(shù)
/**
* @param {String} className
* @param {String/Function} superCls
* @param {Function} factory
*/
function $class(name, superClass, factory) {
if (superClass === '') superClass = Object
function clazz() {
if (typeof this.init === 'function') {
this.init.apply(this, arguments)
}
}
var p = clazz.prototype = new superCls
clazz.prototype.constructor = clazz
clazz.prototype.className = className
var supr = superCls.prototype
window[className] = clazz
factory.call(p, supr)
}
對象類型放在父類原型上時務(wù)必小心子類修改其,這時繼承于該父類的所有子類的實(shí)例都將被修改。而這造成的bug很不容易發(fā)現(xiàn)。
ES5中加入了一個新API用來實(shí)現(xiàn)原型繼承:Object.create??梢杂盟娲厦孀詫?shí)現(xiàn)的create函數(shù),如下
var parent = {
name: 'jack',
age: 30,
isMarried: false
}
var child = Object.create(parent)
console.log(child)
相關(guān)文章
在一個瀏覽器里呈現(xiàn)所有瀏覽器測試結(jié)果的前端測試工具的思路
對前端工程師來說,跨瀏覽器的兼容性問題一直是最頭疼的,測試一個小小的東西,就要打開N個瀏覽器,然后比較來比較去,記錄個瀏覽器的數(shù)據(jù),比較不同,實(shí)在是麻煩.2010-03-03
使用requirejs模塊化開發(fā)多頁面一個入口js的使用方式
這篇文章主要介紹了使用requirejs模塊化開發(fā)多頁面一個入口js的使用方式,需要的朋友可以參考下2017-06-06
返回頁面頂部top按鈕通過錨點(diǎn)實(shí)現(xiàn)(自寫)
用戶在使用系統(tǒng)時,會有很多表單的操作然而很多表單就會很長,所以就需要一個返回頁面頂部的top按鈕啦,于是自己寫了一個,喜歡的朋友可以參考下2013-08-08
javascript隨機(jī)抽取0-100之間不重復(fù)的10個數(shù)
這篇文章主要為大家詳細(xì)介紹了javascript隨機(jī)抽取0-100之間不重復(fù)的10個數(shù),分享了兩種簡單辦法,感興趣的小伙伴們可以參考一下2016-02-02
Javascript中類式繼承和原型式繼承的實(shí)現(xiàn)方法和區(qū)別之處
其它的面向?qū)ο蟪绦蛟O(shè)計語言都是通過關(guān)鍵字來解決繼承的問題。但是javascript中并沒有定義這種實(shí)現(xiàn)的機(jī)制。接下來通過本文給大家介紹Javascript中類式繼承和原型式繼承的實(shí)現(xiàn)方法和區(qū)別,需要的朋友可以參考下2017-04-04

