1. 程式人生 > >整理JavaScript的Call和Apply區別

整理JavaScript的Call和Apply區別

function classA() { 
    this.name='bluedestiny'; 
    this.show = function () { 
//        alert(this.name); 
    } 
} 
function classB() { 
    this.name = 'never-online'; 

} 

var objA = new classA(); 
var objB = new classB(); 

//call 方法以另一個物件替換當前物件 
//也就是說把objA物件的方法show給於objB物件來執行
objA.show.call(objB);

function methods(a,b) {
	
	return arguments[0] + arguments[1] + a + b;
} 
//applyy第一個引數是當前物件,第二個引數是一個數組(methods的引數)
var Result = methods.apply(this,["BBBB","CCC"]);
alert(Result);

//call第一個引數是當前物件,第二個以後的引數(methods的引數)
Result = methods.call(this,"BBBB","CCC");

alert(Result);


var Class = {

  create: function() {

	//當呼叫這個物件後並賦值給一個變數且通過new 變數(),那麼function就是一個建構函式
    return function() {

      this.initialize.apply(this, arguments);

    }

  }

};
var vehicle=Class.create();

vehicle.prototype={

    initialize:function(type){
        this.type=type;

    },

    showSelf:function(){

        alert("this vehicle is "+ this.type);

    }

}
//通過new 關鍵字呼叫的函式就稱為建構函式
var moto=new vehicle("Moto");
//所以moto物件也會有initialize方法,不只如此,每一個有vehicle構造出來的物件都會有一個initialize方法,而在前面說過,構造的時候會呼叫建構函式,建構函式裡面會讓initialize去呼叫apply方法,於是在new A(‘helloWord!')的時候initialize回去呼叫apply方法。這也就是呼叫了一個初始化的方法。
moto.showSelf();
//this.initialize.apply(this , arguments); 
//這裡的第一個this,是指用new呼叫建構函式之後生成的物件,也就是前面的a,那麼第二個this也當然應該是指同一個物件。那這句話就是this(也就是a)呼叫initialize方法,引數是arguments物件(引數的陣列物件),所以在建構函式執行的時候,物件a就會去執行initialize方法來初始化,這樣就和單詞“initialize”的意思對上了。 



// 活用apply(javascript框架prototype的事件繫結):
Function.prototype.bind = function() {

  var __method = this;  

  var args = $A(arguments);  

  var object = args.shift();

  return function() {  

    // 呼叫函式的apply方法執行函式, 其中的object為目標物件, args為bind方法中的引數列表(除了第一個引數以外的引數構成的陣列)

    return __method.apply(object, args.concat($A(arguments)));// 事實上, 這裡的$A(arguments)一定是一個空陣列

  }

}
//程式碼解析:

//該bind用途在於將某個函式繫結到特定的函式去執行,

//a) var __method = this;這首先把Function Context重新賦值到一個本地變數,使得在Closure(這是一個javascript的特性,可解釋為"閉包")中都能訪問到,如此在下邊就可以方便獲取了。它實質就是bind方法的呼叫者, 是一個函式物件。

//b) var args = $A(arguments);這裡因為arguments本就是一個類陣列的物件,通過$A(arguments)將傳入到bind方法的引數都轉化為array.

//c) var object = args.shift();通過擷取args的第一個引數獲取Target Object(目標物件),此時args為除了第一個引數以外的引數構成的陣列(array)

//d) 這是最關鍵的一步,返回一個新的函式物件(不帶有任何的引數的函式),在此通過apply把__method(bind方法的呼叫者)繫結到Target Object(目標物件),並給與除了Target Object(目標物件)之外的所有引數構成的陣列args.concat($A(arguments)),最終Target Object(目標物件)就可執行__method了。

//如此費勁周折的繫結某一個函式所換來的優勢是,從此你不需要顧及Function Context的混亂所帶來的額外顧慮。


var ClassName = function(v){ 
    this.value=v; 
    this.getValue=function(){ 
        return this.value; 
    } 
    this.setValue=function(v){ 
        this.value=v; 
    } 
}

var objectName1 = new ClassName(“a”);//得到一個物件

//其中objectName1就是執行ClassName建構函式後得到的物件,而在ClassName函式中的this指的就是new之後構造出來的物件,所以objectName1會後一個屬性和兩個方法。可以通過這樣來呼叫他們:
//程式碼如下:
objectName1.setValue(''hello''); 
alert(objectName1.getValue());//對話方塊hello 
alert(objectName1.value) ;//對話方塊hello

var objectName2 = ClassName(“b”);//得到一個物件
//這樣objectName2得到的是什麼呢?顯然是方法的返回值,這裡ClassName只作為了一個普通的函式(雖然首字母大寫了)。但是在之前寫的ClassName中並沒有返回值,所以objectName2會是undifinded那麼“b”賦給誰了呢?在這並沒有產生一個物件,而只是單純的執行這個方法,所以這個“b”賦值給了呼叫這個方法的物件window,證據如下: 
var objectName2 = ClassName(“b”);//得到一個物件 
alert(window.value);//對話方塊b