摘要:模式工廠模式構造器模式通過對象實現模式構造器與原型方式的混合模式動態原型模式混合工廠模式模式字面量的表現形式等價于即以對象為一個原型模板新建一個以這個原型模板為原型的對象區別創建一個原型為的對象在里查看各個新建對象的區別可以看出前種模式創建
Objct 模式
工廠模式
構造器模式
通過 Function 對象實現
prototype 模式
構造器與原型方式的混合模式
動態原型模式
混合工廠模式
1.Object 模式var o1 = {};//字面量的表現形式 var o2 = new Object; var o3 = new Object(); var o4 = new Object(null); var o5 = new Object(undefined); var o6 = Object.create(Object.prototype);//等價于 var o = {};//即以 Object.prototype 對象為一個原型模板,新建一個以這個原型模板為原型的對象 //區別 var o7 = Object.create(null);//創建一個原型為 null 的對象
在 chrome 里查看各個新建對象的區別:
可以看出前6種模式創建出來的對象都是一樣的,第七種不同點在于其雖然也為 Object 對象但其無任何屬性(包括沒有任何可以繼承的屬性,因為創建的時候沒有指定其原型)
2.工廠模式//工廠方法1 通過一個方法來創建對象 利用 arguments 對象獲取參數設置屬性(參數不直觀,容易出現問題) function createCar(){ var oTemp = new Object(); oTemp.name = arguments[0];//直接給對象添加屬性,每個對象都有直接的屬性 oTemp.age = arguments[1]; oTemp.showName = function () { alert(this.name); };//每個對象都有一個 showName 方法版本 return oTemp; } createCar("tom").showName();//在 JS 中沒有傳遞的實參,實際形參值為 undefined(這里的 age 為 undefined) createCar("tim",80).showName(); alert(createCar("tom") instanceof Object);//true 判斷對象是否 Object 類或子類
//工廠方法2 通過傳參設置屬性(參數直觀明了) function createCar(name,age){ var oTemp = new Object(); oTemp.name = name;//直接給對象添加屬性,每個對象都有直接的屬性 oTemp.age = age; oTemp.showName = function () { alert(this.name); };//每個對象都有一個 showName 方法版本 return oTemp; } createCar("tom").showName(); createCar("tim",80).showName(); alert(createCar("tom") instanceof Object);//true 判斷對象是否 Object 類或子類3.構造器模式
//構造器方法1 function Car(sColor,iDoors){ //聲明為構造器時需要將函數名首字母大寫 this.color = sColor; //構造器內直接聲明屬性 this.doors = iDoors; this.showColor = function(){ return this.color; };//每個 Car 對象都有自己的 showColor方法版本 this.showDoor = function () { return this.doors; } }
使用方法1的問題很明顯,沒辦法是 showDoor 方法重用,每次新建一個對象就要在堆里新開辟一篇空間.改進如下
//構造器方法2 function showDoor(){ //定義一個全局的 Function 對象 return this.doors; } function Car(sColor,iDoors){//構造器 this.color = sColor; //構造器內直接聲明屬性 this.doors = iDoors; this.showColor = function(){ return this.color; }; this.showDoor = showDoor();//每個 Car 對象共享同一個 showDoor 方法版本(方法有自己的作用域,不用擔心變量被共享) } alert(new Car("red",2).showColor());//通過構造器創建一個對象并調用其對象方法
上面出現的問題就是語義不夠清除,體現不出類的封裝性,改進為 prototype 模式
4.通過Function對象實現創建對象我們知道每聲明一個函數實際是創建了一個Function 實例 JS 函數.
function function_name(param1,param2){alert(param1);} //等價于 var function_name = new Function("param1","pram2","alert(param1);");
var Car2 = new Function("sColor","iDoors", "this.color = sColor;"+ "this.doors = iDoors;"+ "this.showColor = function(){ return this.color; }" ); alert(new Car2("blue",3).showColor());5.prototype模式
類通過 prototype 屬性添加的屬性與方法都是綁定在這個類的 prototype 域(實際為一個 Prototype 對象)中,綁定到這個域中的屬性與方法只有一個版本,只會創建一次.
類的實例對象可以直接像調用自己的屬性一樣調用該類的 prototype 域中的屬性與方法,類可以通過調用 prototype 屬性來間接調用prototype 域內的屬性與方法.
注意:通過類實例化出對象后對象內無 prototype 屬性,但對象可直接像訪問屬性一樣的訪問類的 prototype 域的內容,實例對象有個私有屬性__proto__,__proto__屬性內含有類的 prototype 域內的屬性與方法
方法1 function Car3(){}//用空構造函數設置類名 Car3.prototype.color = "blue";//每個對象都共享相同屬性 Car3.prototype.doors = 3; Car3.prototype.drivers = new Array("Mike","John"); Car3.prototype.showColor = function(){ alert(this.color); };//每個對象共享一個方法版本,省內存。 var car3_1 = new Car3(); var car3_2 = new Car3(); alert(car3_1.color);//blue alert(car3_2.color);//blue alert(Car3.prototype.color);//blue car3_1.drivers.push("Bill"); alert(car3_1.drivers);//"Mike","John","Bill" alert(car3_2.drivers);//"Mike","John","Bill" alert(Car3.prototype.drivers);//"Mike","John","Bill" //直接修改實例對象的屬性,解析器會先去找實例對象是否有這個屬性(不會去找實例對象的 _proto_ 屬性內的那些類的 prototype 屬性,而是直接查看這個實例是否有對應的屬性(與_proto_同級)) //如果沒有則直接給這個實例對象添加該屬性,但不會修改類的prototype域的同名屬性,既實例對象的_proto_屬性內的那些類 prototype 域屬性不會被修改 car3_1.color = "red";//car3_1對象內無名為 color 的對象屬性,故將該屬性添加到該對象上 //解析器對實例對象讀取屬性值的時候會先查找該實例有無同名的直接屬性 //如果沒有,則查找__proto__屬性內保存的那些 當前類的 prototype 域的屬性 //有就返回,無則繼續查找是否有原型鏈中的對應的方法屬性 //有就返回,無則返回undefined alert(car3_1.color);//red alert(car3_2.color);//blue alert(car3_2.color2);//undefined //直接修改類的 prototype 域內的屬性,不會影響該類的實例對象的對象屬性,但會影響實例對象的_proto_屬性(_proto_屬性內存放的是類的 prototype 域的內容) Car3.prototype.color = "black"; alert(car3_1.color);//red 該對象有同名的直接屬性,故不會去_proto_屬性內查找類的 prototype 域的屬性 alert(car3_2.color);//black 受影響 //直接修改實例對象的方法,解析器會先去找實例對象是否有這個方法(不會去找實例對象的 _proto_ 屬性內的那些類的 prototype 域的方法,而是直接查看這個實例是否有對應的方法(與_proto_同級)) //如果沒有則直接給這個實例對象添加該方法,但不會修改類的prototype域的同名方法,既實例對象的_proto_屬性內的那些類 prototype 域方法不會被修改 //car3_1對象內無名為 showColor 的對象方法屬性,故將該方法屬性添加到該對象上 car3_1.showColor = function () { alert("new function"); } //解析器對實例對象調用方法屬性的時候會先查找該實例有無同名的直接方法屬性 //如果沒有,則查找_proto_屬性內保存的那些 當前類的 prototype 域的方法屬性 //有就返回,無則繼續查找是否有原型鏈中的對應的方法屬性 //找到就返回,無則報錯 car3_1.showColor();//new function car3_2.showColor();//blue car3_1.abcd();//直接報錯 //直接修改類的 prototype 域內的方法屬性,不會影響該類的實例對象的方法屬性,但會影響實例對象的_proto_屬性(_proto_屬性內存放的是類的 prototype 域的內容) Car3.prototype.showColor = function () { alert("second function"); } car3_1.showColor();//new function 該對象有同名的方法屬性,故不會去_proto_屬性內查找類的 prototype 域的方法屬性 car3_2.showColor();//second function 受影響
可以看出使用該方法雖然說打打減少了內存的浪費,但依舊有問題,某個對象的屬性一旦改變,所有由該類實例化得到的對象的__proto__內屬性值也會跟著變(實為引用),改進如下
6.構造器方式與原型方式的混合模式//每個對象有專屬的屬性不會與其他對象共享 function Car4(sColor,iDoors){ this._color = sColor;//私有屬性變量名稱頭加下劃線標識 this._doors = iDoors; this.drivers = new Array("Mike","John");//公有屬性標識 } //所有對象共享一個方法版本,減少內存浪費 Car4.prototype.showColor = function () { alert(this._color); }; var car4_1 = new Car4("red",4); var car4_2 = new Car4("blue",3); car4_1.drivers.push("Bill"); alert(car4_1.drivers);//"Mike","John","Bill" alert(car4_2.drivers);//"Mike","John"
這也是常用的創建對象方式之一
7.動態原型模式function Car5(sColor,iDoors,iMpg){ this.color = sColor; this.doors = iDoors; this.mpg = iMpg; this.drivers = new Array("Mike","John"); //使用標志(_initialized)來判斷是否已給原型賦予了任何方法,保證方法永遠只被創建并賦值一次 if(typeof Car5._initialized == "undefined"){//因為這里的標記是附加在類上,故如果后期直接對其進行修改,還是有可能出現再次創建的情況 Car5.prototype.showColor = function () {//為Car5添加一個存放在 prototype 域的方法 alert(this.color); }; Car5._initialized = true;//設置一個靜態屬性 } } var car5_1 = new Car5("red",3,25); var car5_2 = new Car5("red",3,25);
這種模式使得定義類像強類型語言例如 java 等語言的定義模式
8.混合工廠模式function Car6(){ var oTempCar = new Object; oTempCar.color = "blue"; oTempCar.doors = 4; oTempCar.showColor = function () { alert(this.color); }; return oTempCar; } var car6 = new Car6();
由于在 Car6()構造函數內部調用了 new 運算符,所以將忽略第二個 new 運算符(位于構造函數之外),
在構造函數內部創建的對象被傳遞回變量car6,這種方式在對象方法的內部管理方面與經典方式(工廠方法)有著相同的問題.應盡量避免
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/86064.html
摘要:在可讀流事件里我們就必須調用方法。當一個對象就意味著我們想發出信號這個流沒有更多數據了自定義可寫流為了實現可寫流,我們需要使用流模塊中的構造函數。我們只需給構造函數傳遞一些選項并創建一個對象。 前言 什么是流呢?看字面意思,我們可能會想起生活中的水流,電流。但是流不是水也不是電,它只是描述水和電的流動;所以說流是抽象的。在node.js中流是一個抽象接口,它不關心文件內容,只關注是否從...
摘要:聲明的變量不得改變值,這意味著,一旦聲明變量,就必須立即初始化,不能留到以后賦值。 雖然今年沒有換工作的打算 但為了跟上時代的腳步 還是忍不住整理了一份最新前端知識點 知識點匯總 1.HTML HTML5新特性,語義化瀏覽器的標準模式和怪異模式xhtml和html的區別使用data-的好處meta標簽canvasHTML廢棄的標簽IE6 bug,和一些定位寫法css js放置位置和原因...
摘要:聲明的變量不得改變值,這意味著,一旦聲明變量,就必須立即初始化,不能留到以后賦值。 雖然今年沒有換工作的打算 但為了跟上時代的腳步 還是忍不住整理了一份最新前端知識點 知識點匯總 1.HTML HTML5新特性,語義化瀏覽器的標準模式和怪異模式xhtml和html的區別使用data-的好處meta標簽canvasHTML廢棄的標簽IE6 bug,和一些定位寫法css js放置位置和原因...
摘要:聲明的變量不得改變值,這意味著,一旦聲明變量,就必須立即初始化,不能留到以后賦值。 雖然今年沒有換工作的打算 但為了跟上時代的腳步 還是忍不住整理了一份最新前端知識點 知識點匯總 1.HTML HTML5新特性,語義化瀏覽器的標準模式和怪異模式xhtml和html的區別使用data-的好處meta標簽canvasHTML廢棄的標簽IE6 bug,和一些定位寫法css js放置位置和原因...
摘要:我們通過這個構造函數為原型對象添加其他方法和屬性。這個屬性存在與實例與構造函數的原型對象上直接,而不存在于實例與構造函數之間。李小花班花張全蛋張全蛋李小花李小花我們在遍歷對象的的屬性的時候,經常需要判斷屬性是否來自于對象的原型還是屬性。 引言 上面說了創建對象有字面量方式和工廠模式還有構造函數模式,結果發現他們都各自有缺點,所以下面再給大家介紹幾種創建對象的方式,爭取能找到一種無痛的模...
閱讀 2501·2021-11-25 09:43
閱讀 2611·2021-11-16 11:50
閱讀 3294·2021-10-09 09:44
閱讀 3203·2021-09-26 09:55
閱讀 2844·2019-08-30 13:50
閱讀 1032·2019-08-29 13:24
閱讀 2081·2019-08-26 11:44
閱讀 2805·2019-08-26 11:37