2016年6月22日 星期三

[筆記] 談談JavaScript中的function constructor和關鍵字new


在前幾篇的筆記中,我們已經對於物件(object)、原型(prototype)、繼承(inheritance)和原型鏈等等有更多的了解,現在讓我們來更深入的談論一下JavaScript中建立物件的方法。

先前我們有說明使用object literal,也就是大括號的方式來建立物件,或者是使用 new Object( ) 的方式,但除此之外,我們還可以使用函式建構式(function constructor)的方式來建立物件。但在開始深入了解之前,讓我們先來簡單談一下JavaScript發展的歷史,如此我們將更清楚為什麼會使用這樣的方式。

new和JavaScript的關係史


JavaScript是由一個叫做Brendon Eich所開發的,就像現在有Google VS. Apple,在當時也有很多不同的程式語言之間在競爭,而之所以這個語言會叫做JavaScript其中一個原因是當初宣傳這套語言時,想要吸引使用JAVA的程式開發者,這就很像微軟發展了VBScript,之所以稱作VBScript也是因為想要吸引使用Visual Basic的程式開發者。

JavaScript雖然聽起來或看起來和JAVA很像,但實際上可以說是非常的不同,然而,當初在推廣JavaScript這套語言的時候,為了讓它和JAVA有更多的相似性,因此用了和JAVA相似的語法 var XXX = new ooo( ) ,這樣的方式在JAVA中可以根據某個類別(class)來建立物件,但在JavaScript中並沒有真正的class這樣的東西,這麼做的目的只是為了讓JAVA的使用者在看到JavaScript的時候覺得有股熟悉感。

在了解這段小歷史之後讓我們進一步來看function constructor 和 new 。

談談函式建構式(function constructor)


我們先建立一個函式,名稱叫做 Person,要注意的是我們在第9行的地方是使用 new 這個關鍵字,後面放的則是 function Person:

function Person(){

    this.firstname = 'John';
    this.lastname = 'Doe';

}

var john = new Person();
console.log(john);


接著我們把John呼叫出來看,會得到如下的結果,它會幫我們建立一個物件,然後裡面有Person這個function裡面的內容,並且變成了屬性名稱和屬性值:


進一步來看new讓這個過程發生了什麼


在JavaScript中 "new" 這個關鍵字其實是眾多運算子(operators)的其中一種:

圖片來源:MDN Operator Precedence

當我們使用new這個關鍵字時,實際上會先有一個空的物件被建立。

接著People這個函式會被執行(invoke)。我們知道當函式執行的時候,在execution context中會有this被建立,而當我們使用new的時候,函式裡面的this會被指定成剛剛所建立的那個空物件。

所以當執行People這個function,執行到 this.firstnamethis.lastname 時,因為this現在指稱的是那個空物件,所以實際上是在幫這個空物件賦予屬性名稱和屬性值。

在這樣的過程中,只要這個函式建構式 People 沒有指定return為其他物件,它就會直接回傳給我們這個新建立的物件。

接著讓我們透過程式碼來更清楚的了解這個執行的過程:

該函式有被執行(invoke)

讓我們在原本的程式中加入第6行的內容:

function Person(){

    this.firstname = 'John';
    this.lastname = 'Doe';
    console.log('這個函式有被執行');

}

var john = new Person();
console.log(john);


這時候在chrome中呼叫出來的結果如下,說明了當我們使用 new 在建構物件的時候People這個function確實有被執行:


透過new會幫我們建立一個空的物件

現在我把我們原本的程式碼改成這樣:

function Person(){

    console.log(this);

}

var john = new Person();
//    console.log(john);


這時候程式碼回傳的結果如下,表示的確在執行這個程式的過程中幫我們建立了一個新的空物件:


函式的最後若return其他物件,則原新物件內容會被覆蓋

現在,讓我們把原本的程式碼稍微做如下修改,增加第六行的內容:

function Person(){

    this.firstname = 'John';
    this.lastname = 'Doe';
    return  {"RETURN":"原本this的內容就不會被回傳"};

}

var john = new Person();
console.log(john);


回傳的結果如下,原本被建立的新物件不會被回傳,而是回傳我們最後return給它的內容:


function constructor的實際應用


由上面的方法,我們可以透過function的方式來建立一個新的物件,如果我們想要建立出同屬性名稱但不同屬性值的物件內容,我們可以把物件的屬性值變成參數,如此就能透過此function constructor建立出許多不同的物件:

function Person(firstname, lastname){

    this.firstname = firstname;
    this.lastname = lastname;

}

var john = new Person('John', 'Doe');
console.log(john);
var jane = new Person('Jane', 'Doe');
console.log(jane);


如此,我們就可以透過同一個函式建構式建立出很多不同的物件:


此外,我們會把根據建構子(constructor)所建立出來的物件稱作是例子(insatnce)
透過建構子(constructor)所建立出來的物件,我們稱為例子(instance)


注意!如果我們忘了加上關鍵字new


這裡有一個地方我們需要非常留意,如果你在程式撰寫的過程當中,忘記加上 new 這個關鍵字的話,例如:

  var john = Person('John', 'Doe');
  console.log(john);


如此,因為JavaScript不知道你是要執行這個程式還是要根據這個function去建立object,因次最後回傳 undefined 的結果。


最後,讓我們總結一下function constructors


其實function constructor就是普通的function,只是我們可以透過這個function來建立物件。

透過在function前面加上new這個運算子,它會把函式中this這個關鍵字建立成一個新的物件,然後如果你沒有在該函式的最後指定回傳出其它物件的話,它就會自動回傳這個新的物件給你。

那....如何透過function constructors來設定我們的原型(prototype)呢?讓我們在下一篇筆記來談吧!

程式範例

function Person(firstname, lastname){

    this.firstname = firstname;
    this.lastname = lastname;
}

var john = new Person('John', 'Doe');
console.log(john);

var jane = new Person('Jane', 'Doe');
console.log(jane);


→回到此系列文章目錄


Share:

0 意見:

張貼留言