概念

apply call 和bind 允许为不同的对象分配和调用属于一个对象的函数/方法。同时它们可以改变函数内 this 的指向。

区别

  • apply 和 call 接收的参数形式不同

  • apply 和 call 都是直接调用函数并得到函数执行结果,而 bind 会返回待执行函数,需要再次调用

用法演示

我们先创建一个对象 parent

  1. const parent = {
  2. name: 'parent',
  3. sayPerson (age, addr) {
  4. return {
  5. name: this.name,
  6. age,
  7. addr
  8. }
  9. }
  10. }

显然它具有 name 属性,及方法 sayPerson,我们现在可以通过 parent.sayPerson() 来输出该对象信息。

  1. const person = parent.sayPerson(60, 'shenzhen');
  2. // {name: "parent", age: 60, addr: "shenzhen"}

现在我们再创建一个对象 son

  1. const son = {
  2. name: 'son'
  3. }

我们现在也想得到 son 的信息,但是 son 对象没有 sayPerson 函数怎么办?借助已有的 parent 对象和 call 方法,我们可以这样写

  1. const person = parent.sayPerson.call(son, 26, 'shenzhen');
  2. // {name: "son", age: 26, addr: "shenzhen"}

可以看出,通过调用 call 函数,我们为 son 对象分配了 sayPerson 方法并进行调用。实现了一个对象可以调用不属于它自己的方法,并且函数内的 this 指向该对象。apply 方法的用法其实一样,只是传参有些区别

  1. const person = parent.sayPerson.call(son, [26, 'shenzhen']);
  2. // {name: "son", age: 26, addr: "shenzhen"}

bind 函数则不直接调用函数,而是返回待调用函数

  1. const sayPersonFn = parent.sayPerson.bind(son, 26, 'shenzhen');
  2. const person = sayPersonFn();
  3. // {name: "son", age: 26, addr: "shenzhen"}

以上就是三者的使用方法和区别,下面我们来看看它们是如何实现的

实现

call的实现

实现原理就是为对象 obj 添加需要调用的方法,接着调用该方法(此时 this 指向 obj),调用过后再删除该方法

简单版

  1. Object.prototype.callFn = function (...args) {
  2. // 第一个参数为目标对象
  3. const context = args[0];
  4. args.shift();
  5. // 为对象赋值需要调用的方法
  6. context.fn = this;
  7. // 调用该方法
  8. context.fn(...args);
  9. // 删除方法
  10. delete context.fn;
  11. }

加上返回值

  1. Object.prototype.callFn = function (...args) {
  2. // 第一个参数为目标对象
  3. const context = args[0];
  4. args.shift();
  5. // 为对象赋值需要调用的方法
  6. context.fn = this;
  7. // 调用该方法
  8. const result = context.fn(...args);
  9. // 删除方法
  10. delete context.fn;
  11. return result;
  12. }

在测试中发现,我们调用 call,如果第一个参数是 null 或者 undefined,那么 call 将以全局 window 来调用方法,此时 this 也指向 window。如果第一个参数不是对象类型,则以空对象 {} 来调用方法。

  1. Object.prototype.callFn = function (...args) {
  2. // 第一个参数为目标对象
  3. let context = args[0];
  4. // undefined 和 null 指向 window
  5. if (context === null || context === undefined) {
  6. context = window;
  7. }
  8. // 不是对象类型则创建空对象
  9. if (typeof context !== 'object') {
  10. context = {};
  11. }
  12. args.shift();
  13. // 为对象赋值需要调用的方法
  14. context.fn = this;
  15. // 调用该方法
  16. const result = context.fn(...args);
  17. // 删除方法
  18. delete context.fn;
  19. return result;
  20. }

至此,我们实现了一个完整的 call 方法。

apply的实现

既然和 call 只存在传参的区别,那我们只需要简单修改下已实现的 call 方法即可。

  1. Object.prototype.applyFn = function (...args) {
  2. let context = args[0];
  3. if (context === null || context === undefined) {
  4. context = window;
  5. }
  6. if (typeof context !== 'object') {
  7. context = {};
  8. }
  9. args.shift();
  10. context.fn = this;
  11. // 和 call 存在差异的地方
  12. const result = context.fn(...args[0]);
  13. delete context.fn;
  14. return result;
  15. }

bind的实现

在实现了 apply 和 call 的前提下,bind 的实现也比较简单。

  1. Object.prototype.bindFn = function (...args) {
  2. // 实际就是多包了层待执行函数
  3. return () => {
  4. return this.applyFn(args[0], (args || []).slice(1));
  5. }
  6. }

至于以 bind 方法返回的函数作为构造函数来创建对象会存在的问题请参考JavaScript深入之bind的模拟实现

总结

call apply bind 在工作中实际上是比较常见的函数,特别是在一些框架或库的源码中,但是经常有人会混淆它们的用法。希望大家通过此篇文章可以彻底弄清它们的作用与区别,并且知道其实现原理,知其然知其所以然。

参考


欢迎到前端学习打卡群一起学习~516913974

