摘要:如果構造函數有返回值呢一般情況下構造函數沒有返回值,但是我們依舊可以得到該對象的實例如果構造函數有返回值,憑直覺來說情況應該會不一樣。歡迎光臨小弟博客我的博客原文你真的弄明白了嗎參考再談面向對象編程的實例化與繼承請停止使用關鍵字
好久沒有寫點東西了,總覺得自己應該寫點牛逼的,卻又不知道如何下筆。既然如此,還是回歸最基本的吧,今天就來說一說這個new。關于javascript的new關鍵字的內容上網搜一搜還真不少,大家都說new干了3件事:
創建一個空對象
將空對象的__proto__指向構造函數的prototype
使用空對象作為上下文調用構造函數
文字比較難懂,翻譯成javascript:
javascriptfunction Base() { this.str = "aa"; } // new Base()干了下面的事 var obj = {}; obj.__proto__ = Base.prototype; Base.call(obj);
想想是這么回事哈,那就趕快試試:
javascriptvar b = new Base(); console.dir(b); // Base {str: "aa", __proto__: Base}
好像是正確的,但是真的正確嗎???
真的就3件事?每個對象都有一個constructor屬性,那么我們來試試看new出來的實例的constructor是什么吧。
javascriptconsole.dir(b.constructor); // [Function: Base]
可以看出實例b的constructor屬性就是Base,那么我們可以猜測new是不是至少還做了第4件事:
javascriptb.constructor = Base;
以上結果看似正確,下面我們進行一點修改,這里我們修改掉原型的constructor屬性:
javascriptBase.prototype.constructor = function Other(){ }; var b = new Base(); console.dir(b.constructor); // [Function: Other]
情況就不一樣了,可以看出,之前的猜測是錯誤的,第4件事應該是這樣的:
javascriptb.constructor = Base.prototype.constructor;
這里犯了一個錯誤,那就是沒有理解好這個constructor的實質:當我們創建一個函數時,會自動生成對應的原型,這個原型包含一個constructor屬性,使用new構造的實例,可以通過原型鏈查找到constructor。如下圖所示:
這里非常感謝zonxin同學指出我的錯誤。
如果構造函數有返回值呢?一般情況下構造函數沒有返回值,但是我們依舊可以得到該對象的實例;如果構造函數有返回值,憑直覺來說情況應該會不一樣。我們對于之前的構造函數進行一點點修改:
javascriptfunction Base() { this.str = "aa"; return 1; // return "a"; // return true; } var b = new Base(); console.dir(b); // { str: "aa"}
我們在構造函數里設置的返回值好像沒什么用,返回的還是原來對象的實例,換一些例子試試:
javascriptfunction Base() { this.str = "aa"; return [1]; // return {a:1}; } var b = new Base(); console.dir(b); // [1] or {a: 1}
此時結果就不一樣了,從上面的例子可以看出,如果構造函數返回的是原始值,那么這個返回值會被忽略,如果返回的是對象,就會覆蓋構造的實例。
new至少做了4件事總結一下,new至少做了4件事:
javascript// new Base(); // 1.創建一個空對象 obj var obj = {}; // 2.設置obj的__proto__為原型 obj.__proto__ = Base.prototype; // 3.使用obj作為上下文調用Base函數 var ret = Base.call(obj); // 4.如果構造函數返回的是原始值,那么這個返回值會被忽略,如果返回的是對象,就會覆蓋構造的實例 if(typeof ret == "object"){ return ret; } else { return obj; }new的不足
在《Javascript語言精粹》(Javascript: The Good Parts)中,道格拉斯認為應該避免使用new關鍵字:
If you forget to include the new prefix when calling a constructor function, then this will not be bound to the new object. Sadly, this will be bound to the global object, so instead of augmenting your new object, you will be clobbering global variables. That is really bad. There is no compile warning, and there is no runtime warning.
大意是說在應該使用new的時候如果忘了new關鍵字,會引發一些問題。最重要的問題就是影響了原型查找,原型查找是沿著__proto__進行的,而任何函數都是Function的實例,一旦沒用使用new,你就會發現什么屬性都查找不到了,因為相當于直接短路了。如下面例子所示,沒有使用new來創建對象的話,就無法找到原型上的fa1屬性了:
javascriptfunction F(){ } F.prototype.fa1 = "fa1"; console.log(F.fa1); // undefined console.log(new F().fa1); // fa1
這里我配合一張圖來說明其中原理,黃色的線為原型鏈,使用new構造的對象可以正常查找到屬性fa1,沒有使用new則完全走向了另外一條查找路徑:
以上的問題對于有繼承的情況表現得更為明顯,沿著原型鏈的方法和屬性全都找不到,你能使用的只有短路之后的Function.prototype的屬性和方法了。
當然了,遺忘使用任何關鍵字都會引起一系列的問題。再退一步說,這個問題是完全可以避免的:
javascriptfunction foo() { // 如果忘了使用關鍵字,這一步驟會悄悄幫你修復這個問題 if ( !(this instanceof foo) ) return new foo(); // 構造函數的邏輯繼續…… }
可以看出new并不是一個很好的實踐,道格拉斯將這個問題描述為:
This indirection was intended to make the language seem more familiar to classically trained programmers, but failed to do that, as we can see from the very low opinion Java programmers have of JavaScript. JavaScript’s constructor pattern did not appeal to the classical crowd. It also obscured JavaScript’s true prototypal nature. As a result, there are very few programmers who know how to use the language effectively.
簡單來說,JavaScript是一種prototypical類型語言,在創建之初,是為了迎合市場的需要,讓人們覺得它和Java是類似的,才引入了new關鍵字。Javascript本應通過它的Prototypical特性來實現實例化和繼承,但new關鍵字讓它變得不倫不類。
再說一點關于constructor的雖然使用new創建新對象的時候用討論了這個constructor屬性,但是這個屬性似乎并沒有什么用,也許設置這個屬性就是一種習慣,能夠讓其他人直觀理解對象之間的關系。
歡迎光臨小弟博客:Superlin"s Blog
我的博客原文:你真的弄明白new了嗎
再談javascript面向對象編程
JavaScript的實例化與繼承:請停止使用new關鍵字
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/85678.html
摘要:補充的知識這個是原型中的自帶屬性,指向構造函數這個屬性其實是瀏覽器實現的,不是標準的訪問原型的方式中規定的正式方法是以上知識,最終的圖如下思考題在文章開頭我們說過函數也是對象,既然是對象就有原型,那的原型指向誰呢是嗎 文章開頭說的話 首先你必須明白(或者記住)的JavaScript常識: 在JavaScript中每個函數都有一個prototype屬性 在JavaScript中每個對象...
摘要:二進制位,是計算機內部數據儲存的最小單位,是一個位二進制數。由于源代碼也是一個文本文件,所以,當你的源代碼中包含中文的時候,在保存源代碼時,就需要務必指定保存為編碼。 計算機存儲的幾個概念 想要徹底搞清楚編碼問題,我們必須要先搞清楚計算機是怎么存儲數據的,這就涉及到了計算機基礎的幾個概念了,開篇我們就先來捋捋這幾個容易混淆的概念。 bit 二進制位, 是計算機內部數據儲存的最小單位,1...
摘要:那都是老一套了。已死已經沒有人用了。現在所有的一切都在容器化,它是未來。這是確保它可靠的唯一方式。我現在需要一個是的,為了穩定性。我猜是規模的對,沒錯。我明白了,好吧,我懂了。那我來重復一遍確保我領悟了這些。 這是一篇在國外社區非常火的文章。由CircleCI創始人所寫,追逐熱點新技術的程序員與只想做個簡單web應用的程序員對話,Docker到底能否解決簡單小應用的問題嗎?Herok...
閱讀 729·2021-11-24 10:19
閱讀 1106·2021-09-13 10:23
閱讀 3428·2021-09-06 15:15
閱讀 1777·2019-08-30 14:09
閱讀 1684·2019-08-30 11:15
閱讀 1837·2019-08-29 18:44
閱讀 934·2019-08-29 16:34
閱讀 2456·2019-08-29 12:46