摘要:而在原型對象中默認有一個屬性存儲了構造函數的地址引用也就是指向了構造函數。原型鏈的頂端是是所有對象的祖宗,的值為。但是上面的代碼把構造函數和原型分開寫了。
什么是原型
原型其實就是一個特殊的對象,在聲明函數的時候自動創建的。
比如,我們現在聲明一個構造函數 A ,除了會申請保存函數的內存空間,還會額外申請一個內存空間,用于存儲構造函數 A 的原型對象。所有函數中(Function.prototype.bind 除外)默認都有一個 prototype 的屬性,它保存了函數的原型對象的地址(引用)(也就是它指向了原型對象)。
而在原型對象中默認有一個 constructor 屬性存儲了構造函數的地址(引用)(也就是 constructor 指向了構造函數)。如果不理解上面所說的,那我們看下面的圖:
瀏覽器控制臺中:
_ _proto_ _ 與 prototype剛開始接觸原型的時候這兩個東西很容易就搞混了。
先記住以下兩點,就很容易就區分了:
prototype 是函數中才有的屬性
__proto__ 是所有對象都有的屬性
我們已經知道了函數中的 prototype 屬性指向的是它的原型對象,那么對象中的 __proto__ 代表什么?
一般情況下,對象中的 __proto__ 屬性是指向它的構造函數的原型對象的,即和構造函數中的 prototype 屬性所指向的對象是同一個對象。
用一段簡單的代碼:
function A() {} var a = new A()
上圖看著不夠簡便,我們簡化一下:
還有一點,__proto__ 不是一個規范屬性,ie(除了 ie10) 不支持。對應的標準屬性是 [[Prototype]] ,但是這個屬性我們沒法直接訪問到。開發者盡量不要用這種方式去訪問,因為操作不慎會改變這個對象的繼承原型鏈。
在使用 Object.create(參數) 方式創建對象時,對象的 __proto__ 屬性指向的是傳入的參數。
原型鏈由于 __proto__ 是所有對象都具有的屬性,而 __proto__ 本身指向的原型(函數.prototype)也是一個對象,它也有 __proto__ 屬性。所以這樣會形成由 __proto__ 將對象和原型連起來的鏈條。這就是原型鏈。原型鏈的頂端是 Object.prototype(Object 是所有對象的祖宗) ,Object.prototype.__proto__的值為 null 。
還是看之前的代碼:
function A() {} var a = new A()
它的原型鏈如下:
構造函數 A 其實也是一個對象。所有函數都是由 Function 函數構造的。(聲明函數 function A() {} 等價于 var A = new Function()) 。所以所有函數的 __proto__ 指向的都是 Function.prototype 。更新上圖:
Function 也是一個函數,它的 __proto__ 指向的也是 Functon.prototype 即 Funtion.__proto__ === Function.prototype。繼更新上圖:
Object 同樣是一個函數,所以 Object.__proto__ === Function.prototype
到了這里,我們應該可以看懂下面這張圖了:
原型的作用當 JS 引擎查找對象屬性時,先查找對象本身是否存在該屬性,如果不存在,會在對象的 __proto__ 里找,還找不到就會沿著原型鏈一直找到原型鏈頂端(Object.prototype) 直到找到屬性為止,最后在原型鏈頂端都沒找到就返回 undefined 。
由于上面的機制,原型的作用就很明顯了——共享屬性,節省內存空間。
function Animal() { this.name = "動物" this.eat = function() { console.log("在吃···") } } var a1 = new Animal() var a2 = new Animal() console.log(a1.eat === a2.eat) // false // 每個對象的 eat 方法不是同一個,但方法類容一樣,浪費內存
使用 原型解決:
function Animal(name) { this.name = "動物" } Animal.prototype.eat = function() { console.log("吃") } var a1 = new Animal() var a2 = new Animal() console.log(a1.eat === a2.eat) //true // a1.eat 和 a2.eat 都同一個方法(Animal.prototype.eat)
原型非常適合封裝共享的方法。但是上面的代碼把構造函數和原型分開寫了。封裝不到位。使用動態類型模式解決。
function Animal() { this.name = "動物" /* 判斷 this.eat 是不是 函數類型, 如果不是,則表示是第一次創建對象或者調用 Animal 函數, 會將 eat 添加到原型中去。 如果是,則表示原型中存在了 eat 方法,不需要再添加。 */ if(typeof this.eat !== "function") { Animal.prototype.eat = function() { console.log("吃") } } } var a = new Animal() a.eat()
原型基于之前的共享屬性和方法,是實現 JS 中繼承的基礎。
與原型有關的方法 hasOwnProperty()通過之前的學習,我們知道了去訪問一個對象的屬性時,會在原型鏈上查找。所以我們并不知道這個屬性來自哪里。
hasOwnProperty() 方法返回一個布爾值,可以判斷一個屬性是否來自對象本身。
function Animal() {} Animal.prototype.name = "動物" var a = new Animal() a.age = 3 console.log(a.hasOwnProperty("name")) // false console.log(a.hasOwnProperty("age") // truein 操作符
in 操作符用返回一個布爾值,用來判斷一個屬性能否在對象上找到。在對象的原型鏈上找到也返回 true。
function Animal() {} Animal.prototype.name = "動物" var a = new Animal() a.age = 3 console.log("name" in a) // true console.log("age" in a) // true console.log("sex" in a) // false總結
原型就是一個對象,聲明函數就會創建原型對象
prototype 只存在于函數中
所有對象都有一個 __proto__ 屬性,它指向對象的構造函數的原型
原型 也是對象,也有 __proto__ 屬性,__proto__ 將對象和原型連接起來,形成原型鏈
Object.prototype 是原型鏈的頂端
訪問對象的屬性會沿著對象的原型鏈找下去
原型可以共享屬性和方法,是繼承的基礎
閱讀原文
參考資料:
https://juejin.im/post/5835853f570c35005e413b19
https://blog.csdn.net/u012468376/article/details/53121081
https://juejin.im/book/5bdc715fe51d454e755f75ef/section/5bed40d951882545f73004f6
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/109097.html
摘要:情況沒有明確作用對象的情況下,通常為全局對象例如函數的回調函數,它的就是全局對象。正因如此,機器可以作為這類對象的標志,即面向對象語言中類的概念。所以機器又被稱為構造函數。原型鏈也就是繼承鏈。 JS面向對象二:this/原型鏈/new原理 阮一峰JavaScript教程:面向對象編程 阮一峰JavaScript教程:實例對象與 new 命令 阮一峰JavaScript教程:this 關...
摘要:先來說其實構造函數也有,原型對象有,實例有也有,或者更加籠統的說,所有對象都是有的。構造函數的原型對象上的會指向構造函數。由于屬性是可以變更的,所以未必真的指向對象的構造函數,只是一個提示。 續上一集內容,通過構造函數的方式,成功地更新了生產技術,老板笑呵呵,工人少奔波,只是問題總比辦法多,又遇到一個新問題,就是會造成一些資源的重復和浪費,那么經過工程師們的智慧交流,他們產生了一個新技...
摘要:在節中,我們學習到了通過構造函數創建對象的三個重要步驟,其中的一步是把構造函數的對象設置為創建對象的原型。利用而不是直接用創建一個實例對象的目的是,減少一次調用父構造函數的執行。 JavaScript語言不像面向對象的編程語言中有類的概念,所以也就沒有類之間直接的繼承,JavaScript中只有對象,使用函數模擬類,基于對象之間的原型鏈來實現繼承關系,ES6的語法中新增了class關鍵...
摘要:三種使用構造函數創建對象的方法和的作用都是在某個特殊對象的作用域中調用函數。這種方式還支持向構造函數傳遞參數。叫法上把函數叫做構造函數,其他無區別適用情境可以在特殊的情況下用來為對象創建構造函數。 一、工廠模式 工廠模式:使用字面量和object構造函數會有很多重復代碼,在此基礎上改進showImg(https://segmentfault.com/img/bVbmKxb?w=456&...
摘要:創建構造函數后,其原型對象默認只會取得屬性至于其他的方法都是從繼承來的。上圖展示了構造函數的原型對象和現有的兩個實例之間的關系。所有原生的引用類型都在其構造函數的原型上定義了方法。 第6章我一共寫了3篇總結,下面是相關鏈接:讀《javaScript高級程序設計-第6章》之理解對象讀《javaScript高級程序設計-第6章》之繼承 工廠模式 所謂的工廠模式就是,把創建具體對象的過程抽象...
閱讀 2314·2021-11-08 13:13
閱讀 1245·2021-10-09 09:41
閱讀 1683·2021-09-02 15:40
閱讀 3186·2021-08-17 10:13
閱讀 2546·2019-08-29 16:33
閱讀 3122·2019-08-29 13:17
閱讀 3131·2019-08-29 11:00
閱讀 3295·2019-08-26 13:40