JS的call,apply與bind詳解,及其模擬實現

call, apply 與 bind

1.call() 與 apply()

call或apply會自動執行對應的函數

fun.call(thisNew[, arg1[, arg2[, ...]]])
fun.apply(thisNew[, argsArray])

thisNew: fun函數運行時指定的this值,可能的值爲:

  • 不傳,或者傳null,undefined, this指向window對象
  • 傳遞另一個函數的函數名fun2,this指向函數fun2的引用
  • 值爲原始值(數字,字符串,布爾值),this會指向該原始值的自動包裝對象,如 String、Number、Boolean
  • 傳遞一個對象,函數中的this指向這個對象

用例:

call:

window.name = 'windowName'
var obj = {
  name: 'objName'
}
function getName(p1, p2) {
  console.log('name === ', name)
  console.log('p1 === ', p1)
  console.log('p2 === ', p2)
}
getName('str1', 'str2')
getName.call(obj, 'str1', 'str2')

apply:

Math.max.apply(null, [2, 3, 1, 4])

2.bind()

bind()方法會創建一個新函數,稱爲綁定函數。bind是ES5新增的一個方法,不會執行對應的函數,而是返回對綁定函數的引用。

fun.bind(thisNew[, arg1[, arg2[, ...]]]);

用例:

var $ = document.querySelectorAll.bind(document)

3.三者異同

相同:

  • 改變函數體內 this 的指向

不同:

  • call、apply的區別:接受參數的方式不一樣
  • bind不立即執行。而apply、call 立即執行

4.模擬實現

call:

Function.prototype.customCall = function () {
  if (typeof this !== 'function') {
    throw new TypeError('error!')
  }
  let context = arguments[0] || window
  context.fn = this
  let args = [...arguments].slice(1)
  let result = context.fn(...args)
  delete context.fn
  return result
}

apply:

Function.prototype.customApply = function () {
  if (typeof this !== 'function') {
    throw new TypeError('error!')
  }
  let context = arguments[0] || window
  context.fn = this
  let result = !!arguments[1] ? context.fn(...arguments[1]) : context.fn()
  delete context.fn
  return result
}

bind:

Function.prototype.customBind = function () {
  if (typeof this !== 'function') {
    throw new TypeError('error!')
  }
  const that = this
  let context = arguments[0] || window
  const args = [...arguments].slice(1)
  return function() {
    return that.apply(context, args.concat([...arguments]))
  }
}

原文git地址 覺得有用的話,來個star鼓勵,持續更新中。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章