面试官:能解释一下javascript中bind、apply和call这三个函数的用法吗

一.前言

    不知道大家还记不记得前几篇的文章:《面试官:能解释一下javascript中的this吗

  那今天这篇文章虽然是介绍javascript中bind、apply和call函数,但是多少也和this有点关联。

  假如在前面那场面试末尾,面试官不依不饶继续问你javascript中的this,那看完本篇文章后一定还会有收获。

  (本篇文章不会站在this的角度去回答问题,而是重于解释bind、apply和call这三个函数的用法和使用场景)

二.正戏开始

  面试官:能解释一下javascript中bind、apply和call这三个函数的用法吗?

  我:(这三个函数我也只是了解它们的用法,仅此而已)

  我:这三个函数都是用于改变函数运行时内部this的指向的,只是每个函数的用法不一样。

  面试官:那你分别说一下具体都怎么用吧。

  我:(接着我边回忆之前做过的小练习边回答面试官)

  (以下描述和回答均基于浏览环境)

  首先是一个很简单的示例

 1 var objMM = {
 2     name: ‘MM‘,
 3     age: 18,
 4     getPresonInfo: function(addr){
 5         console.log(this.name + "年龄" + this.age + " 地址: " + addr);
 6     }
 7 };
 8
 9 var objZZ = {
10     name: ‘ZZ‘,
11     age: 28,
12     getPresonInfo: function(addr){
13         console.log(this.name + "年龄" + this.age + " 地址: " + addr);
14     }
15 }
16
17
18 objMM.getPresonInfo(‘上海‘);
19
20 objZZ.getPresonInfo(‘深圳‘);

  18行和20行的打印信息分别为:

  

  bind方法

  首先是bind方法,它的基本语法为 targetFunction.bind(thisArg,arg1,arg2,...)。

  第一个参数thisArg会作为目标函数targetFunction运行时的this值传递给目标函数。

  后面的参数列表arg1,arg2,... 是传递给目标函数的参数。

  bind方法的返回值是一个目标函数的一个拷贝。

  这个拷贝出来的函数运行时this指向的就是调用bind传递的thisArg参数。

  并且拷贝函数还拥有调用bind时传递的arg1,arg2,...多个参数。

  感觉这段描述把我自己都说晕了。

  所以如果觉得语言描述不清楚,就写一个简单的用法示例:

var copyF = objMM.getPresonInfo.bind(objZZ,‘远方‘);copyF();

  这个示例是要在前面第一个示例的基础上运行的。

  在结合前面那段晦涩难懂的文字描述,可以这样理解这两行代码:

    copyF为objMM.getPresonInfo函数的一个拷贝。

    copyF运行时内部的this指向objZZ;

    copy函数拥有一个参数‘远方‘

  这样调用copy函数的结果就很显而易见了。

  

  apply方法

  apply方法的基本语法为 targetFunction.apply(thisArg,[arg1,arg2])。

  第一个参数的作用同bind方法。

  第二个参数的作用也是和bind方法相同,只是将参数列表变为数组的形式进行传递。

  apply方法的返回值和bind方法就完全不同了,它会直接调用并执行目标函数。

  那话不多说,在写一个示例

objMM.getPresonInfo.bind(objZZ,[‘你管我在哪‘]);

  打印结果:

  

  call方法

  call方法的基本语法为 targetFunction.call(thisArg,arg1,arg2,...)。

  第一个参数的作用同bind方法,也同apply方法。

  第二个参数的作用也是和bind、apply相同,只是形式同bind方法是参数列表形式。

  call方法的返回值同apply方法,也是直接调用并执行目标函数。

objMM.getPresonInfo.call(objZZ,‘我爱在哪在哪‘);

  打印结果:

  

  面试官:那这些函数你平时用过吗,具体有什么使用场景。

  我:(这下惨了,平时还真没咋用过,如实回答)平时在写代码的时候,基本没咋用过。

  面试官:那好吧

  我:(凉凉)......

三.自我反思

  回家后深刻进行了自我反思:平时好像还真的没有使用过这个三个函数呀,不过没关系,现在学还来得及。

  于是我开始各种搜罗,然后依旧个人理解,将其分为两种使用场景。

  (怎么分类不重要,后面的示例才重要)

1.使用场景一:借用函数

  大概意思就是借用现有方法去自己的需求。

  在文章开始的第一个示例的基础上,稍作一下修改

 1 var objMM = {
 2     name: ‘MM‘,
 3     age: 18,
 4     getPresonInfo: function(addr){
 5         console.log(this.name + "年龄" + this.age + " 地址: " + addr);
 6     }
 7 };
 8
 9 var objZZ = {
10     name: ‘ZZ‘,
11     age: 28
12 }

  这个代码中,objZZ已经没有getPersonInfo这个方法了,假如我们想像objMM那样去打印对象自身的信息怎么办呢?

  此时这三个函数就能派上用场了。

