Javascript Function Invocation



Javascript Function Invocation Patterns 有以下四種方式:
  1. Method Invocation
  2. Function Invocation
  3. Constructor Invocation
  4. Apply And Call Invocation
為什麼要瞭解這是四個有什麼不同呢?接著看就知道了。

Function Execution

function在執行的範圍內的任何地方都可以被呼叫。當我們呼叫了
一個function他就會暫時停止目前的function的執行,並且傳遞參數
和控制的訊息到被呼叫的function。

在呼叫function有不同的方式,但這些不同的方式會產生不一樣的結果作者是認為是在設計javascript時的錯誤。所以最好將這四種方式都瞭解對你在撰寫javascript時才不會太多的問題。

The Four Invocation Patterns

1. Method Invocation
當一個functiion是object的一部分的話,他稱之為方法(method)。
範例:
var obj = {
    value: 0,
    increment: function() {
        this.value+=1;
    }
};

obj.increment(); //Method invocation

increment就是obj的方法,當obj的方法被呼叫後javascript會設定this這個關鍵字指向obj。所以看上面的範例當我們要在increment去讀寫obj的value變數的話,就要寫成this.value。


2. Function Invocation

add(2,3) <== 這樣寫法就是Function Invocation

當我們使用function Invocation的時候,this是被設定為global object而且是指向window object 這是JavaScript設計上的錯誤,一旦不小心寫錯很容易就可以將 global object的內容給破壞掉。

再inner function中這樣的錯誤是很容易出現的,我們可以看一下範例:

var value = 500; //Global variable
var obj = {
    value: 0,
    increment: function() {
        this.value++;

        var innerFunction = function() {
            alert(this.value);
        }

        innerFunction(); //Function invocation pattern
    }
}
obj.increment(); //Method invocation pattern

從這個範例來看你認為innerFunction()會跳出怎樣的答案呢?認為是1的話你就錯了正確答案是500。所以inner function是用function invocation的方式來被呼叫,所以this是被設定成global物件,而不是目前的物件。因此inner function中的this.value的值就是500。

如果要解決這個問題,作者也提供了一個範例:

var value = 500; //Global variable
var obj = {
    value: 0,
    increment: function() {
        var that = this;
        that.value++;

        var innerFunction = function() {
            alert(that.value);
        }

        innerFunction(); //Function invocation pattern
    }
}
obj.increment();

就是用變數that來取代this這樣就可以了,為什麼這樣可以呢?因為JavaScript是closures至於closures是什麼呢?可以看一下這個連結http://doctrina.org/JavaScript:Why-Understanding-Scope-And-Closures-Matter.html#closures (有空再來寫什麼是closures)。

3. Constructor Invocation

JavaScript不是標準的物件導向語言,而是原型物件導向語言(prototypical object oriented language) ,在標準的物件導向,物件是類別的實例。在C++跟Java ,實例是藉由new來產生。

JavaScript也是用new來產生,而constructor invocation也是再這個時候會被呼叫,來看個例子吧:

var Cheese = function(type) {
    var cheeseType = type;
    return cheeseType;
}

cheddar = new Cheese("cheddar"); //new object returned, not the type.

儘管Cheese是一個function物件,我們需要利用new來呼叫function來建立一個新的物件。
this將會設定到新的物件上。
 
1. 假如function回傳一個簡單的型態(像是number,string,boolean,null or undefined),
哪麼回傳的資料將被忽略,取代的是回傳this(新的object)
 
2. 假如function回傳一個object的實例,那麼接著他會回傳object來取代this

範例:
var obj = {
    data : "Hello World"
}

var Func1 = function() {
    return obj;
}

var Func2 = function() {
    return "I am a simple type";
}

var f1 = new Func1(); //f1 is set to obj
var f2 = new Func2(); //f2 is set to a new object

4. Apply And Call Invocation


apply跟call的使用方式是一樣的,不同是在於傳遞變數時,一個是用陣列另一個是用參數
並且要明確的設定this。
範例1:
var add = function(num1, num2) {
        return num1+num2;
}

array = [3,4];
add.apply(null,array); //7

第一個參數設為null(這個function不是object,所以並不需要傳object進去),接著是array傳遞到num1跟num2中(用appay才能這樣做,call不行)

範例2:
var obj = {
    data:'Hello World'
}

var displayData = function() {
    alert(this.data);
}

displayData(); //undefined
displayData.apply(obj); //Hello World

這個範例就看的出來我們可以利用apply來綁住this跟obj來讓我們使用。

張貼留言

這個網誌中的熱門文章

解釋scope.$apply用來做什麼? -- AngularJS

Unions 在C語言的簡單介紹

JavaScript的Timer用法