• JS面试题----手写call, apply, bind


    首先我们要知道call、apply、bind的作用都是用来改变this的指向的,可以从以下几点来考虑如何实现这几个函数:

    • 不传入第一个参数,那么上下文默认是window
    • 改变了this指向,让新的对象可以执行该函数

    实现call

    // 通过配置默认参数的方式,第一个参数如果不传,默认为window
    Function.prototype.myCall = function (context = window) {
      // 上下文校验
      if (typeof this !== 'function') {
        throw new TypeError('Errors')
      }
      // 改变this指向
      context.fn = this
      // 截取参数
      const args = [...arguments].slice(1)
      // 通过新的上下文调用函数并得到结果
      const result = context.fn(...args)
      // 删除临时绑定在context上的方法
      delete context.fn
      return result
    }
    
    function foo(x, y) {
      console.log(this, this.a * x * y)
    }
    
    obj = {
      a: 1,
      b: 2
    }
    
    foo.myCall(obj, 2, 3)

    以下是对实现的分析:

    • 首先context为可选参数,如果不传,默认上下文为window
    • 接下来给context创建一个fn属性,并将值设置为需要调用的函数
    • 因为call可以传入多个参数作为调用函数的参数,所以需要将参数剥离出来
    • 然后调用函数并将对象上的函数删除

    以上就是call的实现思路了

    apply

    apply的实现和call类似,区别在于对参数的处理,call是可以接受多个参数,而apply是接受一个数组作为第二个参数,将数组中的项作为函数的参数。

    Function.prototype.myApply = function(context) {
      if (typeof this !== 'function') {
        throw new TypeError('Error')
      }
      context = context || window
      context.fn = this
      let result
      // 处理参数和 call 有区别
      if (arguments[1]) {
        result = context.fn(...arguments[1])
      } else {
        result = context.fn()
      }
      delete context.fn
      return result
    }

    bind

    Function.prototype.myBind = function (context = window) {
      if (typeof this !== 'function') {
        throw new TypeError('Error')
      }
      const _this = this
    
      /* if (arguments[1]) {
        args = arguments[1]
      } else {
        args = []
      } */
      const args = [...arguments].slice(1)
      return function F () {
        // 因为返回了一个函数,所以可能存在用new调用的情况,所以需要判断
        if (this instanceof F) {
          return new _this(...args, ...arguments)
        }
    
        return _this.apply(context, arsg.concat(...arguments))
      }
    }

    以下是对实现的分析:

    • bind返回了一个函数,对于函数来说又两种方式调用,一种是直接调用,一种是通过new的方式
    • 对于直接调用来说,这里选择了apply的方式实现,但是对于参数需要注意以下情况:因为bind可以实现类似这样的代码f.bind(obj, 1)(2), 所以我们需要将两边的参数拼接起来,于是就有了这样的实现args.concat(...arguments)
    • 对于通过new的方式,因为new调用函数是不会被任何方式改变this的,所以要忽略传入的this, 用最外层保存的_this
  • 相关阅读:
    C# String.Format用法和格式说明
    VS2017桌面应用程序打包成.msi或者.exe
    Mysql授权允许远程访问
    C# Winform频繁刷新导致界面闪烁解决方法
    C# 解决窗体闪烁
    C# winform或控制台Properties.Settings.Default的使用及存储位置
    C# 获取计算机cpu,硬盘,内存相关的信息
    C# 多线程多文件批量下载---子线程中更新UI 实例
    Objective-C:NSSet和NSMutbaleSet的用法
    iOS:App上架流程和支付宝支付流程
  • 原文地址:https://www.cnblogs.com/jett-woo/p/12564066.html
Copyright © 2020-2023  润新知