call,apply,bind的使用及原理

call,apply,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>
      var name = 'tc'

      const obj = {
        name: 'ljr',
        say: function (val, hobby) {
          return this.name + val + hobby
        },
      }

      console.log(obj.say('你好', '喜欢打球')) //ljr你好喜欢打球
      const f = obj.say
      console.log(f('你好', '喜欢打球')) //tc你好喜欢打球
      console.log(f.call(obj, '是美女', '喜欢唱歌')) //ljr是美女喜欢唱歌
      console.log(f.apply(obj, ['是小仙女', '喜欢唱歌'])) //ljr是小仙女喜欢唱歌
      console.log(f.bind(obj, '是宝藏女孩,', '喜欢唱周杰伦的歌')()) //ljr是宝藏女孩,喜欢唱周杰伦的歌
    </script>
  </body>
</html>

三者的区别

call与apply的唯一区别

传给fun的参数写法不同:

  • apply是第2个参数,这个参数是一个数组:传给fun参数都写在数组中。
  • call从第2~n的参数都是传给fun的。

call/apply与bind的区别

执行

  • call/apply改变了函数的this上下文后马上执行该函数
  • bind则是返回改变了上下文后的函数,不执行该函数

返回值:

  • call/apply 返回fun的执行结果
  • bind返回fun的拷贝,并指定了fun的this指向,保存了fun的参数。

原理:

手写 call

Function.prototype.myCall = function(context = globalThis) {
  // 设置 fn 为调用 myCall 的方法
  context.fn = this;

  // 获取剩余参数
  const otherArg = Array.from(arguments).slice(1);

  // 调用这个方法,将剩余参数传递进去
  context.fn(otherArg);

  // 将这个方法的执行结果传给 result
  let result = context.fn();

  // 删除这个变量
  delete context.fn;

  // 返回 result 结果
  return result;
};

this.a = 1;

const fn = function() {
  this.a = 2;
  console.log(this.a);
}

fn.myCall(fn);

手写apply

Function.prototype.myApply = function(context = globalThis, arr) {
  // 设置 fn 为调用 myCall 的方法
  context.fn = this;

  let result;

  // 如果存在参数,则传递进去
  // 将结果返回给 result
  if (arr) {
    result = context.fn(arr);
  } else { // 否则不传
    result = context.fn();
  }

  // 删除这个变量
  delete context.fn;

  // 返回 result 结果
  return result;
};

this.a = 1;

const fn = function() {
  this.a = 2;
  console.log(this.a);
}

fn.myApply(fn);

手写bind

Function.prototype.myBind = function(context = globalThis) {
  // 设置 fn 为调用 myCall 的方法
  const fn = this;

  // 获取该方法剩余参数
  const otherArg = [...arguments].slice(1);

  // 设置返回的一个新方法
  const result = function() {

    // 获取返回方法体的参数
    const resultArg = [...arguments];

    // 如果是通过 new 调用的,绑定 this 为实例对象
    if (this instanceof result) {
      fn.apply(this, otherArg.concat(resultArg));
    } else { // 否则普通函数形式绑定 context
      fn.apply(context, otherArg.concat(resultArg));
    }
  }

  // 绑定原型链
  result.prototype = Object.create(fn.prototype);

  // 返回结果
  return result;
};

this.a = 1;

const fn = function() {
  this.a = 2;
  console.log(this.a);
}

fn.myBind(fn);
fn();

函数的Arguments 对象

arguments 是一个对应于传递给函数的参数的类数组对象。

function fun(a, b, c) {
  console.log(arguments[0]); // 1
  console.log(arguments[1]); // 2
  console.log(arguments[2]); // 3
}
复制代码

arguments 对象不是一个 Array

它类似于 Array,但除了 length 属性和索引元素之外没有任何 Array 属性。

arguments 转为数组:

// ES5
var arg1 = Array.prototype.slice.call(arguments);
var arg2 = [].slice.call(arguments);

// ES6
var arg3 = Array.from(arguments);
var arg4 = [...arguments];
复制代码

在手写 call/bind/apply 过程中,会用到 arguments 来获取方法体的传参,就好比手写 call 过程中,通常我们通过 Array.from(arguments).slice(1) 来获取第二个及后面的参数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cc980302

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值