原型與原型鏈理解 1. 什么是原型
JavaScript是一種簡易的腳本語言,其是由對象構成。每一個JavaScript對象(除null外)都和另一個對象相關聯,“另一個”對象就是原型。也就是說,任何一個對象都有原型這個屬性。
隱式原型(_proto_):上面說的這個原型是JavaScript中的內置屬性[[prototype]],此屬性繼承自object對象,在腳本中沒有標準的方式訪問[[prototype]],但Firefox、Safari和Chrome在每個對象上都支持一個屬性_proto_。隱式原型的作用是用來構成原型鏈,實現基于原型的繼承
顯示原型(prototype):每一個函數在創建之后,便會擁有一個prototype屬性,這個屬性指向函數的原型對象。顯示原型的作用是用來實現基于原型的繼承與屬性的共享
2. 那原型是用來做什么的?其可以解決什么問題?
構造函數的缺陷:
構造函數是通過new運算符創建并初始化一個新的對象,關鍵字new后跟隨一個函數調用,這個函數稱為構造函數,構造函數用來初始化一個新創建的對象。
現在有一個Person的構造函數,表示人對象的原型
function Person(name) { this.name = name this.address = "上海" // 設置一個實例對象的共有屬性address } //生成人對象實例 var person1 = new Person("Tom") var person2 = new Person("Jack")
這兩個對象的address屬性是獨立的,修改其中一個,不會影響到另一個
person1.address = "北京" console.log(person2.address) // 上海,不受person1的影響
每一個實例對象都有自己的屬性和方法的副本,由于無法做到數據共享,導致資源的浪費。所以,為了解決數據無法共享的問題,引入了prototype屬性,prototype屬性是一個指針,指向一個對象,而這個對象的用途是包含可以由特定類型的所有實例共享的屬性和方法,也就是說prototype是通過調用構造函數而創建的那個對象實例的原型對象。因此我們可以將實例對象需要共享的屬性和方法都放在這個對象中。
現在對上面的Person方法進行重寫,假設我們需要address這個屬性是共享的,但是name是獨有的。
function Person(name) { this.name = name } Person.prototype = { address: "上海" } //生成人對象實例 var person1 = new Person("Tom") var person2 = new Person("Jack") //修改共享的屬性address Person.prototype.address = "北京" console.log(person1.prototype) // 北京 console.log(person2.prototype) // 北京
address屬性放在了Person的prototype對象中,創建實例后,兩個實例也將address屬性放在了原型對象中,這兩個實例對象共享這個屬性,只要修改Person中的prototype對象,就會同時影響兩個實例對象
繼承機制
我們都知道JavaScript里面都是對象,如果想要讓所有的對象聯系起來,就需要有一種繼承機制來實現。上面的例子中說了實例中原型的作用,就是實現共享屬性和方法,但是如果想要讓其他引用類型也共享這個引用類型的屬性和方法呢?假如我們讓原型對象等于另一個類型的實例,此時的原型對象將包含一個指向另一個原型的指針,相應地,另一個原型中也包含著一個指向另一個構造函數的指針。假如另一個原型又是另一個類型的實例,且關系依然成立,如此層層遞進,就構成了實例與原型的鏈條。
實現原型鏈的基本模式
//原型鏈 function SuperType() { this.property = true } SuperType.prototype.getSuperValue = function(){ return this.property } function SubType () { this.subproperty = false } //繼承了SubType SubType.prototype = new SuperType() SubType.prototype.getSubValue = function () { return this.subproperty } var instance = new SubType() console.log(instance.getSuperValue())
首先先定義了兩個類型:SuperType和SubType,每個類型分別有一個屬性和方法,通過創建SuperType實例讓SubType繼承SuperType,并且將SuperType實例賦值給SubType.prototype。這樣就將原來存放在SuperType的實例中的所有屬性和方法共享到SubType.prototype中。
然后再給SubType.prototype添加一個方法,這樣就在繼承了SuperType的屬性和方法的基礎上又添加了一個新方法。
最終結果如圖上所示,instance指向SubType的原型,SubType的原型又指向SuperType的原型。getSuperValue()方法仍然還在SuperType.prototype中,但peoperty則位于SubType.prototype中。這是因為property是一個實例屬性,而getSuperValue()這是一個原型方法。對于原型鏈的繼承是如何進行的呢?
這就需要介紹一些原型搜索機制,原型搜索機制是當使用讀取模式訪問一個屬性時,首先會在實例中搜索該屬性,如果沒有找到該屬性,接著就會繼續搜索實例的原型。 在通過原型鏈實現繼承的情況下,搜索過程就得以沿著原型鏈繼續向上。就拿上面的例子來說,調用instance.getSuperValue()會經歷三個搜索步驟:
1). 搜索實例 2). 搜索SubTyp.prototype 3). 搜索SuperType.prototype,最后一步才會找到該方法
在找不到屬性或方法的時的情況下,搜索過程總是要一環一環地前行到原型鏈的末端才會停下來。
總結JavaScript的原型是為了實現對象間的聯系,解決構造函數無法數據共享而引入的一個屬性。而原型鏈是一個實現對象間聯系即繼承的主要方法。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/107477.html
摘要:探索是如何判斷的表達式如果函數的顯式原型對象在對象的隱式原型鏈上,返回,否則返回是通過自己產生的實例案例案例重要注意的顯示原型和隱式原型是一樣的。面試題測試題測試題報錯對照下圖理解 原型與原型鏈深入理解(圖解) 原型(prototype) 函數的 prototype 屬性(圖) 每個函數都有一個prototype屬性,它默認指向一個Object空對象(即稱為:原型對象) 原型對象中有...
摘要:構造函數的屬性指向原型對象原型對象的屬性指向構造函數實例對象的指向原型對象所有引用類型默認都繼承了,而這個繼承也是通過原型鏈實現的。第一種方式是使用操作符,只要用這個操作符來測試實例與原型鏈中出現過的構造函數,結果就會返回。 理解對象 首先對象的定義是:無序屬性的集合,其屬性可以包含基本值、對象或者函數。嚴格來講,這就相當于說對象是一組沒有特定順序的值。對象的每個屬性或方法都有一個名...
摘要:原型對象是由創建的,因此原型對象的構造函數是構造函數也可以是稱為對象,原型對象也就繼承了其生父構造函數中的數據,也同時繼承了原型對象的數據。當然這條原型鏈中的數據,會被還是還是這類構造函數繼承,但是不會被這些繼承,他們不處于同一個鏈條上。 js中,Function的本質是什么?Object的本質又是什么?js中有幾條原型鏈? showImg(https://segmentfault.c...
摘要:相當于在用原型繼承編寫復雜代碼前理解原型繼承模型十分重要。同時,還要清楚代碼中原型鏈的長度,并在必要時結束原型鏈,以避免可能存在的性能問題。 js是一門動態語言,js沒有類的概念,ES6 新增了class 關鍵字,但只是語法糖,JavaScript 仍舊是基于原型。 至于繼承,js的繼承與java這種傳統的繼承不一樣.js是基于原型鏈的繼承. 在javascript里面,每個對象都有一...
摘要:原型鏈與繼承當談到繼承時,只有一種結構對象。如果對該圖不怎么理解,不要著急,繼續往下看基于原型鏈的繼承對象是動態的屬性包指其自己的屬性。當使用操作符來作用這個函數時,它就可以被稱為構造方法構造函數。 原型鏈與繼承 當談到繼承時,JavaScript 只有一種結構:對象。每個實例對象(object )都有一個私有屬性(稱之為proto)指向它的原型對象(prototype)。該原型對象也...
閱讀 1712·2021-11-18 10:02
閱讀 2224·2021-11-15 11:38
閱讀 2675·2019-08-30 15:52
閱讀 2199·2019-08-29 14:04
閱讀 3238·2019-08-29 12:29
閱讀 2093·2019-08-26 11:44
閱讀 1000·2019-08-26 10:28
閱讀 839·2019-08-23 18:37