手写call、apply、bind

前置知识

apply只接受两个参数,其中第二个参数是一个类数组或者数组
call可以接受多个参数,即参数不固定
bind可以接受多个参数,即参数不固定,可分多次传参,绑定时不执行,调用时执行

this指向问题

JavaScript中的this关键字是一个非常重要的概念,它表示当前函数执行的上下文对象。this的指向在不同的情况下会有不同的值,下面列举一些常见的情况:

  1. 全局环境下,this指向全局对象window

  2. 函数中,this的指向取决于函数的调用方式
    如果是作为普通函数调用,this指向全局对象window
    如果是作为对象的方法调用,this指向该对象
    如果是使用call、apply或bind方法调用,this指向传入的第一个参数
    构造函数中,this指向新创建的对象

  3. 箭头函数中,this指向定义时所在的作用域。

手写

call

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <script>
      //call
      Function.prototype.myCall = function (context) {
        //call方法必须由一个函数调用
        if (typeof this !== "function") {
          throw new TypeError("not a function")
        }
        //symbol类型创建的,属性是唯一的,不会与其他属性冲突
        const symbolFn = Symbol()
        const args = [...arguments].slice(1) //类数组arguments转换为真数组,并删除第一项即obj
        //其他两种调用数组方法的方式
        //   const args1 = [].slice.call(arguments).slice(1)
        //   const args2 = Array.prototype.slice.call(arguments).slice(1)
        //   console.log(args, args1, args2)
        context = context || window
        context[symbolFn] = this //this就是foo
        const result = context[symbolFn](...args) //调用obj.foo(1,2,3) this是obj
        delete context[symbolFn]
        return result //obj
      }
      const obj = {
        name: "obj",
      }
      function foo() {
        console.log(this.name)
      }
      foo.myCall(obj, 1, 2, 3) // obj
    </script>
  </body>
</html>

apply

和call类似,处理arguments不同,call是参数列表,apply是数组

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <script>
      //apply
      Function.prototype.myApply = function (context) {
        if (typeof this !== "function") {
          throw new TypeError("error")
        }
        context = context || window
        context.fn = this
        //console.log(arguments[1])
        var result = arguments[1] ? context.fn(...arguments[1]) : context.fn()
        delete context.fn
        return result
      }
      function foo2() {
        console.log(this.age)
      }
      var obj2 = {
        age: 101,
      }
      foo2.myApply(obj2, [1, 2, 3]) // 输出101
    </script>
  </body>
</html>

bind

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <script>
      //bind
      Function.prototype.bind = function () {
        var self = this //fn
        // var context = Array.prototype.shift.call(arguments) // 读取第一个参数,即this对象  obj3 改变了arguments
        // var args = Array.prototype.slice.call(arguments) // 直接返回新的arguments 获取参数 1,2
        var context = [...arguments].shift() // 读取第一个参数,即this对象  obj3 没改变arguments
        var args = [...arguments].slice(1) // 删除第一项(obj)后获取参数 1,2
        // console.log(arguments, self, context, args)
        return function () {
          //  var newArgs = Array.prototype.concat.call( args,  Array.prototype.slice.call(arguments)  )
          var newArgs = [...args, ...arguments]
          //  console.log(newArgs)
          return self.apply(context, newArgs)
        }
      }
      var obj3 = {
        name: "why",
      }
      var fn = function (a, b, c, d) {
        console.log(this.name)
        console.log([a, b, c, d])
      }
      var func = fn.bind(obj3, 1, 2) //改变this不执行
      func(3, 4) // 输出why  [1,2,3,4]
    </script>
  </body>
</html>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值