摘要:在中,萬物皆對象。在日常中,我們除了經常聽到原型這個詞之外,還經常會聽到原型鏈這個詞,那么這兩個詞到底有什么關系呢,下面我們就來探究一下。指向的對象往往被稱為函數的原型。很簡單,委托實際上就是原型鏈。
在JavaScript中,萬物皆對象。每個對象都有一個特殊的內部屬性,[[Prototype]](原型)。它是對于其他對象的引用,也就是說它關聯到別的對象(如果它不為空)。
在日常中,我們除了經常聽到原型這個詞之外,還經常會聽到原型鏈這個詞,那么這兩個詞到底有什么關系呢,下面我們就來探究一下。
那首先我們來看一下[[Prototype]]這個特殊的內部屬性有什么用呢?我們先來講一個關于屬性訪問的一些知識。看下面的代碼:
var myObject = { a:1; }; myObject.a; //1
在這里,我們可以清楚的看到Object.a是一個屬性訪問(訪問了Object的a屬性),那么深入一下,上面的代碼實際上在Object上執行了一個[[Get]]操作。對一個對象執行默認的[[Get]]操作,會首先檢查對象,尋找請求的屬性,如果找到,就返回相應的值。如果沒找到,這個時候對象的[[Prototype]]屬性以及它的[[Prototype]]鏈就需要派上用場了。
先看代碼:
var newObject = { a:1; }; var myObject = Object.create(newObject); myObject.a; //1
首先我們可以看到在上面的代碼中,a這個屬性是不存在myObject這個對象里的,但是最后我們還是得到了a這個屬性的值。
var myObject = Object.create(newObject);這行代碼就是關鍵了。它創建了一個對象myObject關聯到newObject。也就是說myObject的[[Prototype]]屬性關聯到了newObject這個對象。[[Get]]操作在對象本身沒找到需要的屬性后,便順著這個關聯去newObject這個對象里進行查找。
所以在對屬性進行查詢的時候,就會順著這個一層又一層的關聯,也就是所謂的[[Prototype]]鏈,對需要的屬性進行查找。在[[Prototype]]鏈找到了就返回屬性值或者在鏈條的末尾都沒找到就返回undefined。那么鏈條的末尾是什么呢?每個普通的[[Prototype]]鏈的最頂端,是內建的Object.prototype,也就是null。
開頭講到,[[Prototype]]這個屬性是把一個對象關聯到另一個對象。那么這個關聯有什么用呢?
常見的用法那就是所謂的原型繼承和委托了。
我們通過代碼來理解一下:
function Foo(a) { this.a = a; } Foo.prototype.myA = function() { return this.a; }; function Bar(a,b) { Foo.call(this,a); this.b = b; } Bar.prototype = Object.create(Foo.prototype); Bar.prototype.myB = function() { return this.b; }; var Baz = new Bar( "1", "obj 1" ); Baz.myA(); // "1" Baz.myB(); // "obj 1"
在上面的代碼中,最重要的部分就是Bar.prototype = Object.create(Foo.prototype);。這個代碼應該會比較眼熟,因為在上面的例子中我們也用到了相似的代碼,并且解釋說是把一個對象關聯到另一個對象上。那么這里我們是把新創建的Bar對象的內部的[[Prototype]]鏈接到了指定的對象Foo.prototype。
Bar和Foo在這里既是對象也是函數。函數有一個性質:所有的函數默認都會得到一個可以指向任何對象的屬性prototype。
指向的對象往往被稱為“函數的原型”。每個由調用new Foo()而創建的對象將最終被[[Prototype]]鏈接到所謂的“函數的原型”。
看段代碼來深入了解一下:
function Foo(a){ this.a = a; } var bar = new Foo(2); bar.a; //2 Object.getPrototypeOf(bar) === Foo.prototype; //true
那么為什么調用new Foo()創建的對象可以鏈接到函數原型呢?這就跟它的實現有關了。
當函數前面加new調用時,會有以下事情完成:
一個全新的對象被創建
這個新的對象會被接入到原型鏈
這個新的對象被設置為函數調用的this綁定
除非函數有返回對象,否則這個被new調用的函數將自動返回這個新的對象
主要我們要看的是第二點,其他的會在this綁定的文章中講到。
所以在上面的例子中,調用new Foo()創建bar的時候,bar會得到一個內部的[[Prototype]]鏈接,鏈接到Foo.prototype所指向的對象。
在“原型繼承”的例子代碼中var Baz = new Bar( "1", "obj 1" );也是使用了new來創建對象,從而使baz對象鏈接到bar.prototype上.
到目前為止,我們提到了2種方法來創建新對象并與其他對象關聯:
Object.create()
函數前面加new調用
表面上看好像都可以達到我們的目的,但是第二種方法可能會有意想不到的副作用產生。假如說Foo()這個函數還可以改變狀態或者向this添加數據屬性等,那么在對象在被創建的時候就會有這些我們可能本身并不需要的東西。
最后用一張圖來總結一下原型繼承:(圖來源:You-Dont-Know-JS)
從圖中可以看出,箭頭由右至左,由下至上。而[[Prototype]]機制,就是一種存在于對象上的內部鏈接,指向另一個對象。
事實上,“原型繼承”這個詞很容易讓人產生誤會,因為JavaScript中沒有類,也就沒有繼承。實際上,Bar與Foo不能說是繼承的關系,用準確點的術語來說,是委托。所以接下來我們就要來了解一下委托了。
很簡單,委托實際上就是原型鏈。比如說新建對象a鏈接到對象b,a可以使用b的方法,也就是a委托了b(來實現它想要實現的效果)。這樣的話直接用Object.create就可以了,不需要再調用new函數了。var a = Object.create(a);
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/93654.html
摘要:看完視頻初步認識了一下,以及模塊化開發的概念,在此做一下總結。所以應該將功能抽象成模塊。并且非常耗性能解決辦法,在滾動條正在運動或者已經到達目的地,就不應該執行動畫。 前言:在慕課網上跟著視頻《側邊工具欄開發》做了一遍,用到了jquery操作DOM,其中,用requirejs管理模塊依賴,然后自定義了兩個模塊它們都依賴jquery,并且其中一個自定義模塊依賴另一個,所以要暴露出接口。看...
摘要:最后舉兩個例子,回顧上面的內容例一改變的是數組元素中屬性,由于創建的的指令,因此這里直接由指令更新對應元素的內容。 下面例子來自官網,雖然看上去就比Hello World多了一個v-for,但是內部多了好多的處理過程。但是這就是框架,只給你留下最美妙的東西,讓生活變得簡單。 {{ todo.text }} ...
摘要:屬性這是每個對象都有的隱式原型屬性,指向了創建該對象的構造函數的原型。 原型 在JavaScript中,有兩個原型,分別是 prototype 和 _proto_注:在ECMA-262第5版中管這個 _proto_ 叫 [[Prototype]] prototype 屬性:這是一個顯式原型屬性,只有函數才擁有該屬性。_proto_ 屬性:這是每個對象都有的隱式原型屬性,指向了創建該對象...
摘要:很多情況下,通常一個人類,即創建了一個具體的對象。對象就是數據,對象本身不包含方法。類是相似對象的描述,稱為類的定義,是該類對象的藍圖或原型。在中,對象通過對類的實體化形成的對象。一類的對象抽取出來。注意中,對象一定是通過類的實例化來的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 馬上就要到七夕了,離年底老媽老爸...
閱讀 955·2019-08-30 14:24
閱讀 987·2019-08-30 14:13
閱讀 1799·2019-08-29 17:21
閱讀 2661·2019-08-29 13:44
閱讀 1654·2019-08-29 11:04
閱讀 438·2019-08-26 10:44
閱讀 2564·2019-08-23 14:04
閱讀 908·2019-08-23 12:08