前兩天在作小程序的需求的時候用到bind的時候纔想起本身對這三的東西的瞭解比較淺薄,這個時候用的時候就有點怕。時候仍是要好好學習下,理解下怎麼玩。面試
先說call
和 apply
吧:
ECMAScript3給Function的原型定義了兩個方法,他們是Function.prototype.call
和 Function.prototype.apply
. 在實際開發中,特別是在一些函數式風格的代碼編寫中,call和apply方法尤其有用。小程序
一、call和apply區別數組
其實他們的做用是同樣的,只是傳遞的參數不同而已。
apply: 接受2個參數,第一個參數指定了函數體內this對象的指向,第二個參數爲數組或者一個類數組。apply傳入的是一個參數數組,也就是將多個參數組合成爲一個數組傳入,而call則做爲call的參數傳入(從第二個參數開始)。
舉個栗子:app
let obj1 = { name: "copyes", getName: function(){ return this.name; } } let obj2 = { name: 'Fanchao' } console.log(obj1.getName()); // "copyes" console.log(obj1.getName.call(obj2)); // "Fanchao" console.log(obj1.getName.apply(obj2)); // "Fanchao"
function showArgs(a, b, c){ console.log(a,b,c); } showArgs.call(this, 3,4,5); showArgs.apply(this, [5,6,7]);
二、常見的call 和 apply 用法dom
數組之間追加函數
let arr1 = [12, 'foo', {name: 'fanchao'}, -1024]; let arr2 = ['copyes', '22', 1024]; Array.prototype.push.apply(arr1, arr2); console.log(arr1); // [ 12, 'foo', { name: 'fanchao' }, -1024, 'copyes', '22', 1024 ]
獲取數組中的最大值和最小值學習
let numbers = [5,665,32,773,77,3,996]; let maxNum = Math.max.apply(Math, numbers); let maxNum2 = Math.min.call(Math, 5,665,32,773,77,3,996); console.log(maxNum); console.log(maxNum2);
驗證是不是數組(前提是toString()方法沒有被重寫過)this
function isArray(obj){ return Object.prototype.toString.call(obj) === '[object Array]'; } console.log(isArray(1)); console.log(isArray([1,2]));
類(僞)數組使用數組方法prototype
var domNodes = Array.prototype.slice.call(document.getElementsByTagName("*"));
三、經過一個面試題去深刻理解下apply 和 call代理
定義一個 log 方法,讓它能夠代理 console.log 方法:
// 常規作法 function log(msg){ console.log(msg); } log(12); log(1,2)
上面可以基本解決打印輸出問題,可是下面多參數的時候就gg了。換個更好的方式吧。
function log(){ console.log.apply(console, arguments); } log(12); log(1,2)
接下來是要在每一條打印信息前面都要加上一個特定字符串'fanchao`s'又怎麼說呢?
function log(){ let args = Array.prototype.slice.call(arguments); args.unshift('(fanchao`s)'); console.log.apply(console, args); } log(12); log(1,2)
四、說完了call和apply,接下來講說bind
bind() 方法與 apply 和 call 很類似,也是能夠改變函數體內 this 的指向。
MDN的解釋是:bind()方法會建立一個新函數,稱爲綁定函數,當調用這個綁定函數時,綁定函數會以建立它時傳入 bind()方法的第一個參數做爲 this,傳入 bind() 方法的第二個以及之後的參數加上綁定函數運行時自己的參數按照順序做爲原函數的參數來調用原函數。
看個栗子:
var func = function(){ console.log(this.x); console.log(arguments); } func(); // undefined, {} var obj = { x: 2 } var bar = func.bind(obj,1); bar(); // 2 , {'0':1}
一個有意思的事:
var bar = function() { console.log(this.x); } var foo = { x: 3 } var sed = { x: 4 } var func = bar.bind(foo).bind(sed); func(); //3 var fiv = { x: 5 } var func = bar.bind(foo).bind(sed).bind(fiv); func(); //3
在Javascript中,屢次 bind() 是無效的。更深層次的緣由, bind() 的實現,至關於使用函數在內部包了一個 call / apply ,第二次 bind() 至關於再包住第一次 bind() ,故第二次之後的 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
看到bind後面對了一對括號。區別是,當你但願改變上下文環境以後並不是當即執行,而是回調執行的時候,使用 bind() 方法。而 apply/call 則會當即執行函數。
apply 、 call 、bind 三者都是用來改變函數的this對象的指向的;apply 、 call 、bind 三者第一個參數都是this要指向的對象,也就是想指定的上下文;apply 、 call 、bind 三者均可以利用後續參數傳參;bind是返回對應函數,便於稍後調用;apply、call則是當即調用 。