call()
、apply()
、bind()
方法的做用都是改變函數運行時this的指向。 bind()
是返回對應的函數,便於稍後調用;call()
和apply()
則是當即調用。數組
相同點app
兩者做用徹底相同,只是接收參數上的不一樣。若是不傳入第一個參數,則默認上下文是 window
。函數
call
Function.prototype.myCall = function(context, ...args) { if( typeof this !== 'function') { throw new TypeError('Error') // 判斷是不是函數調用 } context = context ? Object(context) : window // 原始值的this會指向該原始值的實例對象 所以須要Object轉換成對象類型 context.fn = this // 函數的this指向隱式綁定到context上 const result = context.fn(...args) // 經過隱式綁定函數並傳遞參數 delete context.fn // 刪除上下文對象的屬性 return result // 返回函數執行結果 }
示例this
let test = { name: "test" } let fun = { fn: function () { console.log(this.name) } } fun.fn.myCall(test) // test
apply
注意: 上述指定的this值(thisArg)並不必定是該函數執行時真正的this值,若是該函數處於 非嚴格模式下,則指定爲null或者undefined時會自動指向全局對象(瀏覽中就是window對象),同時值爲原始值(number、string、boolean)的this會指向該原始值的自動包裝對象。
Function.prototype.myApply = function(context) { if( typeof this !== 'function' ) { throw new TypeError('Error') } context = context ? Object(context) : window context.fn = this let result if(arguments[1]) { // 處理參數上和call有區別 result = context.fn(...arguments[1]) } else { result = context.fn() } delete context.fn return result }
示例prototype
function fn() { console.log(this.age) } let person = { age: 12 } fn.myApply(person) // 12
bind
方法會建立一個新函數,稱爲綁定函數,當調用這個綁定函數時,綁定函數會以建立它時傳入bind()
的第一個參數做爲this
,傳入bind
方法的 其餘參數以及和綁定函數運行時自己的參數 ,將按照順序做爲原函數的參數來調用原函數。code
new
操做符調用綁定函數時,該參數無效。Function.prototype.myBind = function(context) { if( typeof this !== 'function' ) { throw new TypeError('Error') } let args = [...arguments].slice(1) // bind 函數中的參數 let self = this // 保存原函數 return function() { return self.apply(context, args.concat(...arguments)) // arguments 是外部函數傳入的 } }
示例對象
let obj = { a: 'a' }; function f(b, c, d) { console.log(this.a, b, c, d) } f.myBind(obj, 'b')('e') // a b e undefined f.myBind(obj, 'b', 'c')('e') // a b c e f.myBind(obj, 'b', 'c', 'd')('e') //a b c d