outline
prototype
與__proto__
function
與object
new
到底發生了什么
prototype
與 __proto__
首先說下在JS中比較容易讓人困惑的 prototype
和 __proto__
__proto__
就是JavaScript中所謂的原型.
一個對象的 __proto__
屬性和自己的內部屬性[[Prototype]]指向一個相同的值 (通常稱這個值為原型),原型的值可以是一個對象值也可以是null(比如說Object.prototype.__proto__
的值就是null).該屬性可能會引發一些錯誤,因為用戶可能會不知道該屬性的特殊性,而給它賦值,從而改變了這個對象的原型. 如果需要訪問一個對象的原型,應該使用方法Object.getPrototypeOf.
firefox、chrome等瀏覽器把對象內部屬性[[Prototype]]用 __proto__
的形式暴露了出來.(老版本的IE並不支持 __proto__
,IE11中已經加上了 __proto__
屬性)
prototype
是function中特有的.什么意思呢?舉個例子:
function A(name){ this.name = name; } console.dir(A);
我們得到如下結果:

首先看A是一個函數,自然A的原型鏈就應該指向一個函數對象.
其次我們還看到當我們定義了function A的時候,A上會有一個 prototype
的屬性.這個屬性是我們定義function的時候就默認帶上的.A的 prototype
指向一個對象,這個對象的包含一個 constructor
屬性以及一個 __proto__
( __proto__
指向Object表示這是一個對象).默認的constructor屬性指向function A.
看起來有點混亂是不?這邊只要記住一點: __proto__
是原型,prototype是函數默認的一個屬性,它指向一個對象,這個對象的constructor屬性指向函數本身.
function與object
首先看一個例子
function A(name){ this.name = name; this.getName = function(){ console.log(this.name); } var b = 'test'; console.log(b); } var a = new A('testa'); A('TESTA');
當執行 var a = new A('testa');
得到的a是這樣的:

而我們執行 A('TESTA');
相當於:
//window.name = 'TESTA'(由於非strict模式下,this默認指向window) //window.getName = function(){console.log(this.name);}
我們的函數A既可以直接執行,又可以new一下返回一個對象.function和object到底是什么關系,new的時候發生了什么?
new到底發生了什么
還是我們上面的問題,當我們執行 var a = new A('testa')
到底發生了什么.MDN上是這么說的
對於 var o = new Foo();
//JavaScript 實際上執行的是:
var o = new Object(); o.[[Prototype]] = Foo.prototype; Foo.call(o);
這樣大概就明白了,當我們執行 new A('testa')
的時候
JS會這樣做
- var o = new Object();
- o.
__proto__
= A.prototype;//這里還記得之那個function里面的默認的屬性么? - A.call(o)//由於這里this是指向o,可以把什么this.name/getName綁定到o上.
- 把這個o返回給a;//完成var a = new A()的過程.
這里注意下,上面所謂的第4步其實是一個簡化的說法.真正的過程是在第3步之后,如果發現A返回是一個Object類型(非primitive類型,即非string,boolean,number,null,undefined類型就是Object類型),則直接返回A的返回值,否則把第1步new的Object返回出去.(默認情況下,JS中函數默認返回值是undefined)舉個例子
function A(name){ this.name = name; this.getName = function(){ console.log(this.name); } var b = 'test'; console.log(b); return {}; } var a = new A('testa');//{}
這里我們把A函數的返回值設置為一個Object類型,則這個時候執行new A返回的就是A函數的返回值{}.如果我們把A的返回值設置為return [];那么我們在new A的時候也相應的得到一個空數組.
用 stackoverflow 上一個人的回答來總結下就是:
In JavaScript, most functions are both callable and instantiable: they have both a [[Call]] and [[Construct]] internal methods.
在JS中,絕大多數的函數都是既可以調用也可以實例化的.我們既可以直接執行函數得到函數的返回值.也可以通過new操作符得到一個對象.
原文地址:http://warjiang.github.io/devcat/2016/05/12/JS中new到底發生了什么/