call,apply,bind混淆?那手写一个吧

call,apply,bind混淆?那手写一个吧

js 里,this 指向一直是一个让人又爱又恨的问题,用的好的那真是一柄利刃,用不好的那网页飘红。我们在开发过程中经常会改变this 的指向,常用的就是call、apply 和 bind

简述 call、apply、bind 方法的区别

  1. callapply 是改变后页面加载之后就立即执行,bind 不会立即执行,而是返回一个 新函数,适合回调场景使用。
  2. call、apply、bind第一个参数都是相同的(总是指函数运行时的 this)
    • apply 的第二个参数是一个数组
    • callbind的第二个参数是一 一列出的
  3. callapply 只是临时的修改一次,也就是调用 call 和 apply 方法的那次;后面再次调用原函数的时候,它的指向还是原来的指向
function fn({
  console.log(this);
};
fn(); // window

const obj = {
  name'constRen',
};

fn.call(obj); // {name: 'constRen'}
fn.apply(obj); // {name: 'constRen'}
fn();  // window
  1. bind 是永久修改函数 this 指向,但它修改的不是原函数;而是返回的新函数,新函数的 this 被永远改变了
function fn({
  console.log(this);
};
fn(); // window

const obj = {
  name'constRen',
};

let newfn = fn.bind(obj); 
newfn(); // {name: 'constRen'}
fn(); // window
newfn() // {name: 'constRen'}

很多人都搞不清楚他们的用法,或者是容易混淆,我想了一个形象好记的:

1. call()

被借的对象.方法.call(借给谁, 参数1, 参数2, 参数3)

  • 被借的对象===>就理解为 一个 有很多工具的人
  • 方法  ===>就是工具
  • 借给谁===> 就像你没有斧头,你想砍树,你可以向那个有很多工具的人 借用一下他的斧头

2. apply()

被借的对象.方法.call(借给谁, [参数1, 参数2, 参数3])

以上两个方法是一组的,它们只有参数不同,其他功能一样,都必须”马上执行”。

3. bind()

一般用于回调函数中,用于永久性的改变this的指向

被借的对象.方法.bind(借给谁, 参数1, 参数2, 参数3)

手写实现

实现Call

Function.prototype.myCall = function (ctx, ...args{
   // 1. 将方法挂载到 ctx  这个 this 就是那个方法!! 因为是 say 调用的 myCall
   // 注意:有一种特殊情况就是 ctx 本身就有一个fn方法,这样就会被覆盖  这儿就需要一个第一无二的变量
   const fn = Symbol();
   ctx[fn] = this;
   // 2. 调用这个方法
   ctx[fn](...args);
   // 3.调用完之后删除方法 不然对象就被改变了 多了一个方法
   delete ctx[fn]
};
function say(...args{
   console.log('...args', ...args); //  p1 p2 p3
   console.log('this.name'this.name); // constRen
};
say.myCall({ name"constRen" }, 'p1''p2''p3')

实现apply

Function.prototype.myApply = function (ctx, args = []{
   // 因为 apply 的第二个参数是一个数组  所以这儿需要限制
   if (args && !Array.isArray(args)) {
       throw '第二个参数必须是数组'
   }
   const fn = Symbol();
   ctx[fn] = this;
   ctx[fn](...args);
   delete ctx[fn]
}

function say(...args{
   console.log('...args', ...args); // p1 p2 p3
   console.log('this.name'this.name); // constRen
};
say.myApply({ name"constRen" }, ['p1''p2''p3'])

实现bind

Function.prototype.myBind = function (ctx, ...args1{
   // 注意:bind 是返回一个新函数 
   return (...args2) => {
       const fn = Symbol();
       ctx[fn] = this;
       ctx[fn](...args1.concat(...args2));
       delete ctx[fn]
   }
}

function say(...args{
   console.log('...args', ...args); //  'p1', 'p2', 'p3', 1, 23
   console.log('this.name'this.name); // constRen
};
const sayFn = say.myBind({ name"constRen" }, 'p1''p2''p3')

sayFn(123// 

总结

我觉得这个就是一个借鸡生蛋的过程,借鸡生蛋大家都听说过吧?原理其实就和这个差不多

就三步

  1. 将方法挂载到对象上 (把鸡借过来)
  2. 执行这个方法 (让鸡生蛋)
  3. 从这个对象上删除刚刚挂载的方法 (把鸡还回去)

文章出自:https://juejin.cn/post/7225281021843030077

作者:constRen


原文始发于微信公众号(前端24):call,apply,bind混淆?那手写一个吧

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/216402.html

(0)
李, 若俞的头像李, 若俞

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!