1 objMM.getPresonInfo.bind(objZZ,‘我爱在哪在哪‘)();   // ZZ年龄28 地址: 我爱在哪在哪
2 objMM.getPresonInfo.apply(objZZ,[‘我爱在哪在哪‘]);  // ZZ年龄28 地址: 我爱在哪在哪
3 objMM.getPresonInfo.call(objZZ,‘我爱在哪在哪‘);     // ZZ年龄28 地址: 我爱在哪在哪

  

  在就是javascript里面有很多工具对象(我自己这样叫),比如Math。

  Math类有两个函数max和min,一般情况下依照这两个函数的语法只能这样使用:

var maxNum = Math.max(23,197,88,35,109,11);
console.log(maxNum);   // 197

var minNum = Math.min(23,197,88,35,109,11);
console.log(minNum);   //11

  假设现在代码里面有一个数组变量要求出最大最小值,我们又不想自己去实现。

  那我们就只能借助Math提供的max和min方法,使用apply函数去实现这个功能。

var arr = [23,197,88,35,109,11];

var maxNum = Math.max.apply(Math,arr);
console.log(maxNum);   // 197

var minNum = Math.min.apply(Math,arr);
console.log(minNum);   //11

  

  除了Math类之外,数组也有很多api,比如最常见的forEach。

  这个方法也只能是数组类型的变量才能使用,那非数组类型的变量要使用怎么办呢?

 1 var divCollections = document.getElementsByTagName(‘html‘);
 2
 3 Array.prototype.forEach.bind(divCollections,function(item){
 4     console.log(item);
 5 })();
 6 Array.prototype.forEach.apply(divCollections,[function(item){
 7     console.log(item);
 8 }]);
 9 Array.prototype.forEach.call(divCollections,function(item){
10     console.log(item);
11 });

  

  借用函数的最后一个使用场景就是数据类型判断。

  我们知道javascript中使用typeof可以判断一个变量的类型,但是仅限于基础的类型。

  比如:number、string、boolean、undefined类型。

  其他类型的例如:array、object、null使用typeof 判断类型打印均为“object”

  所以我们可以借助Object对象提供的一个函数,准确的知道一个数据的类型。

1 Object.prototype.toString.call(1);   // "[Object Number]"
2 Object.prototype.toString.call(‘1‘); // "[Object String]"
3 Object.prototype.toString.call(true); // "[Object Boolean]"
4 Object.prototype.toString.call(undefined); // "[Object Undefined]"
5 Object.prototype.toString.call([]); // "[Object Array]"
6 Object.prototype.toString.call({}); // "[Object Object]"
7 Object.prototype.toString.call(null); // "[Object Null]"

  

2.使用场景二:实现继承

  我们都知道,javascript中最简单的继承代码是通过将子类原型指向父类实例实现的。

 1 function Father(name,age){
 2     this.name = name;
 3     this.age  = age;
 4     this.sayInfo = function(){
 5         console.log(this.name + "年龄: "+ this.age);
 6     }
 7 }
 8
 9
10 function Son(name,age){
11     this.name = name;
12     this.age  = age;
13 }
14
15 //将子类原型指向父类实例
16 Son.prototype = new Father(‘我是你爸爸‘,);
17
18 var s = new Son(‘Son‘,1)
19 s.sayInfo();   //打印:Son年龄: 1

  那我们可以借助这三个函数实现javascript中的继承。

  (这里只写call方法的实现)

 1 function Father(name,age){
 2     this.name = name;
 3     this.age  = age;
 4     this.sayInfo = function(){
 5         console.log(this.name + "年龄: "+ this.age);
 6     }
 7 }
 8
 9 function Son(name,age){
10     Father.call(this,name,age)
11 }
12
13
14 var s = new Son(‘Son‘,1)
15 s.sayInfo();   //打印:Son年龄: 1

  可以看到使用call实现继承时,只需要在子类Son中调用父类的构造函数,并且按照call函数的语法传入所需参数即可。

  后面直接使用Son的实例就能调用sayInfo函数。

  这种方式说来有点意思,因为前面es5语法的继承是子类原型指向父类实例,也就是通过原型链实现的。

  而这种方式的原理又是什么呢?

  好奇心驱使,我分别打印了前面es5中原型链实现继承后创建的实例s和使用call实现继承后创建的实例s

  

  从结果可以看到,使用call实现继承,实例化后的对象s本身已经拥有了sayInfo方法。

  所以说原型链式的继承和call实现的继承还是有本质的区别的。

  

  那到底里,关于bind、apply、call函数的使用场景就整理完了,下次遇到面试官问应该就不虚了。

  (使用场景有可能不全,欢迎大家补充)

四.总结

  本篇到此就基本结束了,结合前一篇关于this的文章,javascript中的this基本就没啥大问题了。

  当然实际的项目千变万化,还是需要谨慎使用this。

  介于本篇文章主要还是解释javascript中bind、apply和call函数的用法,因此后续会在补一篇总结《使用原生Javascript实现bind、apply和call函数》。

    最近作者新开通了一个微信公众号。

  微信公众号会分享一些自己日常的东西,包括个人总结呀,吸猫日常呀,同时也会分享一些博客上的前端技术文章。

  

  

   欢迎大家扫码关注~

  

  

