摘要:北山愚公者年且九十面山而居。工廠模式愚小公北山愚小小公北山工廠模式比較明顯的一個(gè)缺點(diǎn)就是由于生成并返回了一個(gè)中間對(duì)象,所以不能判斷對(duì)象的類型。
??太行、王屋二山,方七百里,高萬(wàn)仞。本在冀州之南,河陽(yáng)之北.......
??嗯,按照慣例,第一句話就是騙你們點(diǎn)進(jìn)來(lái)的。在讀本文之前,希望你對(duì)Javascript的原型和原型鏈有一定了解,這有助于你更好的理解本文,之前有寫過(guò)一篇相關(guān)文章,點(diǎn)此閱讀。但這并不是必須的。
??都退后,我要繼續(xù)講故事了。
??北山愚公者,年且九十,面山而居。
var person = { name : "愚公", age: 90, address: "北山腳下", whereToLive: function () { alert(this.address) } };
??......北山愚公曰:“雖我之死,有子存焉;子又生孫,孫又生子;子又有子,子又有孫;子子孫孫無(wú)窮匱也”。
??看到這兒,問(wèn)題來(lái)了,愚公的子子孫孫那么多,顯然使用對(duì)象字面量去創(chuàng)建是不合理的。我們介紹第一種創(chuàng)建方式。
工廠模式function createPerson (name, age, address){ var o = new Object(); o.name = name; o.age = age; o.address = address; o.whereToLive = function () { alert(this.address) }; return o; } var son = createPerson("愚小公", 30, "北山"); var grandSon = createPerson("愚小小公", 5, "北山");
??工廠模式比較明顯的一個(gè)缺點(diǎn)就是由于生成并返回了一個(gè)中間對(duì)象,所以不能判斷對(duì)象的類型。
構(gòu)造函數(shù)模式function Person(name, age, address) { this.name = name; this.age = age; this.address = address; this.whereToLive = function(){ alert(this.address); }; } var son = new Person("愚小公", 30, "北山"); var grandSon = new Person("愚小小公", 5, "北山");
??構(gòu)造函數(shù)與普通函數(shù)沒有異處,沒有語(yǔ)法上的任何差別,只是在調(diào)用的時(shí)候使用了new關(guān)鍵字。所以我們有必要說(shuō)一下new到底干了什么:
創(chuàng)建一個(gè)新的中間對(duì)象
將構(gòu)造函數(shù)的作用于賦給這個(gè)中間對(duì)象
執(zhí)行構(gòu)造函數(shù)中的代碼
返回中間對(duì)象
??以這里的代碼為例,實(shí)際上第二步和第三步的操作可以總結(jié)為Person.apply(newObject,arguments),這里順便說(shuō)一句bind與call/apply的一個(gè)區(qū)別,bind返回的是一個(gè)函數(shù),call/apply是順帶把這個(gè)函數(shù)給執(zhí)行了,返回的是執(zhí)行后的結(jié)果。
??那么,構(gòu)造函數(shù)模式有什么問(wèn)題呢,其實(shí)也是顯而易見的,如果愚公有一千個(gè)子子孫孫,那么每個(gè)子孫都會(huì)自帶一個(gè)whereToLive的方法,顯然這種做法不文藝范兒
原型模式function Person () { } Person.prototype.name = "愚公"; Person.prototype.age = 90; Person.prototype.address = "北山"; Person.prototype.whereToLive = function () { alert(this.address); }; var son = new Person(); var grandSon = new Person(); son.name = "愚小公"; son.address = "山的那邊"; son.whereToLive(); // "山的那邊" grandSon.whereToLive(); // "北山"
??我們?cè)趕on對(duì)象上試圖修改address屬性,并且似乎看起來(lái)也修改成功了,但是沒有影響到grandSon的屬性。所以其實(shí)這兩個(gè)address其實(shí)并不一樣。為什么呢?我們?cè)谧鋈缦虏僮鳎?/p>
delete son.address; son.whereToLive(); // "北山"
??我們刪掉了son的address屬性,這時(shí)候son的address又成了原型中定義的值。所以我們?cè)谛薷腶ddress屬性的時(shí)候并沒有動(dòng)到原型中的值,而是在這個(gè)對(duì)象上新建了一個(gè)屬性。并且在試圖獲取這個(gè)屬性的時(shí)候會(huì)優(yōu)先返回對(duì)象上的屬性值。我們管這個(gè)現(xiàn)象叫屬性屏蔽。
??另外多提一點(diǎn),就是在讀取對(duì)象屬性的時(shí)候,首先會(huì)查看該對(duì)象本身有沒有,沒有的話會(huì)順著原型鏈一直向上查找,如果達(dá)到原型鏈頂層都沒有找到,則返回undefined。這里再穿插一個(gè)知識(shí)點(diǎn)。很多剛?cè)腴T的開發(fā)者會(huì)犯這樣的錯(cuò)誤:
var a = {}; console.log(a.b.c)
??在沒有校驗(yàn)b屬性是否存在便去試圖獲取c屬性。如果到了原型鏈的頂端都沒有找到b,a.b的值則為undefined,所以獲取undefined的c屬性一定會(huì)報(bào)錯(cuò)。正確的做法是在不確定是否存在對(duì)應(yīng)屬性的時(shí)候,應(yīng)當(dāng)先做判斷。
??但是在寫入基本類型屬性的時(shí)候有所不同,在當(dāng)前對(duì)象沒有找到要寫入的屬性時(shí),不會(huì)向上查找,而是在當(dāng)前對(duì)象里新建一個(gè)屬性,這么做的原因是防止污染其他對(duì)象的屬性值。細(xì)心的你可能發(fā)現(xiàn)了我在開頭的時(shí)候強(qiáng)調(diào)了基本類型屬性。如果是引用類型會(huì)怎么樣呢?
function Person () { } Person.prototype.name = "愚公"; Person.prototype.age = 90; Person.prototype.address = ["北山"]; Person.prototype.whereToLive = function () { alert(this.address); }; var son = new Person(); var grandSon = new Person(); son.address.push("山的那邊"); grandSon.whereToLive(); // "北山","山的那邊"
??這里又有一個(gè)小知識(shí)點(diǎn),引用類型是存在堆內(nèi)存中的,不同地方的應(yīng)用其實(shí)指向的是同一塊堆內(nèi)存。所以如果試圖修改原型對(duì)象中的應(yīng)用類型,會(huì)造成全局污染,這也就是原型模式的一個(gè)致命缺點(diǎn)。
組合使用構(gòu)造函數(shù)模式和原型模式??坐穩(wěn),我又要穿插新的知識(shí)點(diǎn)了。我們可以采用簡(jiǎn)寫的方式避免原型模式賦予原型對(duì)象方法時(shí)啰嗦的問(wèn)題。
function Person(name, age, address) { this.name = name; this.age = age; this.address = address; } Person.prototype = { constructor : Person, // 手動(dòng)修改構(gòu)造函數(shù)指向 whereToLive : function () { alert(this.address); }, howOld : function () { alert(this.age); } }
??組合使用構(gòu)造函數(shù)模式和原型模式的寫法是不是同時(shí)規(guī)避掉了構(gòu)造函數(shù)模式和原型模式的問(wèn)題呢?既可以共享公用的函數(shù),又可以讓每個(gè)對(duì)象獨(dú)享自己的屬性。
??需要注意的是,我們?cè)谥貙?b>Person.prototype的時(shí)候,實(shí)際上使得constructor指向了Object,所以我這里進(jìn)行了手動(dòng)修正。
寄生構(gòu)造函數(shù)模式function PersonList (name, age, address){ var o = new Array(); o.push.apply(o, arguments); o.consoleString = function () { return this.join(","); }; return o; } var list = new PersonList("愚小公", "愚小小公"); alert(list.consoleString());
??是不是很眼熟,跟工廠模式一模一樣,只不過(guò)是在調(diào)用的時(shí)候使用了new關(guān)鍵字。利用這種模式,我們可以為對(duì)象添加額外的能力。本例中,就是給數(shù)組添加一個(gè)自定義的方法,使其可以擁有我們賦予的新能力。
結(jié)語(yǔ)??實(shí)際開發(fā)中還是得根據(jù)實(shí)際場(chǎng)景靈活運(yùn)用,總有適合你的那一款。今天就聊到這,歡迎大家補(bǔ)充和指正。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/107955.html
摘要:它是第一個(gè)把數(shù)據(jù)分布在全球范圍內(nèi)的系統(tǒng),并且支持外部一致性的分布式事務(wù)。目的是使得開發(fā)者閱讀之后,能對(duì)項(xiàng)目有一個(gè)初步了解,更好的參與進(jìn)入的開發(fā)中。深度探索數(shù)據(jù)庫(kù)并發(fā)控制技術(shù)并發(fā)控制技術(shù)是數(shù)據(jù)庫(kù)事務(wù)處理的核心技術(shù)。 存儲(chǔ)過(guò)程高級(jí)篇 講解了一些存儲(chǔ)過(guò)程的高級(jí)特性,包括 cursor、schema、控制語(yǔ)句、事務(wù)等。 數(shù)據(jù)庫(kù)索引與事務(wù)管理 本篇文章為對(duì)數(shù)據(jù)庫(kù)知識(shí)的查缺補(bǔ)漏,從索引,事務(wù)管理,...
摘要:若函數(shù)不能執(zhí)行有效的轉(zhuǎn)換,返回。如果數(shù)值超過(guò)可表示的范圍,則返回或。示例輸入輸出解釋轉(zhuǎn)換截止于數(shù)字,因?yàn)樗南乱粋€(gè)字符不為數(shù)字。 這是我參與11月更文挑戰(zhàn)的第12天。一、寫在前面LeetCode 第一題兩數(shù)之和傳輸門:聽說(shuō)你還在寫雙層for循環(huán)解兩數(shù)之和?LeetCode 第二題兩數(shù)之和傳輸門:兩個(gè)排序數(shù)組的中...
摘要:據(jù)不完全統(tǒng)計(jì),這五年中,白鷺引擎累計(jì)運(yùn)轉(zhuǎn)的游戲和微信小游戲的流水?dāng)?shù)據(jù)約為億。 我們的引擎架構(gòu)師做某一沙龍活動(dòng)的演講速記,純純的干貨,分享給大家。 王澤:各位開發(fā)者下午好!我叫王澤,是白鷺引擎的首席架構(gòu)師。 今天給大家分享的題目是《重度H5游戲性能優(yōu)化技巧》。之所以決定用這個(gè)題目,是因?yàn)槲易罱鼛字茉趶V深一帶拜訪了很多使用白鷺引擎的開發(fā)者,發(fā)現(xiàn)特別是在廣州一帶,大部分開發(fā)者都在做重度H5游...
javascript是一門弱語(yǔ)言,他有著分同一般的靈活性使它迅速的成為幾乎人人必會(huì)的一門語(yǔ)言,but,你們使用的姿勢(shì)真的正確嗎? 在以前的開發(fā)過(guò)程當(dāng)中,老板:給我加個(gè)驗(yàn)證用戶郵箱、驗(yàn)證用戶短信...功能! function checkMessage(){...} function checkEmail(){...} function ... //茫茫多的函數(shù) 這樣寫好了之后 function 是全...
閱讀 659·2021-11-22 14:45
閱讀 3161·2021-10-15 09:41
閱讀 1710·2021-10-11 10:58
閱讀 2862·2021-09-04 16:45
閱讀 2681·2021-09-03 10:45
閱讀 3299·2019-08-30 15:53
閱讀 1273·2019-08-29 12:28
閱讀 2206·2019-08-29 12:14