在多個(gè)程序員開(kāi)發(fā)一個(gè)頁(yè)面的時(shí)候,作用域安全的構(gòu)造函數(shù)就很有用了,我們不能保證每個(gè)人寫(xiě)的代碼都那么小心,如果一個(gè)人代碼出錯(cuò),影響到全局屬性,那么這種錯(cuò)誤難以追蹤調(diào)試,這時(shí)候使用作用域安全的構(gòu)造函數(shù)就可以避免此類(lèi)問(wèn)題。
屬性值被掛載到window
JavaScript中構(gòu)造函數(shù)其實(shí)是一個(gè)使用new操作符調(diào)用的函數(shù),在調(diào)用時(shí), 構(gòu)造函數(shù)內(nèi)部用到的this對(duì)象會(huì)指向新創(chuàng)建的對(duì)象
function Person( name, age ){
this.name = name;
this.age = age;
}
var person = new Person( 'Caleb', 20 );
使用new操作符時(shí),會(huì)創(chuàng)建一個(gè)新的Person對(duì)象,并給它分配屬性。正常使用new操作符不會(huì)出現(xiàn)問(wèn)題。問(wèn)題出在疏忽忘記使用new操作符來(lái)調(diào)用構(gòu)造函數(shù)的情況下 - 由于this對(duì)象是在運(yùn)行期綁定的所以直接調(diào)用Person(),this會(huì)映射到全局對(duì)象window上,導(dǎo)致錯(cuò)誤對(duì)象屬性的意外增加。
var person = Person( 'Caleb', 20 );
alert( window.name ); //Caleb
alert( window.age ); //20
這樣原本針對(duì)Person對(duì)象的屬性被添加window對(duì)象,因?yàn)闃?gòu)造函數(shù)沒(méi)有通過(guò)new操作符調(diào)用,而是作為普通函數(shù)被調(diào)用的,由于this的晚綁定而被解析成window對(duì)象。
window的那么屬性是用來(lái)標(biāo)識(shí)鏈接目標(biāo)和框架的,這里對(duì)該屬性的偶然覆蓋可能會(huì)導(dǎo)致頁(yè)面上的其它錯(cuò)誤,這個(gè)問(wèn)題的解決方法就是創(chuàng)建一個(gè)作用域安全的構(gòu)造函數(shù)。
作用域安全的構(gòu)造函數(shù)
作用域安全的構(gòu)造函數(shù)在進(jìn)行屬性賦值之前會(huì)this對(duì)象是否是正確類(lèi)型的實(shí)例,如果不是那么創(chuàng)建新的實(shí)例并返回,改造一下上面的構(gòu)造函數(shù)。
function Person( name, age ){
if(this instanceof Person){
this.name = name;
this.age = age;
}else{
return new Person( name, age );
}
}
var person = Person( 'Caleb', 20 );
alert( window.name ); //""
alert( person.name ); //Caleb
這段代碼中構(gòu)造函數(shù)添加了一個(gè)檢查,確保this對(duì)象是Person的實(shí)例,如果不是則使用new操作符調(diào)用,如果是則在實(shí)例內(nèi)添加屬性。
這樣保證了無(wú)論是否顯示使用new操作符,都可以正確構(gòu)造對(duì)象。貌似完美了,但是仍舊有問(wèn)題。