摘要:今天同事小英童鞋問了我一個問題小英童鞋認為的原型對象是,所以會繼承的屬性,調用相當于調用,但結果不是一個方法。構造函數創建對象實例函數有兩個不同的內部方法和。如果不通過關鍵字調用函數,則執行函數,從而直接執行代碼中的函數體。
今天同事小英童鞋問了我一個問題:
function Foo(firstName, lastName){ this.firstName = firstName; this.lastName = lastName; } Foo.prototype.logName = function(){ Foo.combineName(); console.log(this.fullName); } Foo.prototype.combineName = function(){ this.fullName = `${this.firstName} ${this.lastName}` } var foo = new Foo("Sanfeng", "Zhang"); foo.logName(); // Uncaught TypeError: Foo.combineName is not a function
小英童鞋認為Foo的原型對象是Foo.prototype,所以Foo會繼承Foo.prototype的屬性,調用Foo.combineName()相當于調用Foo.prototype.combineName(),但結果Foo.combineName()不是一個方法。
會造成這個問題的原因一定是因為小英童鞋弄混了原型和繼承的一些原理,下面我們來整理一下原型和繼承的相關原理,找出問題的根本原因。
prototypeprototype是一個擁有 [[Construct]] 內部方法的對象才有的屬性。
例如函數,對象的方法,ES6 中的類。注意 ES6 中的箭頭函數沒有 [[Construct]] 方法,因此沒有prototype這個屬性,除非你為它添加一個。
當創建函數時,JavaScript 會為這個函數自動添加prototype屬性,這個屬性指向的是一個原型對象Functionname.prototype。我們可以向這個原型對象添加屬性或對象,甚至可以指向一個現有的對象。
__proto__接下來我們說說繼承,每個對象都有一個__proto__屬性,這個屬性是用來標識自己所繼承的原型。
注意: JavaScript 中任意對象都有一個內置屬性 [[Prototype]] ,在ES5之前沒有標準的方法訪問這個內置屬性,但是大多數瀏覽器都支持通過__proto__來訪問。以下統一使用__proto__來訪問 [[Prototype]],在實際開發中是不能這樣訪問的。
原型鏈JavaScript 可以通過prototype和__proto__在兩個對象之間創建一個關聯,使得一個對象就可以通過委托訪問另一個對象的屬性和函數。
這樣的一個關聯就是原型鏈,一個由對象組成的有限對象鏈,用于實現繼承和共享屬性。
構造函數創建對象實例JavaScript 函數有兩個不同的內部方法:[[Call]] 和 [[Construct]] 。
如果不通過new關鍵字調用函數,則執行 [[Call]] 函數,從而直接執行代碼中的函數體。
當通過new關鍵字調用函數時,執行的是 [[Construct]] 函數,它負責創建一個實例對象,把實例對象的__proto__屬性指向構造函數的prototype來實現繼承構造函數prototype的所有屬性和方法,將this綁定到實例上,然后再執行函數體。
模擬一個構造函數:
function createObject(proto) { if (!(proto === null || typeof proto === "object" || typeof proto === "function"){ throw TypeError("Argument must be an object, or null"); } var obj = new Object(); obj.__proto__ = proto; return obj; } var foo = createObject(Foo.prototype);
至此我們了解了prototype和__proto__的作用,也了解使用構造函數創建對象實例時這兩個屬性的指向,以下使用一張圖來總結一下如何通過prototype和__proto__實現原型鏈。
從上圖我們可以找出foo對象和Foo函數的原型鏈:
foo.__proto__ == Foo.prototype; foo.__proto__.__proto__ == Foo.prototype.__proto__ == Object.prototype; foo.__proto__.__proto__.__proto__ == Foo.prototype.__proto__.__proto__ == Object.prototype.__proto__ == null;
Foo.__proto__ == Function.prototype; Foo.__proto__.__proto__ == Function.prototype.__proto__; Foo.__proto__.__proto__.__proto__ == Function.prototype.__proto__.__proto__ == Object.prototype.__proto__ == null;
構造函數Foo的原型鏈上沒有Foo.prototype,因此無法繼承Foo.prototype上的屬性和方法。而實例foo的原型鏈上有Foo.prototype,因此foo可以繼承Foo.prototype上的屬性和方法。
到這里,我們可以很簡單的解答小英童鞋的問題了,在Foo的原型鏈上沒有Foo.prototype,無法繼承Foo.prototype上的combineName方法,因此會拋出Foo.combineName is not a function的異常。要想使用combineName方法,可以這樣Foo.prototype.combineName.call(this),或者這樣this.combineName()(this指向實例對象)。
歡迎關注:Leechikit
原文鏈接:segmentfault.com到此本文結束,歡迎提問和指正。
寫原創文章不易,若本文對你有幫助,請點贊、推薦和關注作者支持。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/92015.html
摘要:的英文含義是名單種技術的確都是把當做清單使用緩存清單清單打包資源路徑清單打包清單只不過是在不同的場景中使用特定的清單來完成某些功能所以,學好英文是多么重要,這樣才不會傻傻分不清到底是干啥的 在前端,說到manifest,其實是有歧義的,就我了解的情況來說,manifest可以指代下列含義: html標簽的manifest屬性: 離線緩存(目前已被廢棄) PWA: 將Web應用程序...
摘要:當這步完成,這個對象就與構造函數再無聯系,這個時候即使構造函數再加任何成員,都不再影響已經實例化的對象了。此時,對象具有了和屬性,同時具有了構造函數的原型對象的所有成員,當然,此時該原型對象是沒有成員的。 學到原型的時候感覺頭都大了/(ㄒoㄒ)/~~ 尤其是prototype和__proto__ 傻傻分不清,通過多番查找資料,根據自己的理解,記錄下最近研究對象的一些心得,做一個記錄與總...
摘要:忍者級別的函數操作對于什么是匿名函數,這里就不做過多介紹了。我們需要知道的是,對于而言,匿名函數是一個很重要且具有邏輯性的特性。通常,匿名函數的使用情況是創建一個供以后使用的函數。 JS 中的遞歸 遞歸, 遞歸基礎, 斐波那契數列, 使用遞歸方式深拷貝, 自定義事件添加 這一次,徹底弄懂 JavaScript 執行機制 本文的目的就是要保證你徹底弄懂javascript的執行機制,如果...
摘要:原型鏈首先,的對象普通對象和函數對象都會有屬性,指向創建它的構造函數的原型對象,比如上面的例子這就形成了原型鏈,會一直查找原型對象的屬性,直到為。,保證原型鏈能夠正常結束。 前言 一般談到js中的繼承的時候,一定會遇到原型,原型鏈的問題,原型里面又有prototype,__proto__,constructor屬性,講到這兒,很多同學是不是都一頭霧水,傻傻分不清楚,因為工作中用到的地方...
摘要:組合方式繼承終極版工商建設開心能分清是孩子還是父輩二狗的構造函數已指向圖示關鍵代碼創建對象的方法就是用原型鏈來連接的。也讓二狗有了確定的歸屬。 一、繼承原理 原型鏈不知道什么是原型鏈?來讀幾個關鍵詞: 哥歐 構 構造函數 構造函數 構造函數 實例 實例 實例 原型對象 原型對象 原型對象 prototype prototype prototype __proto__ __pro...
閱讀 1139·2021-11-08 13:13
閱讀 1721·2019-08-30 15:55
閱讀 2773·2019-08-29 11:26
閱讀 2439·2019-08-26 13:56
閱讀 2561·2019-08-26 12:15
閱讀 2143·2019-08-26 11:41
閱讀 1404·2019-08-26 11:00
閱讀 1543·2019-08-23 18:30