天天看點

js--原型和原型鍊相關問題

js--原型和原型鍊相關問題

前言

  閱讀本文前先來思考一個問題,我們在 js 中建立一個變量,我們并沒有給這個變量添加一些方法,比如 toString() 方法,為什麼我們可以直接使用這個方法呢?如以下代碼,帶着這樣的問題,我們來學習本節的原型和原型鍊的一些知識。

js--原型和原型鍊相關問題

正文

  1.構造函數建立對象問題

  當使用構造函數建立對象person時,即使用new操作符構造一個執行個體對象的時候,首先會建立一塊新的記憶體空間,标記為person執行個體,執行構造函數會建立一個對象,會将對象的原型指向構造函數的 prototype 屬性,然後執行上下文中的this指向這個對象,最後再執行整個函數,如果傳回值不是對象,則傳回建立的對象,建立的對象有一個構造函數 constructor 屬性。其實質就是建立一個 object 引用類型的執行個體,然後把執行個體儲存在變量 person 中。

  總結 :new 操作符調用構造函數經曆了以下四步:

  (1)建立一個新對象;

  (2)将構造函數的作用域指派給新對象(是以 this 指向這個新對象);

  (3)執行構造函數中的代碼(為這個構造的新對象添加屬性);

  (4)傳回這個新對象。

  2.原型相關問題

  我們建立的每個函數都有一個 prototype 屬性,這個屬性是一個指針,指向一個對象,而這個對象包含了通過該構造函數執行個體的對象所共享的屬性和方法。那麼,prototype 就是通過調用構造函數而建立的那個對象執行個體的原型對象。

  上面的代碼,我們将 sayHello() 方法和所有屬性直接添加到了 Person 的 prototype 屬性中,構造函數變成了空函數,通過此構造函數建立的新對象執行個體,具有相同的屬性和方法,與純構造函數建立的對象不同的是所有執行個體共享了這些屬性和方法。

  (1)了解原型對象

  無論什麼時候,隻要建立一個新函數,就會根據一種特定的規則為該函數建立一個 prototype 屬性,這個屬性指向函數的原型對象,預設情況下,所有原型對象都會自動獲得一個 constructor (構造函數)屬性,這個屬性包含一個指向 prototype 屬性所在函數的指針。例如上面的例子中 Person.prototype.constructor 指向 Person,同樣,我們可以繼續為原型對象添加别的屬性和方法。建立了自定義構造函數之後,其原型隻會取得constructor屬性,其他方法都是通過從object繼承而來,當調用構造函數建立一個新執行個體後,該執行個體内部會包含一個指針指向構造函數的原型對象,這個指針叫 __proto__ ,是以可以通過下面的圖來表示上面例子的代碼。

js--原型和原型鍊相關問題

  是以通過上面的圖不難得出,js 中擷取原型的方法有如下三種:

  (1)person1.__proto__

  (2)Object.getPrototype(person1)

  (3)person1.constructor.prototype

  同樣可以通過 isPrototypeOf() 方法來确定對象之間是否存在原型關系,Person.prototype.isPrototypeOf( person1 )傳回值為 true 。當然也可以如下使用Object.getPrototype(person1).name傳回值為“ xiaoming ”。再來看下下面的這段代碼:

  通過上面的代碼不難得出對象屬性的通路順序,每當代碼中讀取某個對象的屬性是,都會執行一次搜尋,目标是給定名字的屬性,搜尋首先從對象執行個體本身開始,如果在執行個體中找到了具有給定名字的屬性,則傳回該屬性的值,如果沒有找到,則會繼續搜尋__proto__指針指向的原型對象,在原型對象中找到具有相同名字的屬性。雖然可以通過對象執行個體通路儲存在原型對象中的值,但是不能通過獨享執行個體重新原型中的值,如果我們在執行個體中添加一個屬性,而該屬性與原型中的屬性同名,那麼就在執行個體中建立該屬性,該屬性就會屏蔽原型對象中的那個屬性。即添加了同名屬性後,這個屬性就會阻止我們通路原型中的屬性。即使我們把這個屬性值設定為null,也隻會在執行個體中通路這個屬性,不會恢複對原型的同名屬性的通路,要想恢複,隻能使用 delete 操作符完全删除該執行個體屬性。是以,官方也提供了一個 hasOwnProperty() 方法來判斷該屬性是否屬于執行個體對象,如果是則傳回 true,否則傳回 false 。

  最後總結得出原型,構造函數,執行個體對象三者之間的關系如下:

js--原型和原型鍊相關問題

  (2)原型與 in 操作符

  使用 in 操作符有兩種情況,一種是直接使用,另外一種是 for- in循環中使用,在單獨使用的時候,in 操作符會在通過對象能夠通路屬性的時候傳回 true ,無論該屬性存在于對象執行個體還是原型對象中。"name" in person1 傳回 true ,是以結合 hasOwnProperty() 方法可以判斷屬性是存在于自身執行個體中,還是存在于原型對象中。使用 for-in 循環時,傳回的是所有能夠在對象中可以通路,可以枚舉的屬性,其中既包含執行個體中的有包含原型中的,tostring(),valueOf()....但是由于浏覽器版本限制,這種方式不推薦使用。

  要取得對象上所有可枚舉的執行個體屬性,可以通過 Object.keys() 方法,該方法接收一個對象作為參數,傳回一個包含所有可枚舉屬性的字元串數組。

  (3)原型的原型關系如下圖:

js--原型和原型鍊相關問題

  2.原型鍊

  了解原型鍊之前,先來看如下代碼:

  這就是剛開始講到的,為什麼每一個對象都包含 tostring() 這個方法呢,有了原型的了解,這裡用到原型鍊,當我們通路一個對象的屬性或者方法時,如果這個對象執行個體内部不存在這個屬性或者方法,那麼他會在原型對象裡找這個同名屬性或者方法,這個原型對象又有自己的原型,于是這麼一層一層找下去,也就産生了原型鍊這個概念,原型鍊的盡頭一般來說都是 Object.prototype ,所有者就産生了建立的對象都會存在 toString() 等方法。

js--原型和原型鍊相關問題

總結

  以上就是本文的全部内容,希望給讀者帶來些許的幫助和進步,友善的話點個關注,小白的成長之路會持續更新一些工作中常見的問題和技術點。

js--原型和原型鍊相關問題