前端工作和面试中常常会遇到批改this指向的问题, 这就避不开对 callapplybind 的探讨

用法

1. call

语法: function.call(thisArg, arg1, arg2, ...)
其中: thisArg 可选值; 指定为 nullundefined 时会主动替换为全局对象(严格模式下将会是 undefined); 指定为数字、字符串或布尔类型, 则会转换成他们的包装对象. 是 function 函数运行时指向的 this 值. arg1, arg2, ... 指定的参数, 能够有多个
返回值: 调用有指定 this 值和参数的函数的后果。
应用场景:

    // 判断数据类型    const a = 1    const b = '1'    const c = true    const d = () => {}    toString.call(a) // 输入 '[object Number]'    toString.call(b) // 输入 '[object String]'    toString.call(c) // 输入 '[object Boolean]'    toString.call(d) // 输入 '[object Function]'    // 将伪数组转换为数组    function transformArgement() {        const arr = Array.prototype.slice.call(arguments)        return arr    }    console.log(transformArgement(1, 2, 3, 4, 5)) // 输入 [1, 2, 3, 4, 5]        // 通过调用父构造函数的 call 办法来实现继承    function Calc (args) {        const arr = Array.prototype.slice.call(args)        // 最大值        this.max = Math.max.apply(null, arr)        // 最小值        this.min = Math.min.apply(null, arr)        // 求和        this.sum = arr.reduce((pre, cur) => pre + cur)    }    function Ages() {        Calc.call(this, arguments)        this.property = 'ages'    }        const team01 = new Ages(10, 20, 12, 80, 4, 100, 19)    console.log(team01.min) // 输入 4    console.log(team01.max) // 输入 100    console.log(team01.sum) // 输入 245

2. apply

语法: function.apply(thisArg, argsArray)
其中: thisArg 用法同上. argsArray 指定的参数, 能够为一个数组或者类数组对象,其中的数组元素将作为独自的参数传给 function 函数
返回值: 调用有指定 this 值和参数的函数的后果。
应用场景:

    // 数组增加数组元素    const arr1 = [1, 2, 3]    const arr2 = ['1', '2', '3']    Array.prototype.push.apply(arr1, arr2)    console.log(arr1) // 输入 [1, 2, 3, '1', '2', '3']        //数组转化    const slice = Array.prototype.slice;    function args() {        return slice.apply(arguments)    }    args(1, 2, 3, 4) // 返回 [1, 2, 3, 4]    // 内置函数的扩大    const arrNum = [1, 4, 6, 3, 2]    console.log(Math.min.apply(null, arrNum))    console.log(Math.max.apply(null, arrNum))

3. bind

语法: function.bind(thisArg, arg1, arg2, ...)
其中: thisArg 调用绑定函数时作为 this 参数传递给指标函数的值。 如果应用 new 运算符结构绑定函数,则疏忽该值。当应用 bindsetTimeout 中创立一个函数(作为回调提供)时,作为 thisArg 传递的任何原始值都将转换为 object。如果 bind 函数的参数列表为空,或者 thisArgnullundefined,执行作用域的 this 将被视为新函数的 thisArg. arg1, arg2, ... 指定的参数, 能够有多个
返回值: 返回一个原函数的拷贝,并领有指定的 this 值和初始参数。
应用场景:

    // 创立绑定函数    // 老手常常犯的一个谬误是将一个办法从对象中拿进去,而后再调用,冀望办法中的 this 是原来的对象    this.a = 100    const obj = {        a: 1,        fn: function() {            return this.a        }    }        obj.fn() // 输入 1    const f = obj.fn.bind(obj)    f() // 输入 1    // React 组件中为函数绑定组件实例    class Foo extends Component {          constructor(props) {            super(props);            this.handleClick = this.handleClick.bind(this);          }          handleClick() {            console.log('Click happened');          }          render() {          return <button onClick={this.handleClick}>Click Me</button>;        }    }    // 偏函数实现    function add(arg1, arg2) {        return arg1 + arg2    }    const addBase10 = add.bind(null, 10)    console.log(addBase10(100)) // 输入 110    console.log(addBase10(200)) // 输入 210        // 类数组转化    const unboundSlice = Array.prototype.slice    const slice = Function.prototype.apply.bind(unboundSlice)        function args() {        return slice(arguments)    }    args(1, 2, 3, 4) // 返回 [1, 2, 3, 4]

区别

从下面的用法比照不难看出, callapply 次要是入参不同, 他们都是返回调用有指定 this 值和参数的函数的后果(即立刻调用)。而 bind 的入参加 call 雷同, 然而他的返回值与 callapply 都不同, 是一个原函数的拷贝,并领有指定的 this 值和初始参数。

延长

应用 js 实现 bind 办法

  • 首先须要把办法增加到函数原型
  • 办法能够承受 n 个参数, 其中第一个参数为调用办法的函数的 this 指向, 其余参数将作为调用函数的入参

      Function.prototype.customBind = function (targetThis) {      // 类型校验      if (toString.call(this) !=== '[object Function]') {          throw new Error(`${this} mast be a Function`)      }      // 保留this      const _this = this      // 保留参数(剔除第一个参数 - 须要 this 指向的参数)      const args = Array.prototype.slice.call(arguments, 1)      const fn = function () {          // 保留调用时传入的参数          const fnArgs = Array.prototype.slice.call(arguments)          return _this.apply(targetThis, args.concat(fnArgs))      }      return fn  }    function fn() {    console.log(this) // 输入 { a: 10 }    console.log(this.a, arguments) // Arguments [1, 2, 3, 4, 5, 6]  }  const o = { a: 10 }  fn.customBind(o, 1, 2, 3)(4, 5, 6)