《JavaScript: The Definitive Guide》web
call()和apply()的第一個實參是要調用函數的母對象,它是調用上下文,在函數體內經過this來得到對它的引用。簡單來講就是把一個方法綁定到一個對象上去調用:編程
慄如,要想以對象o的方法來調用函數f():數組
f.call(o); f.apply(o);
其實至關於:閉包
o.m = f; //將f存儲爲o的臨時方法 o.m(); //調用它,不傳入參數 delete o.m; //將臨時方法刪除
--> 對於call(),第一個實參以後的全部實參就是要傳入待調用函數的值。慄如:app
//以對象o的方法的形式調用函數f(),並傳入兩個參數 f.call(o, 1, 2);
--> 對於apply(),它的實參都放入一個數組當中:ide
f.apply(o,[1, 2]);
給apply()傳入的參數數組能夠是任意長度的,慄如:函數式編程
//找出一個數組中最大的數值元素 var biggest = Math.max.apply(Math, array_of_numbers);
傳入apply()的參數數組能夠是類數組對象也能夠是真實數組。實際上,能夠將當前函數的arguments數組直接傳入apply()來調用另外一個函數:函數
//將對象o中名爲m的方法替換爲另外一個方法 //能夠在調用原始方法以前和以後記錄日誌消息 function trace(o, m) { var original = o[m];//在閉包中保存原始方法 o[m] = function() {//定義新的方法 console.log(new Date(), 'Entering', m); var result = original.apply(this, arguments);//調用原始函數 console.log(new Date(), 'Exiting', m); return result; }; } //這個新方法是包裹原始方法的另外一個泛函數 (monkey-patching)?
bind()是ES5中的方法。
當在函數f()上調用bind()方法並傳入一個對象o做爲參數,這個方法將返回一個新的函數,(以函數調用的方式)調用新的函數將會把原始的函數f()看成o的方法來調用。傳入新的函數的任何實參都講傳入原始函數。慄如:ui
function f(y) { return this.x + y; } var o = { x: 1 }; var g = f.bind(o); g(2); //=> 3
能夠用ES3簡單模擬:this
function bind(f, o) { if(f.bind) return f.bind(o); else return function() { return f.apply(o, arguments); } }
然而,bind()方法不單單是將函數綁定至一個對象----除了第一個參數外,傳入bind()的實參也會綁定至this,這個附帶的應用是一種常見的函數式編程技術,也被稱爲「柯里化「。
function f(y, z) { return this.x + y + z } var g = f.bind({ x: 1 }, 2); g(3);//=> 6 this.x綁定到1, y綁定到2, z綁定到3
若是用ES3模擬:
if(!Function.prototype.bind){ Function.prototype.bind = function(o /*, args*/){ //將this和arguments的值保存至變量中 //以便在後面嵌套的函數中能夠使用它們 var self = this, boundArgs = arguments; //bind方法的返回值是一個函數 return function(){ //建立一個實參列表,將傳入bind()的第二個及後續的實參傳入這個參數 var args = [], i; for(i=1; i<boundArgs.length; i++){ args.push(boundArgs[i]; } for(i=0;i<arguments.length;i++){ args.push(arguments[i]; } //如今將self做爲o的方法來調用,傳入這些實參 return self.apply(o, args); }; }; }
http://web.jobbole.com/83642/
深刻淺出妙用 Javascript 中 apply、call、bind
一個比較:
var obj = { x: 81, }; var foo = { getX: function() { return this.x; } } console.log(foo.getX.bind(obj)()); //81 console.log(foo.getX.call(obj)); //81 console.log(foo.getX.apply(obj)); //81
三個輸出的都是81,可是注意看使用 bind() 方法的,他後面多了對括號。
也就是說,區別是,當你但願改變上下文環境以後並不是當即執行,而是回調執行的時候,使用 bind() 方法。而 apply/call 則會當即執行函數。
一個總結:
apply 、 call 、bind 三者都是用來改變函數的this對象的指向的;
apply 、 call 、bind 三者第一個參數都是this要指向的對象,也就是想指定的上下文;
apply 、 call 、bind 三者均可以利用後續參數傳參;
bind 是返回對應函數,便於稍後調用;apply 、call 則是當即調用 。
一道題:
定義一個 log 方法,讓它能夠代理 console.log 方法
function log(){ console.log.apply(console, arguments); }
若要給每個 log 消息添加一個」(app)」的前輟?
//該怎麼作比較優雅呢?這個時候須要想到arguments參數是個僞數組,經過 //Array.prototype.slice.call 轉化爲標準數組,再使用數組方法unshift function log(){ var args = Array.prototype.slice.call(arguments); args.unshift('(app)'); console.log.apply(console, args); }