bind call apply 的區別和使用:https://www.jianshu.com/p/015f9f15d6b3javascript
在講這個以前要理解一些概念,這些概念很重要,有人說過學會了javascript 的this 就基本會了一半的javascripthtml
在 javascript 中,call 和 apply 都是爲了改變某個函數運行時的上下文(context)而存在的,換句話說,就是爲了改變函數體內部 this 的指向。java
定義時上下文
運行時上下文
上下文是能夠改變面試
若是要深刻理解這個知識要開個javascript 內存管理機制和運行原理了,這裏就不作過多的介紹了。數組
function Fruits() {} Fruits.prototype = { color: "red", printf: function() { console.log("My color is " + this.color); } } var apple = new Fruits; apple.printf(); //My color is red // 改變this banana = { color: "yellow" } apple.printf.call(banana); //My color is yellow apple.printf.apply(banana); //My color is yellow // 經過call apply這兩個來改變上下文的this指向
call ,apply 方法是同樣的只是傳遞的參數不一樣而已,call(obj,args1,args2)
apply(obj,[args1,args2]) ,這樣很明顯看出區別了吧!app
var array1 = [12 , "foo" , {name "Joe"} , -2458]; var array2 = ["Doe" , 555 , 100]; Array.prototype.push.apply(array1, array2); /* array1 值爲 [12 , "foo" , {name "Joe"} , -2458 , "Doe" , 555 , 100] */ // 這樣子優雅的解決了push 方法子傳遞一個參數的問題了。固然數組合並有contact 方法來合併的 // 比較數組的大小,使用 apply 做爲傳遞數組的必選方法。 var numbers = [5, 458 , 120 , -215 ]; var maxInNumbers = Math.max.apply(Math, numbers), //458 maxInNumbers = Math.max.call(Math,5, 458 , 120 , -215); //458 // 判斷是不是數組 前提是toString 方法沒有被重寫。 functionisArray(obj){ return Object.prototype.toString.call(obj) === '[object Array]' ; } // 將僞數組轉成數組 // ES6 有方法 Array.from(args) 轉化 var dom = Array.prototype.slice.call(document.getElementsByTagName("div")); // 這樣 domNodes 就可使用pop() ,push() 等方法了。
封裝console.log 方法dom
function log(){ console.log.apply(console, arguments); }; log(1); //1 log(1,2); //1 2 // 這是一道面試題這樣的方法能夠說是最優雅的了 // 我也是今天才知道他們兩能力這麼大 function log(){ var args = Array.prototype.slice.call(arguments); var tim = new Date.getTime() args.unshift(tim); console.log.apply(console, args); }; // 這個就能夠優雅的給log 方法帶上一個時間搓的前綴啦,是否是很是的棒。函數的不定參 arguments 是僞數組來的 //寫了這麼多相信各位已經明白了,我如今才知道這兩個方法的強大,之前一直認爲只是改變this這麼簡單,其實也改變this啊!
再來講說bind。bind() 方法與 apply 和 call 很類似,也是能夠改變函數體內 this 的指向。函數
個人解釋是:bind()方法會建立一個新函數,稱爲綁定函數,當調用這個綁定函數時,綁定函數會以建立它時傳入 bind()方法的第一個參數做爲 this,傳入 bind() 方法的第二個以及之後的參數加上綁定函數運行時自己的參數按照順序做爲原函數的參數來調用原函數。ui
直接來看看具體如何使用,在常見的單體模式中,一般咱們會使用 _this , that , self 等保存 this ,這樣咱們能夠在改變了上下文以後繼續引用到它。 像這樣:this
var foo = { bar : 1, eventBind: function(){ var _this = this; $('.someClass').on('click',function(event) { /* Act on the event */ console.log(_this.bar); //1 }); } } // 使用 bind 方法 var foo = { bar : 1, eventBind: function(){ $('.someClass').on('click',function(event) { /* Act on the event */ console.log(this.bar); //1 }.bind(this)); } } // 多個bind var bar = function(){ console.log(this.x); } var foo = { x:3 } var sed = { x:4 } var func = bar.bind(foo).bind(sed); func(); //? var fiv = { x:5 } var func = bar.bind(foo).bind(sed).bind(fiv); func(); //3 第一個值,第二個失效了
Function.prototype.bind= function(obj){ if (Function.prototype.bind) return Function.prototype.bind; var _self = this, args = arguments; return function() { _self.apply(obj, Array.prototype.slice.call(args, 1)); } } // 可能你們會有疑惑,這裏爲何return 一個函數回去,由於bind()不是調用就執行的因此在這裏返回一個函數。 // MDN的方法 if (!Function.prototype.bind) { Function.prototype.bind = function(oThis) { if (typeof this !== 'function') { // closest thing possible to the ECMAScript 5 // internal IsCallable function throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable'); } var aArgs = Array.prototype.slice.call(arguments, 1), fToBind = this, fNOP = function() {}, fBound = function() { return fToBind.apply(this instanceof fNOP ? this : oThis, // 獲取調用時(fBound)的傳參.bind 返回的函數入參每每是這麼傳遞的 aArgs.concat(Array.prototype.slice.call(arguments))); }; // 維護原型關係 if (this.prototype) { // Function.prototype doesn't have a prototype property fNOP.prototype = this.prototype; } fBound.prototype = new fNOP(); return fBound; }; } // 也就是加了比較嚴格的判斷。
從bind 的源碼中能夠看出跟 call ,apply 的卻別了吧!
bind調用完成後不執行,call,apply是立刻執行。相互之間是互通的
bind不兼容(IE5,6,7,8)
參考文獻:
http://www.javashuo.com/article/p-bywxlvak-dk.html
https://blog.csdn.net/u012443286/article/details/78633540