apply call bind的用法与实现的更多相关文章

  1. js中call、apply、bind的用法

    原文链接:http://www.cnblogs.com/xljzlw/p/3775162.html var zlw = { name: "zlw", sayHello: funct ...

  2. call、apply、bind的用法

    数组追加 //用apply拼接 var arr1=[12,'name:foo',2048]; var arr2=['Joe','Hello']; Array.prototype.push.apply( ...

  3. javascript中call()、apply()、bind()的用法理解

    一.bind的用法 第一个:obj.showInfo('arg','arg_18');中传的2个参数通过showInfo方法改变的是obj下中的name和age 第二个:obj.showInfo.bi ...

  4. JS中的call()、apply() 以及 bind()方法用法总结

    JS中的call()方法和apply()方法用法总结  : 讲解: 调用函数,等于设置函数体内this对象的值,以扩充函数赖以运行的作用域. function add(c,d){ return thi ...

  5. javascript中call()、apply()、bind()的用法终于理解

    其实是一个很简单的东西,认真看十分钟就从一脸懵B 到完全 理解! 先看明白下面: 例1 obj.objAge;  //17 obj.myFun()  //小张年龄undefined 例2 shows( ...

  6. call,apply,bind的用法与区别

    1.call/apply/bind方法的来源 首先,在使用call,apply,bind方法时,我们有必要知道这三个方法究竟是来自哪里?为什么可以使用的到这三个方法? call,apply,bind这 ...

  7. (转)javascript中call()、apply()、bind()的用法

    其实是一个很简单的东西,认真看十分钟就从一脸懵B 到完全 理解! 先看明白下面: 例1 obj.objAge;  //17 obj.myFun()  //小张年龄undefined 例2 shows( ...

  8. <JavaScript> call()、apply()、bind() 的用法

    其实是一个很简单的东西,认真看十分钟就从一脸懵B 到完全 理解! 先看明白下面: 例 1 obj.objAge; obj.myFun() // 小张年龄 undefined   例 2 shows() ...

  9. call、apply、bind 的用法

    例1 obj.objAge; //17 obj.myFun() //小张年龄undefined 例2 shows() //盲僧 比较一下这两者this 的差别,第一个打印里面的this 指向obj,第 ...

  10. JS中call()、apply()、bind()的用法

    其实是一个很简单的东西,认真看十分钟就从一脸懵B 到完全 理解! 先看明白下面: 例1 obj.objAge;  //17 obj.myFun()  //小张年龄undefined 例2 shows( ...

随机推荐

  1. M - Help Hanzo LightOJ - 1197 (大区间素数筛法)

    题解:素数区间问题.注意到a和b的范围是1<<31,所以直接暴力打表肯定不可以.如果一个数是合数,他的两个因子要么是两个sqrt(x),要么就分布在sqrt(x)两端,所以我们可以根据sq ...

  2. A Bug's Life POJ 2492

    D - A Bug's Life 二分图 并查集 BackgroundProfessor Hopper is researching the sexual behavior of a rare spe ...

  3. Django开发文档-域用户集成登录

    项目概述: 一般在企业中,用户以WINDOWS的域用户统一的管理,所以以Django快速开发的应用,不得不集成AD域登录. 网上一般采用django-python3-ldap的库来做集成登录,但是本方 ...

  4. bluecms v1.6 sp1 代码审计学习

    前言 正式开始代码审计的学习,拓宽自己的知识面.代码审计学习的动力也是来自团队里的王叹之师傅,向王叹之师傅学习. 这里参考了一些前辈,师傅的复现经验和bluecms审计的心得 安装 install.p ...

  5. MySQL如何创建一个好索引?创建索引的5条建议【宇哥带你玩转MySQL 索引篇(三)】

    MySQL如何创建一个好索引?创建索引的5条建议 过滤效率高的放前面 对于一个多列索引,它的存储顺序是先按第一列进行比较,然后是第二列,第三列...这样.查询时,如果第一列能够排除的越多,那么后面列需 ...

  6. sql语句-------重复时插入更新

    ON DUPLICATE KEY UPDATE重复时插入更新 insert into user(id,username) value('231',"二人") on duplicat ...

  7. 深入理解Java枚举

    深入理解Java枚举 重新认识Java枚举 老实说,挺羞愧的,这么久了,一直不知道Java枚举的本质是啥,虽然也在用,但是真不知道它的底层是个啥样的 直到2020年4月28日的晚上20点左右,我才真的 ...

  8. ansible一键安装mysql8.0

    ansbile安装: # ansible在CentOS7中需要安装epel仓库 yum install -y epel-release yum install -y ansible 安装有好几种方法, ...

  9. AMD 开源照片级渲染引擎 Radeon ProRender

    除了Radeon Pro WX.Radeon Pro Solid State两款全新的专业显卡,AMD今天还宣布,Radeon ProRender渲染引擎即将开放源代码,开发人员可任意使用.AMD去年 ...

  10. IIS6服务器的请求流程(图文&源码)

    1.IIS 7开发与管理完全参考手册  http://book.51cto.com/art/200908/146040.htm 2.Web服务IIS 6   https://technet.micro ...