摘要:用對象字面量形式創建的對象,直接賦值給函數的原型對象,本質上完全重寫了其對象,因此屬性也就變成了新對象的屬性指向構造函數,不再指向函數。
【上一篇】:JavaScript對象內部屬性及其特性總結
工廠模式(★★)先在內部顯示地創建一個臨時對象,根據接收的參數來構建(賦值屬性和方法)該對象,并返回該對象。
缺點:沒有解決對象識別的問題(即無法確認一個對象的類型)。
function PersonFactory (name, age){ var o = new Object(); o.name = name; o.age = age; o.sayName = function(){ console.log(this.name) } return o; } var p1 = PersonFactory(); var p2 = PersonFactory(); p1 instanceof Object; // true p2 instanceof Object; // true p1 instanceof PersonFactory; // false 無法識別具體對象類型 p2 instanceof PersonFactory; // false構造函數模式(★★★)
調用構造函數實際經歷4個步驟函數名首字母一般大寫(如:Person,借鑒OO語言命名習慣)區別于其他函數;
構造函數本身也是函數,只不過可以用來參加對象而已;
每個新建的實例對象都有一個constructor屬性,該屬性指向構造函數自身Person;
構造函數也可以被當做普通函數來調用;
在全局作用域中調用一個函數時,this對象總是指向Global對象(瀏覽器中即window對象)
【優點】自定義構造函數可以將它的實例標識為一種特定的類型;
【缺點】構造函數的主要問題是,每個方法都要在每個實例上重新創建一遍;
與工廠模式比較創建(隱式地)一個新對象;
將構造函數的新對象賦值給新對象(此時this指向這個新對象);
執行構造函數中的代碼(為這個新對象添加屬性);
返回新對象(該構造函數的實例);
沒有顯示地創建對象;
直接將屬性和方法賦值給this對象;
沒有return語句;
優點:可以確認具體對象類型;
function Person (name, age){ this.name = name; this.age = age; this.sayName = function(){ console.log(this.name); } } // 當做普通函數 var p1 = new Person("Tom", 20); var p2 = new Person("Greg", 30); p1 instanceof Object; // true p2 instanceof Object; // true p1 instanceof PersonFactory; // true 可以確認具體對象類型 p2 instanceof PersonFactory; // true // 作為普通函數調用 Person("Green", 30); // 屬性和方法都被添加到window對象了 window.sayName(); // "Green" // 在另一個對象的作用域中調用 var obj = new Object(); Person.call(obj , "Jim", 23); obj .sayName(); // "Jim"原型模式(★★★)
與構造函數模式比較構造函數變為空函數;
將所有屬性和方法都添加到了構造函數的prototype屬性中;
不同:新對象的屬性和方法由所有實例共享(p1和p2訪問的都是同一組屬性和同一個函數);
function Person(){} Person.prototype.name = "Tom"; Person.prototype.age = 24; Person.prototype.sayName = function(){ console.log(this.name); } var p1 = new Person(), p2 = new Person(); p1.sayName();// "Tom" p2.sayName();// "Tom" console.log(p1.sayName === p2.sayName);// true利用更簡單的原型語法
每創建一個函數,就會同時創建它的prototype對象,該prototype對象也會自動獲得constructor屬性。
用對象字面量形式創建的對象,直接賦值給函數的原型對象(Person.prototype),本質上完全重寫了其prototype對象,
因此constructor屬性也就變成了新對象的constructor屬性(指向Object構造函數),不再指向Person函數。
此時instanceof操作符可以返回正確結果,但通過constructor已經無法確定對象類型了。
function Person(){} Person.prototype = { // construtor : Person, // 需要重新指設constructor屬性 name : "Tom", age : 24, sayName : function(){ console.log(this.name); } } var p = new Person(); console.log(p instanceof Object); // ture console.log(p instanceof Person); // ture console.log(p.construtor == Object); // ture console.log(p.construtor == Person); // false安全地重設constructor
以上述方式重設constructor屬性會導致它的[[Enumerable]]特性被設置為true;
默認情況下,原生的constructor屬性是不可枚舉的;
因此可利用Object.defineProperty()重設;
Object.defineProperty(Person.prototype, "constructor", { enumerable : false, value : Person });組合模式(構造函數模式和原型模式)(★★★★)
定義
組合使用構造函數模式和原型模式;
構造函數模式用于定義實例屬性,原型模式用于定義方法和共享的屬性;
優點:
每個實例都會有自己的一份實例屬性的副本,同時又共享著對方方法的引用,最大限度節省了內存;
這種混成模式支持向構造函數傳遞參數;
目前使用最廣泛、認同度最高的一種自定義類型的方法,可以說是用來定義引用類型的一種默認模式;
// 實例屬性均在構造函數中定義 function Person(name, age){ this.name = name; this.age = age; this.friends = ["Nicholas", "Jim"]; } // 由所有實例共享屬性constructor和方法則是在原型中定義的 Person.prototype = { construtor: Person, sayName: function(){ console.log(this.name); } } var p1 = new Person("Tom", 25); var p2 = new Person("Greg", 26); p1.friends.push("Tony"); console.log(p1.friends); // ["Nicholas", "Jim", "Tony"] console.log(p2.friends); // ["Nicholas", "Jim"] console.log(p1.friends === p2.friends); // false console.log(p1.sayName === p2.sayName); // true動態原型模式(★★★★★)
注意點:
定義:
動態原型模式把所有信息都封裝在了構造函數中;
通過在構造函數中初始化原型(僅在必要的情況下,比如第一次新建實例時);
通過檢查某個應該存在(原型中)的方法是否有效,來決定是否需要初始化原型;
優點:保持了同時使用構造函數和原型的特點;
下段代碼中只會在初次調用構造函數時才會執行,此后原型已經完成初始化,無需再做修改;
這里對原型所做對修改,能夠立即在所有實例中得到反映;
if語句檢查的可以是初始化之后應該存在的任何屬性或方法,檢查其中一個即可;
function Person(name, age){ // 屬性 this.name = name; this.age = age; // 方法 if(typeof this.sayName != "function"){ Person.prototype.sayName = function(){ console.log(this.name); } } }寄生構造函數模式(★★)
與工廠模式的比較【定義】: 基本思想是創建一個函數,該函數的作用僅僅是封裝創建對象的代碼,然后再返回新創建的對象。
【特點】:
返回的對象與構造函數或者與構造函數的原型屬性之間沒有關系;
寄生構造函數返回的對象與在寄生構造函數外部創建的對象沒有什么不同;
不能依賴instanceof操作符來確定對象類型;
與構造函數模式的比較除了使用new操作符并把使用的包裝函數叫做構造函數之外,該模式和工廠模式其實是一模一樣的;
從表面上看,很像典型的構造函數;
構造函數在不返回值的情況下,默認會返回新對象實例;
而寄生構造函數通過在構造函數的末尾加一個return語句,重寫了調用構造函數時返回的值;
此時返回的對象的__proto__屬性指向Object;
function Person(name, age){ // 創建臨時新對象 var o = new Object(); // 初始化該對象 o.name = name; o.age = age; o.sayName = function(){ console.log(this.name); } // 返回該臨時新對象 return o; } var p1 = new Person("Tom", 25); var p2 = new Person("Greg",30); console.log(p1 instanceof Object); // true console.log(p1 instanceof Person); // false console.log(p1.sayName == p2.sayName); // false console.log(p1.constructor == Object); //true穩妥構造函數模式(★★)
所謂穩妥對象,就是指沒有公共屬性,而且其方法也不引用this的對象。與寄生構造函數模式的比較
穩妥對象最適合在一些安全的環境中(這些環境會禁用this和new),或者防止數據被其他應用程序改動時調用。
與寄生構造函數類似,但又不同:
一是新創建的對象實例方法不引用this;
二是不使用new操作符調用構造函數;
function Person (name, age){ var o = new Object(); // 可定義私有變量和函數 // ... // 新創建的對象實例方法未引用this; o.sayName = function(){ console.log(name) } return o; } var p = Person("Tom", 23); p.sayName(); // "Tom" console.log(p instanceof Person); // false
除了sayName()方法外,沒有別的方法可以訪問其數據成員;
即使有其他代碼給這個對象添加方法或數據成員,也不可能有別的辦法訪問傳入到構造函數中的原始數據;
與寄生構造函數模式類似,使用穩妥構造函數模式創建的對象與構造函數之間也沒有關系(故instanceof操作符對這種對象也無意義);
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/99379.html
摘要:函數類型檢測是的子類型,其屬性為參數個數,但是判斷結果有內建函數原生函數常見的有,可能被當作構造函數來使用,創建出來的是封裝了的基本類型值。構造函數可以不帶關鍵字。建議使用和來進行顯示強制轉換。 前言 此篇小結來源與《你不知道的JavaScript》和《JavaScript高級程序設計》的結合??或許是的,龜速總結中... 七種內置類型 null undefined boolean ...
摘要:前言一直混跡社區突然發現自己收藏了不少好文但是管理起來有點混亂所以將前端主流技術做了一個書簽整理不求最多最全但求最實用。 前言 一直混跡社區,突然發現自己收藏了不少好文但是管理起來有點混亂; 所以將前端主流技術做了一個書簽整理,不求最多最全,但求最實用。 書簽源碼 書簽導入瀏覽器效果截圖showImg(https://segmentfault.com/img/bVbg41b?w=107...
摘要:繼承的是超類型中構造函數中的屬性,如上繼承了屬性,但沒有繼承原型中的方法。上述造成的結果是子類型實例中有兩組超類型的構造函數中定義的屬性,一組在子類型的實例中,一組在子類型實例的原型中。 ECMAScript只支持實現繼承,主要依靠原型鏈來實現。與實現繼承對應的是接口繼承,由于script中函數沒有簽名,所以無法實現接口繼承。 一、原型鏈 基本思想:利用原型讓一個引用類型繼承另一個引用...
摘要:創建對象中,創建對象的基本模式有三種。因此,在設計構造函數時,需要進行慎重考慮。因此在中,這種問題被稱作繼承破壞封裝。靜態成員每個只有一份,直接通過類對象進行訪問。 什么是封裝 找工作時一些公司給了offer后我就想知道真正拿到手的是多少,畢竟賦稅繁重。但各種稅也好,五險一金也好我實在是弄不清楚,于是我就會在網上的一些稅后收入計算器上進行計算,只需要填寫一些基本信息,比如稅前收入,所...
閱讀 1865·2023-04-26 01:58
閱讀 1991·2019-08-30 11:26
閱讀 2735·2019-08-29 12:51
閱讀 3501·2019-08-29 11:11
閱讀 1190·2019-08-26 11:54
閱讀 2104·2019-08-26 11:48
閱讀 3486·2019-08-26 10:23
閱讀 2391·2019-08-23 18:30