前言
對於函數綁定(Function binding)很有可能是大家在使用JavaScript時最少關注的一點,但是當你意識到你需要一個解決方案來解決如何在另一個函數中保持this上下文的時候,你真正需要的其實就是 Function.prototype.bind()
,只是你有可能仍然沒有意識到這點。
第一次遇到這個問題的時候,你可能傾向於將this設置到一個變量上,這樣你可以在改變了上下文之後繼續引用到它。
一. bind的語法
bind()
方法的主要作用就是將函數綁定至某個對象,bind()
方法會創建一個函數,函數體內this對象的值會被綁定到傳入bind()
函數的值。
1.1 定義
bind()的定義如下:
The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.
bind() 函數會創建一個新函數(稱為綁定函數),新函數與被調函數(綁定函數的目標函數)具有相同的函數體。當目標函數被調用時 this 值綁定到 bind()
的第一個參數,該參數不能被重寫。
1.2 原理
可以用如下代碼模擬bind()
的原理:
Function.prototype.bind = function(context) { var self = this; // 保存原函數 return function() { // 返回一個新函數 return self.apply(context, arguments); // 執行新函數時,將傳入的上下文context作為新函數的this } }
1.3 語法
Function.prototype.bind(thisArg[, arg1[, arg2[, ...]]])
二. bind的應用場景
2.1 實現對象繼承
var A = function(name) { this.name = name; } var B = function() { A.bind(this, arguments); } B.prototype.getName = function() { return this.name; } var b = new B("hello"); console.log(b.getName()); // "hello"
2.2 事件處理
var paint = { color: "red", count: 0, updateCount: function() { this.count++; console.log(this.count); } }; // 事件處理函數綁定的錯誤方法: document.querySelector('button') .addEventListener('click', paint.updateCount); // paint.updateCount函數的this指向變成了該DOM對象 // 事件處理函數綁定的正確方法: document.querySelector('button') .addEventListener('click', paint.updateCount.bind(paint)); // paint.updateCount函數的this指向變成了paint
2.3 時間間隔函數
var notify = { text: "Hello World!", beforeRender: function() { alert(this.text); }, render: function() { // 錯誤方法: setTimeout(this.beforeRender, 0); // undefined // 正確方法: setTimeout(this.beforeRender.bind(this), 0); // "Hello World!" } }; notify.render();
2.4 借用Array的原生方法
var a = {}; Array.prototype.push.bind(a, "hello", "world")(); console.log(a); // "hello", "world"
三. bind()方法的浏覽器兼容性
四. bind()的兼容性寫法
if (!Function.prototype.bind) { Function.prototype.bind = function() { var self = this, // 保存原函數 context = [].shift.call(arguments), // 需要綁定的this上下文 args = [].slice.call(arguments); // 剩余的參數轉成數組 return function() { // 返回一個新函數 // 執行新函數時,將傳入的上下文context作為新函數的this // 並且組合兩次分別傳入的參數,作為新函數的參數 return self.apply(context, [].concat.call(args, [].slice.call(arguments))); } }; }
五. bind與 call/apply方法的區別
共同點:
都可以改變函數執行的上下文環境;
不同點:
bind: 不立即執行函數,一般用在異步調用和事件; call/apply: 立即執行函數。
總結
好了,以上就是這篇文章的全部內容了,希望本文的內容對大家學習或者使用Javascript能有一定的幫助,如果有疑問大家可以留言交流。