📕 重学JavaScript:如何实现一个`call`/`apply`?

简介: 这次要说的 call/apply 方法其实和 bind 极其类似。

📕 重学JavaScript:如何实现一个call/apply

嗨,大家好!这里是道长王jj~ 🎩🧙‍♂️

这次要说的 call/apply 方法其实和 bind 极其类似。

它们可以让你改变一个函数的 this 指向,也就是让这个函数执行时,里面的 this 指向你想要的对象。😮

❓ 什么是call/apply

比如,你有一个函数叫 fn ,它会打印出 this 的 z 属性和两个参数 x 和 y 的和,就像这样:

function fn(x, y) {
   
  console.log(this.z);
  console.log(x + y);
}

然后,你有一个对象叫 obj ,它有一个 z 属性,就像这样:

var obj = {
   
  z: 1
};

现在,你想让 fn 的 this 指向 obj ,而且给 fn 传递两个参数 2 和 3 ,就可以使用 call/apply方法了!😊

你只要这样写:

fn.call(obj, 2, 3); // call 方法是一个一个传入参数
fn.apply(obj, [2, 3]); // apply 方法是通过一个数组传入参数

就会打印出:

1
5

他们俩区别就是传递参数的方式不同。call 方法是一个一个传入参数,而 apply 方法是通过一个数组传入参数。😁

那么,现在我们要自己实现call/apply,该怎么办呢?🤔

🔰 思路分析

其实核心套路其实和bind差不多,都是就两件事情。

  1. 让一个普通函数的 this 指向你想要的对象。
  2. 让一个构造函数的原型对象上的属性不会丢失。

确定好思路之后,我们就可以进行伪代码环节了。

💫 伪代码思路

1. 把第一个参数作为新的 this ,把剩下的参数作为新函数的初始参数,放在一个数组里。
2. 需要注意 call 方法是一个一个传入参数,而 apply 方法是通过一个数组传入参数。
3. 用 eval 函数执行原来的函数,把新的 this 和参数传进去。
4. 返回执行结果

⭕ 代码实现

function myCall(obj) {
   
  // 如果 obj 参数为空,则默认为 window 对象
  obj = obj || window;
  // 使用 Symbol 函数创建一个唯一的标识符
  const fnSymbol = Symbol();
  // 把原来的函数赋值给 obj 的 fnSymbol 属性
  obj[fnSymbol] = this;
  // 获取剩余参数
  const args = [...arguments].slice(1);
  // 构造字符串代码
  let code = `obj[fnSymbol](${
     args})`;
  // 执行代码并返回结果
  let result = eval(code);
  // 删除 obj 的 fnSymbol 属性
  delete obj[fnSymbol];
  // 返回结果
  return result;
};


function myApply(obj) {
   
  // 如果 obj 参数为空,则默认为 window 对象
  obj = obj || window;
  // 使用 Symbol 函数创建一个唯一的标识符
  const fnSymbol = Symbol();
  // 把原来的函数赋值给 obj 的 fnSymbol 属性
  obj[fnSymbol] = this;
  // 获取剩余参数(数组)
  const args = arguments[1];
  // 构造字符串代码
  let code = `obj[fnSymbol](${
     args})`;
  // 执行代码并返回结果
  let result = eval(code);
  // 删除 obj 的 fnSymbol 属性
  delete obj[fnSymbol];
  // 返回结果
  return result;
};

💥 测试一下看看有没有问题

function sayHello(name) {
   
  return "Hello, " + this.greeting + " " + name;
}

sayHello.myCall = myCall;
sayHello.myApply = myApply;

var obj = {
    greeting: "你好" };

// 用 myCall 调用函数
var result1 = sayHello.myCall(obj, "小明");

// 用 myApply 调用函数
var result2 = sayHello.myApply(obj, ["小红"]);

console.log(result1); // Hello, 你好 小明
console.log(result2); // Hello, 你好 小红

🎉 你觉得怎么样?这篇文章可以给你带来帮助吗?如果你有任何疑问或者想进一步讨论相关话题,请随时发表评论分享您的想法,让其他人从中受益。🚀✨

目录
相关文章
|
1月前
|
JavaScript 前端开发
javascript中的call和apply
javascript中的call和apply
|
4月前
|
JavaScript 前端开发
JavaScript中call()与apply()的作用与区别?
JavaScript中call()与apply()的作用与区别?
|
18天前
|
JavaScript 前端开发
JavaScript中call()与apply()的作用与区别?
JavaScript中call()与apply()的作用与区别?
20 2
|
1月前
|
JavaScript
JS中call()、apply()、bind()改变this指向的原理
JS中call()、apply()、bind()改变this指向的原理
|
3月前
|
JavaScript 前端开发 API
掌握apply和call,解密JavaScript的this指向
掌握apply和call,解密JavaScript的this指向
|
3月前
|
前端开发 JavaScript Java
【面试题】JavaScript 中 call()、apply()、bind() 的用法
【面试题】JavaScript 中 call()、apply()、bind() 的用法
|
3月前
|
前端开发 JavaScript
【面试题】 JavaScript 中 call()、apply()、bind() 的用法
【面试题】 JavaScript 中 call()、apply()、bind() 的用法
|
5月前
|
JavaScript 前端开发
javascript函数的call、apply和bind的原理及作用详解
javascript函数的 call、apply和bind 本质是用来实现继承的,专业点说法就是改变函数体内部 this 的指向,当一个对象没有某个功能时,就可以用这3个来从有相关功能的对象里借用过来
37 0
|
9月前
|
JavaScript 前端开发
JavaScript call、apply 和 bind 的区别
JavaScript call、apply 和 bind 的区别
|
8月前
|
JavaScript 前端开发
JavaScript中的this指向,call、apply、bind的简单实现
JavaScript中的this指向,call、apply、bind的简单实现
39 0