很多job 的描述都說(shuō)要求精通 javascript 面向?qū)ο缶幊蹋歉鶕?jù)一般的套路蛀恩,寫(xiě)精通其實(shí)就是熟練,寫(xiě)熟練其實(shí)就是一般双谆,寫(xiě)一般其實(shí)就是懵逼!
雖然話(huà)說(shuō)如此顽馋,但是我們還是要熟練使用 javascript 面向?qū)ο缶幊痰模吘惯@是js社會(huì)高能人才的其中一個(gè)標(biāo)準(zhǔn)寸谜,這里我就用一個(gè)鮮活的例子來(lái)說(shuō)明和理解我們應(yīng)該如何使用javascript 面向?qū)ο蟮姆绞絹?lái)編程。
一、野蠻方式構(gòu)建對(duì)象
剛開(kāi)始最初地啰,我們創(chuàng)建對(duì)象的方式是這樣的:
// 。亏吝。。蔚鸥。每次都要寫(xiě)上面的一大段代碼,只是為了創(chuàng)建一個(gè) food
var food = new Object();
food.name = "蘋(píng)果";
food.sayName = function() {
console.log("我是" + this.name);
};
但是這樣創(chuàng)建起來(lái)很麻煩止喷,寫(xiě)的代碼也是很長(zhǎng),如果要?jiǎng)?chuàng)建好多對(duì)象弹谁,例如我制造了10000個(gè)食物,就要寫(xiě)10000次這一大段代碼了预愤,所以后來(lái)聰明的工程師改為了這樣寫(xiě):
// 起碼比之前的少了幾行,也整潔了一些
var food = {
name: "蘋(píng)果",
sayName: function() {
console.log("我是" + this.name);
}
};
起碼代碼少了一些植康,但是還是沒(méi)辦法很好解決我要寫(xiě)100000段代碼的問(wèn)題,所以再后來(lái)的人們就開(kāi)始使用一些高級(jí)玩意來(lái)解決這個(gè)問(wèn)題销睁。
二、使用工廠模式構(gòu)建對(duì)象
通過(guò)抽象出創(chuàng)建具體對(duì)象的過(guò)程存崖,用函數(shù)來(lái)進(jìn)行封裝,換句話(huà)來(lái)說(shuō)来惧,就是抽象了一個(gè) food 的工廠,然后通過(guò)對(duì)這個(gè)工廠傳入不同的材料违寞,來(lái)生成不同的食物。
function createFood(name) {
var o = new Object();
o.name = name;
o.sayName = function() {
console.log("我是" + this.name);
};
return o;
}
var food1 = createFood("蘋(píng)果");
var food2 = createFood("蘋(píng)果");
這里可以看到food1趁曼,food2 就是這樣被制造出來(lái)的,然后只需要少量的代碼(預(yù)先定義好一個(gè)生產(chǎn)工廠函數(shù))挡闰,就可以完成大量的事情掰盘,徹底解決了問(wèn)題赞季,實(shí)現(xiàn)了多快好爽的新局面愧捕。但是用了一段時(shí)間之后申钩,隨之而來(lái)發(fā)現(xiàn)一個(gè)新問(wèn)題次绘,當(dāng)食物多起來(lái)的時(shí)候撒遣,老板貌似不知道哪些食物是屬于那些分類(lèi)的(假設(shè)老板是 zz),那怎么辦呢义黎?
// 都統(tǒng)一返回是[Function: Object],沒(méi)辦法用區(qū)分識(shí)別(賣(mài)個(gè)關(guān)子廉涕,你不用管那個(gè)constructor)
console.log(food1.constructor) // 返回[Function: Object]
console.log(food2.constructor) // 返回[Function: Object]
三、使用構(gòu)造函數(shù)模式來(lái)區(qū)分自己人
經(jīng)過(guò)一番智慧交流之后狐蜕,聰明的人們想出了一個(gè)方法宠纯,使用一個(gè)在對(duì)象里面的 constructor
函數(shù)來(lái)識(shí)別那些不一樣的對(duì)象馏鹤,類(lèi)似使用部門(mén)工牌來(lái)標(biāo)記這個(gè)人是是屬于哪個(gè)部門(mén)的娇哆。
function Food(name) {
this.name = name;
this.sayName = function() {
console.log("我是" + this.name);
};
}
var food1 = new Food("蘋(píng)果");
var food2 = new Food("蘋(píng)果");
// 假設(shè)這里有一個(gè)其他的食物湃累,可能是冒充的
var food3 = new otherFood("蘋(píng)果");
因?yàn)橐獙?shí)現(xiàn)類(lèi)似工牌的方式來(lái)識(shí)別碍讨,所以在創(chuàng)建food的工廠里做一些調(diào)整:
- 沒(méi)有顯式的創(chuàng)建對(duì)象,例如:
var o = new Object();
- 直接將屬性和方法付給了
this
對(duì)象 - 沒(méi)有
return
語(yǔ)句 - 函數(shù)使用了大寫(xiě)字母開(kāi)頭(這里只是為了區(qū)分這個(gè)函數(shù)的特別勃黍,按照慣例,大寫(xiě)字母開(kāi)頭的覆获,一般都是 class 或者構(gòu)造函數(shù))
- 使用了 new 來(lái)創(chuàng)建`Food``對(duì)象
做了以上的改變之后,整個(gè)創(chuàng)建對(duì)象的模式被改變了:
- 首先定義了一個(gè)
Food
的構(gòu)造函數(shù)(其實(shí)就是之前的工廠函數(shù)createFood弄息,但是現(xiàn)在升級(jí)了) - 通過(guò)
new
來(lái)創(chuàng)建一個(gè)對(duì)象(現(xiàn)在的 Food 用 new 來(lái)先創(chuàng)建) - 將構(gòu)造函數(shù)的作用域賦值給新對(duì)象,將
this
指向這個(gè)新對(duì)象(將升級(jí)版的工廠送給這個(gè)用new
創(chuàng)建的 food) - 執(zhí)行構(gòu)造函數(shù)的中的代碼(升級(jí)版的工廠會(huì)自動(dòng)將里面的零件和機(jī)器放到新的 Food 上摹量,相當(dāng)于組裝放在了食物本身 身上)
- 不需要主動(dòng)
return
馒胆,自動(dòng)返回新對(duì)象(升級(jí)版的工廠會(huì)自動(dòng)返回構(gòu)造好的 food 對(duì)象)
通過(guò)這種方式,我們制造出來(lái)的食物都會(huì)有一個(gè) constructor
為 Food 的標(biāo)記來(lái)標(biāo)識(shí)祝迂,如果看到不是的話(huà),那肯定就不是我們制造的型雳。
console.log(food1.constructor) // 返回[Function: Food]
console.log(food2.constructor) // 返回[Function: Food]
console.log(food3.constructor) // 返回[Function: OtherFood]
// 檢驗(yàn)的方式有兩種
console.log(food1.constructor == Food) // 返回 true
console.log(food2.constructor == Food) // 返回 true
console.log(food3.constructor == Food) // 返回 false ,這個(gè)不是我們制造的食物
console.log(food1 instanceof Food) // 返回 true
console.log(food3 instanceof Food) // 返回 false四啰,這個(gè)不是我們制造的食物
可以看到,使用了新技術(shù)(constructor
模式技術(shù))之后柑晒,在沒(méi)有增加工作量的情況下,解決了令人頭痛的問(wèn)題匙赞,簡(jiǎn)直是完美,不過(guò)過(guò)了一段時(shí)間之后涌庭,發(fā)現(xiàn)好像還是有些瑕疵,使用構(gòu)造函數(shù)constructor
模式的時(shí)候欧宜,函數(shù)里面的每個(gè)方法都會(huì)在每個(gè)實(shí)例上重新創(chuàng)建一遍,那么最明顯的地方是:
console.log(food1.sayName == food2.sayName); // 返回 false
因?yàn)槭褂?code>new來(lái)創(chuàng)建實(shí)例席镀,new
的話(huà)還會(huì)把構(gòu)造函數(shù)里面的方法也一起創(chuàng)建,因?yàn)榉椒ㄒ彩呛瘮?shù)夏漱,而函數(shù)的實(shí)例化也會(huì)被new
觸發(fā):
// 省略了其他部分,只關(guān)注方法部分
this.sayName = function() {
console.log("我是" + this.name);
};
this.sayName = new function() {
console.log("我是" + this.name);
}();
這樣就會(huì)造成內(nèi)存和時(shí)間和性能的浪費(fèi)挂绰,明明不需要重新重建新的函數(shù)實(shí)例的。
其實(shí)在之前的工廠模式里面葵蒂,也存在這個(gè)問(wèn)題,不過(guò)工廠模式更徹底践付,直接完全創(chuàng)建一個(gè)新對(duì)象,而構(gòu)造函數(shù)模式的話(huà)只是方法會(huì)被重新創(chuàng)建荔仁。
那怎么解決呢芽死?會(huì)用到原型模式,下回分解关贵。
參考內(nèi)容
- 紅寶書(shū),《javascript 高級(jí)程序設(shè)計(jì)第三版》
版權(quán)信息
作者: 慫如鼠
網(wǎng)站: https://www.whynotbetter.com
本作品著作權(quán)歸作者所有揖曾,商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。