[JS-03]、call apply bind

465 阅读2分钟

前言

因为最近公司招人,面试时深刻感觉到“吾生也有涯,而知也无涯”,查阅整理了一下callapply bind的一些区别以及如何手写实现,总结一下,做个记录。

1. call

call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数。
!注意:该方法的语法和作用与 apply() 方法类似,只有一个区别,就是 call() 方法接受的是一个参数列表,而 apply() 方法接受的是一个包含多个参数的数组

/**
 * _call
 *
 * @param { context } context
 * @param { arguments } arguments
 */
Function.prototype._call = function(context) {
  // 如果没有传或传的值为空对象 context指向window
  context = context || window
  let fn = Symbol(context)
  context[fn] = this //给context添加一个方法 指向this
  // 处理参数 去除第一个参数this 其它传入fn函数
  let args = [...arguments].slice(1) //[...xxx]把类数组变成数组,arguments为啥不是数组自行搜索 slice返回一个新数组
  context[fn](...args) //执行fn
  delete context[fn] //删除方法
}

var obj = {
    name: 'Bob',
    age: '18',
    fn() {
        console.log(`My name is ${this.name}, my age is ${this.age}`)
    }
}

var dog = {
    name: 'Snoopy',
    age: 3
}
obj.fn.call(dog,'daddata','ttt','yuyuyuuy') // My name is Snoby, my age is 3
obj.fn._call(dog,'daddata','ttt','yuyuyuuy') // My name is Snoby, my age is 3

2. apply

类似的,apply方法实现一样,只是参数不一样

Function.prototype._apply = function(context) {
    // 如果没有传或传的值为空对象 context指向window
    context = context || window
    let fn = Symbol(context)
    context[fn] = this 
    let arg = [...arguments].slice(1) 
    context[fn](arg) //执行fn
    delete context[fn] //删除方法
}

3. bind

bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。

相较于callapplybind 区别还是很大的,分析一下bind的特点:1、改变this 2、返回一个绑定this的函数 3、接收多个参数 4、支持柯里化形式传参 fn(1)(2)
!注意: bind 方法与 call、apply 最大的不同就是前者返回一个绑定上下文函数,而后两b者是直接执行了一个函数

/**
 * _bind
 *
 * @param {*} context
 */
Function.prototype._bind = function (context) {
  //返回一个绑定this的函数,我们需要在此保存this
  let self = this
  // 可以支持柯里化传参,保存参数
  let arg = [...arguments].slice(1)
  // 返回一个函数
  return function () {
    //同样因为支持柯里化形式传参我们需要再次获取存储参数
    let newArg = [...arguments]
    // 返回函数绑定this,传入两次保存的参数
    //考虑返回函数有返回值做了return
    return self.apply(context, arg.concat(newArg))
  }
}