淺談Javascript的new運算符

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 表達式的結果

相關文章
相關標籤/搜索