1、背景app
在網上看到一篇別人轉的玉伯前輩關於「new FunctionName()運行機制淺析」的文章,裏面舉了一個例子,代碼以下:函數
function Dog(name) { this.name = name; Dog.prototype = { shout: function() { alert("I am " + this.name); } }; } var dog1 = new Dog("Dog 1"); dog1.shout();
運行以後報錯:Uncaught TypeError: Object #<Dog> has no method 'shout'this
實際上,new Dog()的過程等價於spa
var o = {__proto__: Dog.prototype}; Dog.apply(o); return o;
而JS引擎在遇到函數聲明的時候會給函數對象添加prototype屬性,即Dog.prototype = {constructor: Dog},運行到new Dog(...)時,prototype
執行的操做至關於code
// Dog.prototype = {constructor: Dog}; var o = {__proto__: Dog.prototype}; // 如今,o = {__proto__: {constructor: Dog}} Dog.apply(o); // 如今,Dog.prototype = {shout: function(){...}} return o;
因此,dog1.shout()會報錯也是情理之中的事情。對象
2、探索blog
雖然dog1沒有shout()方法,可是目前Dog的prototype已是{shout: function(){...}}繼承
因此此時再寫2句var dog2 = new Dog('xxx');dog2.shout();就能夠正常執行了原型
總的來講,上面的構造函數還都是比較規範的,下面咱們作一點改變,在構造函數里加一句return 語句
function a() { this.name = 'joe'; return {name: 'ray'}; } var obj = new a(); alert(obj.name); //ray
運行的結果是ray,因而可知,new a()生成的a對象被拋棄,返回的是return語句後面的對象
下面咱們再來作一個實驗
function a() { this.name = 'joe'; return 'ray'; } var obj = new a(); alert(obj.name); //joe alert(obj); //[object Object]
這回obj.name的值是joe,並且obj是一個對象,說明new a()生成的a對象並無被拋棄
3、小結
事實上,在使用new Func()來生成一個對象的時候, 整個過程是這樣的:
一、建立一個新對象,它的類型是Func,而且它會繼承Func.prototype的全部屬性(原型繼承)
二、構造函數被調用,this對象被綁定給這個新建立的對象
三、若構造函數沒有明確的返回值,那麼新建立的對象就是整個 new
表達式的結果;反之,若構造函數內顯式定義了返回值,則該返回值爲整個 new
表達式的結果