摘要:的過程新生成了一個對象鏈接到原型綁定返回新對象在調用的過程中會發(fā)生以上四件事情,我們也可以試著來自己實現(xiàn)一個創(chuàng)建一個空的對象獲得構造函數(shù)鏈接到原型綁定,執(zhí)行構造函數(shù)確保出來的是個對象對于實例對象來說,都是通過產生的,無論是還是。
prototype
首先來介紹下 prototype 屬性。這是一個顯式原型屬性,只有函數(shù)才擁有該屬性?;旧纤泻瘮?shù)都有這個屬性,但是也有一個例外
let fun = Function.prototype.bind()
如果你以上述方法創(chuàng)建一個函數(shù),那么可以發(fā)現(xiàn)這個函數(shù)是不具有 prototype 屬性的。
prototype 如何產生的
當我們聲明一個函數(shù)時,這個屬性就被自動創(chuàng)建了
function Foo() {}
并且這個屬性的值是一個對象(也就是原型),只有一個屬性 constructor
constructor 對應著構造函數(shù),也就是 Foo。
constructor
constructor 是一個公有且不可枚舉的屬性。一旦我們改變了函數(shù)的 prototype ,那么新對象就沒有這個屬性了(當然可以通過原型鏈取到 constructor)。
那么你肯定也有一個疑問,這個屬性到底有什么用呢?其實這個屬性可以說是一個歷史遺留問題,在大部分情況下是沒用的,在我的理解里,我認為他有兩個作用:
1.讓實例對象知道是什么函數(shù)構造了它
2.如果想給某些類庫中的構造函數(shù)增加一些自定義的方法,就可以通過 xx.constructor.method 來擴展
這是每個對象都有的隱式原型屬性,指向了創(chuàng)建該對象的構造函數(shù)的原型。其實這個屬性指向了 [[prototype]],但是 [[prototype]] 是內部屬性,我們并不能訪問到,所以使用 __proto__ 來訪問。
因為在 JS 中是沒有類的概念的,為了實現(xiàn)類似繼承的方式,通過 __proto__ 將對象和原型聯(lián)系起來組成原型鏈,得以讓對象可以訪問到不屬于自己的屬性。
實例對象的 __proto__ 如何產生的
從上圖可知,當我們使用 new 操作符時,生成的實例對象擁有了 __proto__屬性。
function Foo() {} // 這個函數(shù)是 Function 的實例對象 // function 就是一個語法糖 // 內部調用了 new Function(...)
所以可以說,在 new 的過程中,新對象被添加了 __proto__ 并且鏈接到構造函數(shù)的原型上。
new 的過程
1.新生成了一個對象
2.鏈接到原型
3.綁定 this
4.返回新對象
在調用 new 的過程中會發(fā)生以上四件事情,我們也可以試著來自己實現(xiàn)一個 new
function create() { // 創(chuàng)建一個空的對象 let obj = new Object() // 獲得構造函數(shù) let Con = [].shift.call(arguments) // 鏈接到原型 obj.__proto__ = Con.prototype // 綁定 this,執(zhí)行構造函數(shù) let result = Con.apply(obj, arguments) // 確保 new 出來的是個對象 return typeof result === "object" ? result : obj }
對于實例對象來說,都是通過 new 產生的,無論是 function Foo() 還是 let a = { b : 1 } 。
對于創(chuàng)建一個對象來說,更推薦使用字面量的方式創(chuàng)建對象。因為你使用 new Object() 的方式創(chuàng)建對象需要通過作用域鏈一層層找到 Object,但是你使用字面量的方式就沒這個問題。
function Foo() {} // function 就是個語法糖 // 內部等同于 new Function() let a = { b: 1 } // 這個字面量內部也是使用了 new Object()Function.__proto__ === Function.prototype
對于對象來說,xx.__proto__.contrcutor 是該對象的構造函數(shù),但是在圖中我們可以發(fā)現(xiàn) Function.__proto__ === Function.prototype,難道這代表著 Function 自己產生了自己?
答案肯定是否認的,要說明這個問題我們先從 Object 說起。
從圖中我們可以發(fā)現(xiàn),所有對象都可以通過原型鏈最終找到 Object.prototype ,雖然 Object.prototype 也是一個對象,但是這個對象卻不是 Object 創(chuàng)造的,而是引擎自己創(chuàng)建了 Object.prototype 。所以可以這樣說,所有實例都是對象,但是對象不一定都是實例。
接下來我們來看 Function.prototype 這個特殊的對象,如果你在瀏覽器將這個對象打印出來,會發(fā)現(xiàn)這個對象其實是一個函數(shù)。
我們知道函數(shù)都是通過 new Function() 生成的,難道 Function.prototype 也是通過 new Function() 產生的嗎?答案也是否定的,這個函數(shù)也是引擎自己創(chuàng)建的。首先引擎創(chuàng)建了 Object.prototype ,然后創(chuàng)建了 Function.prototype ,并且通過 __proto__ 將兩者聯(lián)系了起來。這里也很好的解釋了上面的一個問題,為什么 let fun = Function.prototype.bind() 沒有 prototype 屬性。因為 Function.prototype 是引擎創(chuàng)建出來的對象,引擎認為不需要給這個對象添加 prototype 屬性。
所以我們又可以得出一個結論,不是所有函數(shù)都是 new Function() 產生的。
有了 Function.prototype 以后才有了 function Function() ,然后其他的構造函數(shù)都是 function Function() 生成的。
現(xiàn)在可以來解釋 Function.__proto__ === Function.prototype 這個問題了。因為先有的 Function.prototype 以后才有的 function Function() ,所以也就不存在雞生蛋蛋生雞的悖論問題了。對于為什么 Function.__proto__ 會等于 Function.prototype ,個人的理解是:其他所有的構造函數(shù)都可以通過原型鏈找到 Function.prototype ,并且 function Function() 本質也是一個函數(shù),為了不產生混亂就將 function Function() 的 __proto__ 聯(lián)系到了 Function.prototype 上。
總結Object 是所有對象的爸爸,所有對象都可以通過 __proto__ 找到它
Function 是所有函數(shù)的爸爸,所有函數(shù)都可以通過 __proto__ 找到它
Function.prototype 和 Object.prototype 是兩個特殊的對象,他們由引擎來創(chuàng)建
除了以上兩個特殊對象,其他對象都是通過構造器 new 出來的
函數(shù)的 prototype 是一個對象,也就是原型
對象的 __proto__ 指向原型, __proto__ 將對象和原型連接起來組成了原型鏈
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://m.hztianpu.com/yun/98259.html
摘要:使用指定的參數(shù)調用構造函數(shù),并將綁定到新創(chuàng)建的對象。由構造函數(shù)返回的對象就是表達式的結果。情況返回以外的基本類型實例中只能訪問到構造函數(shù)中的屬性,和情況完全相反,結果相當于沒有返回值。 定義 new 運算符創(chuàng)建一個用戶定義的對象類型的實例或具有構造函數(shù)的內置對象的實例。 ——(來自于MDN) 舉個栗子 function Car(color) { this.color = co...
摘要:從最開始的到封裝后的都在試圖解決異步編程過程中的問題。為了讓編程更美好,我們就需要引入來降低異步編程的復雜性。異步編程入門的全稱是前端經典面試題從輸入到頁面加載發(fā)生了什么這是一篇開發(fā)的科普類文章,涉及到優(yōu)化等多個方面。 TypeScript 入門教程 從 JavaScript 程序員的角度總結思考,循序漸進的理解 TypeScript。 網(wǎng)絡基礎知識之 HTTP 協(xié)議 詳細介紹 HTT...
摘要:忍者級別的函數(shù)操作對于什么是匿名函數(shù),這里就不做過多介紹了。我們需要知道的是,對于而言,匿名函數(shù)是一個很重要且具有邏輯性的特性。通常,匿名函數(shù)的使用情況是創(chuàng)建一個供以后使用的函數(shù)。 JS 中的遞歸 遞歸, 遞歸基礎, 斐波那契數(shù)列, 使用遞歸方式深拷貝, 自定義事件添加 這一次,徹底弄懂 JavaScript 執(zhí)行機制 本文的目的就是要保證你徹底弄懂javascript的執(zhí)行機制,如果...
閱讀 2070·2019-08-29 16:27
閱讀 1422·2019-08-29 16:14
閱讀 3436·2019-08-29 14:18
閱讀 3520·2019-08-29 13:56
閱讀 1305·2019-08-29 11:13
閱讀 2197·2019-08-28 18:19
閱讀 3505·2019-08-27 10:57
閱讀 2349·2019-08-26 11:39