整理JavaScript的Call和Apply區別
阿新 • • 發佈:2019-02-19
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