原文地址:https://www.cnblogs.com/HouJiao/p/12283748.html

时间: 2024-08-08 13:43:46

面试官:能解释一下javascript中bind、apply和call这三个函数的用法吗的相关文章

面试官竟然问我JavaScript中var、let和const有什么区别?

在JavaScript中有三种声明变量的方式:var.let.const. 目录1.var let const1.var(1)var定义的变量在之后可以修改,如果不初始化会输出undefined,不会报错. var a;console.log(a); // undefined// -----------------------------console.log(a); // undefinedvar a = 1;12345(2)var定义的变量,可以跨块访问, 不能跨函数访问. (3)var只有

JavaScript中bind、call、apply函数用法详解

在给我们项目组的其他程序介绍 js 的时候,我准备了很多的内容,但看起来效果不大,果然光讲还是不行的,必须动手.前几天有人问我关于代码里 call() 函数的用法,我让他去看书,这里推荐用js 写服务器的程序猿看<javascript编程精粹> 这本书,crockford大神果然不是盖的.之后我在segmentfault上又看到了类似的问题,那边解答之后干脆这里记一笔. 首先,关于 js 定义类或对象的方法,请参看w3school 的这里的这里,写的非常详细和清晰,我不再赘言了. 为了介绍 b

javascript中call,apply,bind的用法对比分析

这篇文章主要给大家对比分析了javascript中call,apply,bind三个函数的用法,非常的详细,这里推荐给小伙伴们. 关于call,apply,bind这三个函数的用法,是学习javascript这门语言无法越过的知识点.下边我就来好好总结一下它们三者各自的用法,及常见的应用场景. 首先看call这个函数,可以理解成"借用“,"请求".想像一下如下的情景:你孤单一人漂泊在外,有急事想往家里打电话,可是很不巧,手机欠费了,或者没电了,或者掉坑里了,总之你的手机就是用

JavaScript中的apply()方法和call()方法使用介绍

javascript中apply和call方法的作用及区别说明 call和apply的说明 call,apply都属于Function.prototype的一个方法,它是JavaScript引擎内在实现的,因为属于Function.prototype,所以每个Function对象实例(就是每个方法)都有call,apply属性.既然作为方法的属性,那它们的使用就当然是针对方法的了,这两个方法是容易混淆的,因为它们的作用一样,只是使用方式不同. 语法:foo.call(this, arg1,arg

string中c_str()、data()、copy(p,n)函数的用法(转)

标准库的string类提供了3个成员函数来从一个string得到c类型的字符数组:c_str().data().copy(p,n). 1. c_str():生成一个const char*指针,指向以空字符终止的数组. 注: ①这个数组的数据是临时的,当有一个改变这些数据的成员函数被调用后,其中的数据就会失效.因此要么现用先转换,要么把它的数据复制到用户自己可以管理的内存中.注意.看下例: const char* c; string s="1234"; c = s.c_str(); co

javascript中bind函数的作用

javascript的bind的作用 1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <style> 6 button {background-color:#0f0;} 7 </style> 8 </head> 9 <body> 10 <button id="button"> 按钮

阿里面试官:字符串在JVM中如何存放?90%的人就真的只回答在哪里存放

目录: 一道面试题的引出 案例分析 intern 源码分析 总结 1. 一道面试题的引出 在面试BAT这种一线大厂时,如果面试官问道:字符串在 JVM 中如何存放?大多数人能顺利的给出如下答案: 字符串对象在JVM中可能有两个存放的位置:字符串常量池或堆内存. 使用常量字符串初始化的字符串对象,它的值存放在字符串常量池中: 使用字符串构造方法创建的字符串对象,它的值存放在堆内存中: 但是如果能针对上述回答,做进一步扩展,会给你的面试表现加分不少,让你从一大波候选人中脱颖而出.下面就一起来分析一下

JavaScript中的apply()、call()、bind()

JavaScript 中 apply.call.bind方法的异同: 相同点 都是用来动态指定函数 this 对象的指向 第一个参数都是 this 要指向的对象,也就是要指定的上下文 都可以利用后续参数传参 不同点 传参形式不同:apply 方法接受的是一个参数数组,call 和 bind 方法接受的是参数列表 执行方式不同:apply.call 会立即执行,而 bind 方法会创建一个新函数,需要单独调用执行 apply() 的使用 语法:func.apply(thisArg, [argsAr

理解javascript中bind的使用和模拟实现

前面提到了call/apply的理解和模拟,再次谈谈具有相似性的bind函数的用法和模拟,bind同样是Function.prototype上面的函数,是es5中新增方法. bind的作用 bind()方法创建一个新的函数,在调用时设置this关键字为提供的值.并在调用新函数时,将给定参数列表作为原函数的参数序列的前若干项. // bind 函数的特点:返回一个函数,可以传入参数 function sayName(name, age) { this.name = name; this.age =