目錄javascript
- 建立對象有幾種方法
- 原型、構造函數、實例、原型鏈
- instanceof的原理
- new運算符
建立對象的方法
在瞭解原型鏈以前,首先先了解一下建立對象的幾種方式,介紹如下三種。html
代碼:java
<script type="text/javascript"> // 第一種方式:字面量 var o1 = {name: 'o1'} var o2 = new Object({name: 'o2'}) // 第二種方式:構造函數 var M = function (name) { this.name = name; } var o3 = new M('o3') // 第三種方式:Object.create var p = {name: 'p'} var o4 = Object.create(p)
console.log(o1)
console.log(o2)
console.log(o3)
console.log(o4)
</script>
打印結果:函數
對象是建立出來了,但你可能對結果很詫異,爲何不一樣呢?別急,慢慢來。post
原型及原型鏈
先來一張容易讓人懵逼的圖this
什麼是原型對象?實例?構造函數?spa
概念就很少說了,看代碼吧prototype
var M = function (name) { this.name = name; } var o3 = new M('o3')
- 實例就是對象,在本例中o3就是實例,M就是構造函數。
- 實例經過new一個構造函數生成的。
- 從上圖中能夠知道,實例的__protpo__指向的是原型對象。
- 實例的構造函數的prototype也是指向的原型對象。
- 原型對象的construor指向的是構造函數。
再來經過下面這個圖來理解一下 3d
那什麼是原型鏈呢?code
簡單理解就是原型組成的鏈,對象的__proto__它的是原型,而原型也是一個對象,也有__proto__屬性,原型的__proto__又是原型的原型,就這樣能夠一直經過__proto__想上找,這就是原型鏈,當向上找找到Object的原型的時候,這條原型鏈就算到頭了。
原型對象和實例之間有什麼做用呢?
經過一個構造函數建立出來的多個實例,若是都要添加一個方法,給每一個實例去添加並非一個明智的選擇。這時就該用上原型了。
在實例的原型上添加一個方法,這個原型的全部實例便都有了這個方法。
接着上面的例子繼續演示:
var M = function (name) { this.name = name; }
var o3 = new M('o3')
var o5 = new M()
o3.__proto__.say=furnction(){ console.log('hello world') } o3.say() o5.say()
打印結果
按照JS引擎的分析方式,在訪問一個實例的屬性的時候,如今實例自己中找,若是沒找到就去它的原型中找,還沒找到就再往上找,直到找到。這就是原型鏈。
補充:
只有函數有prototype,對象是沒有的。
可是函數也是有__proto__的,由於函數也是對象。函數的__proto__指向的是Function.prototype。
也就是說普通函數是Function這個構造函數的一個實例。
instanceof原理
instanceof是判斷實例對象的__proto__和生成該實例的構造函數的prototype是否是引用的同一個地址。
是返回true,否返回false。
注意:實例的instanceof在比較的時候,與原型鏈上想上找的的構造函數相比都是true。
繼續上面的代碼
那怎麼判斷實例是由哪一個構造函數生成的呢?這時候就要用到constructor了。
實例的原型的構造函數, obj.__proto__.constructor
new運算符
new運算符的原理
- 一個新對象被建立。它繼承自foo.prototype。
- 構造函數返回一個對象。在執行的時候,相應的傳參會被傳入,同時上下文(this)會被指定爲這個新的實例。
- new foo等同於new foo(), 只能用在不傳遞任何參數的狀況
- 若是構造函數反悔了一個對象,那個這個對象會取代整個new出來的結果。若是構造函數沒有返回對象,那個new出來的結果爲步驟1建立的對象。
下面根據new的工做原理經過代碼手動實現一下new運算符
var new2 = function (func) { var o = Object.create(func.prototype); //建立對象 var k = func.call(o); //改變this指向,把結果付給k if (typeof k === 'object') { //判斷k的類型是否是對象 return k; //是,返回k } else { return o; //不是返回返回構造函數的執行結果 } }
驗證
通過上圖一系列折騰,不難看出,咱們手動編寫的new2和new運算符的做用是同樣的。
經過這個例子,你是否是已經熟知了new的工做原理了呢