作者:小土豆biubiubiu

博客园:www.cnblogs.com/HouJiao/

掘金:https://juejin.im/user/58c61b4361ff4b005d9e894d

简书:https://www.jianshu.com/u/cb1c3884e6d5

微信公众号:土豆妈的碎碎念(扫码关注,一起吸猫,一起听故事,一起学习前端技术)

码字不易,点赞鼓励哟~

一.前言

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

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

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

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

二.正戏开始

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

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

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

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

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

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

  首先是一个很简单的示例

 var objMM = {
name: 'MM',
age: 18,
getPresonInfo: function(addr){
console.log(this.name + "年龄" + this.age + " 地址: " + addr);
}
}; var objZZ = {
name: 'ZZ',
age: 28,
getPresonInfo: function(addr){
console.log(this.name + "年龄" + this.age + " 地址: " + addr);
}
} objMM.getPresonInfo('上海'); 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.使用场景一:借用函数

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

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

 var objMM = {
name: 'MM',
age: 18,
getPresonInfo: function(addr){
console.log(this.name + "年龄" + this.age + " 地址: " + addr);
}
}; var objZZ = {
name: 'ZZ',
age: 28
}

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

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

 objMM.getPresonInfo.bind(objZZ,'我爱在哪在哪')();   // ZZ年龄28 地址: 我爱在哪在哪
objMM.getPresonInfo.apply(objZZ,['我爱在哪在哪']); // ZZ年龄28 地址: 我爱在哪在哪
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); // var minNum = Math.min.apply(Math,arr);
console.log(minNum); //

  

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

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

 var divCollections = document.getElementsByTagName('html');

 Array.prototype.forEach.bind(divCollections,function(item){
console.log(item);
})();
Array.prototype.forEach.apply(divCollections,[function(item){
console.log(item);
}]);
Array.prototype.forEach.call(divCollections,function(item){
console.log(item);
});

  

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

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

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

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

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

 Object.prototype.toString.call(1);   // "[Object Number]"
Object.prototype.toString.call('1'); // "[Object String]"
Object.prototype.toString.call(true); // "[Object Boolean]"
Object.prototype.toString.call(undefined); // "[Object Undefined]"
Object.prototype.toString.call([]); // "[Object Array]"
Object.prototype.toString.call({}); // "[Object Object]"
Object.prototype.toString.call(null); // "[Object Null]"

  

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

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

 function Father(name,age){
this.name = name;
this.age = age;
this.sayInfo = function(){
console.log(this.name + "年龄: "+ this.age);
}
} function Son(name,age){
this.name = name;
this.age = age;
} //将子类原型指向父类实例
Son.prototype = new Father('我是你爸爸',); var s = new Son('Son',1)
s.sayInfo(); //打印:Son年龄: 1

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

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

 function Father(name,age){
this.name = name;
this.age = age;
this.sayInfo = function(){
console.log(this.name + "年龄: "+ this.age);
}
} function Son(name,age){
Father.call(this,name,age)
} var s = new Son('Son',1)
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函数》。

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

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

  

  

   欢迎大家扫码关注~

  

  

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

  1. javascript中bind,apply,call的相同和不同之处

    javasctipt中bind,apply,call的相同点是: 1,都是用来改变this的指向; 2,都可以通过后续参数进行传参; 3,第一个参数都是指定this要指向的对象; 不同点: 1,调用方 ...

  2. 面试系列-面试官:你能给我解释一下javascript中的this吗?

    一.前言 关于javascript中的this对象,可能已经被大家说烂了. 即使是这样,我依然决定将这篇文章给水出来.毕竟全国在新型肺炎的影响下,公司没法正常复工. 除了刷刷手机,还是要适当的学习一下 ...

  3. 博文推荐】Javascript中bind、call、apply函数用法

    [博文推荐]Javascript中bind.call.apply函数用法 2015-03-02 09:22 菜鸟浮出水 51CTO博客 字号:T | T 最近一直在用 js 写游戏服务器,我也接触 j ...

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

    在给我们项目组的其他程序介绍 js 的时候,我准备了很多的内容,但看起来效果不大,果然光讲还是不行的,必须动手.前几天有人问我关于代码里 call() 函数的用法,我让他去看书,这里推荐用js 写服务 ...

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

    这篇文章主要给大家对比分析了javascript中call,apply,bind三个函数的用法,非常的详细,这里推荐给小伙伴们.   关于call,apply,bind这三个函数的用法,是学习java ...

  6. php中print_r、var_dump和var_export几个函数的用法区别

    php中print_r.var_dump和var_export几个函数的用法区别

  7. JavaScript中bind、call、apply函数使用方法具体解释

    在给我们项目组的其它程序介绍 js 的时候,我准备了非常多的内容,但看起来效果不大,果然光讲还是不行的,必须动手. 前几天有人问我关于代码里 call() 函数的使用方法.我让他去看书,这里推荐用js ...

  8. javascript中的apply,call,bind详解

    apply.call 在 javascript 中,call 和 apply 都是为了改变某个函数运行时的上下文(context)而存在的,换句话说,就是为了改变函数体内部 this 的指向. Jav ...

  9. 面试官:能手写实现call、apply、bind吗?

    1 call.apply.bind 用法及对比 1.1 Function.prototype 三者都是Function原型上的方法,所有函数都能调用它们 Function.prototype.call ...

随机推荐

  1. html页脚固定在底部的方法

    <style type="text/css"> html { height: 100%; } body { height: 100%; margin: 0; paddi ...

  2. CAP 3.0 版本发布通告

    前言 大家好,我们很高兴宣布 CAP 发布了 3.0 版本正式版. 自从上次 CAP 2.6 版本发布 以来,已经过去了几个月的时间,关注的朋友可能知道,在这几个月的时间里,也发布了几个预览版的 3. ...

  3. 小小知识点(三十五)MATLAB中如何更改所画Figure的图形比例

    1. 打开一个figure,show plot tools and dock figure 2.选择图形的 more properties 3. 选择aspect ratio中的plotboxaspe ...

  4. 【JavaWeb学习】过滤器Filter

    一.简介 Filter也称之为过滤器,它是Servlet技术中最激动人心的技术,WEB开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件或静 ...

  5. css控制div等比高度

    在移动端开发中,在banner轮播图未加载出来之前,banner层是不占文档流高度的,当从服务器获取完banner数据,展示的时候,banner层因为有了内容 所以会撑开,导致banner层下面的内容 ...

  6. Java 第一次课堂测验

    周一下午进行了开学来java第一次课堂测验,在课堂上我只完成了其中一部分,现代码修改如下: 先定义 ScoreInformation 类记录学生信息: /** * 信1805-1 * 胡一鸣 * 20 ...

  7. 在浏览器窗口内移动的div

    ------------今天研究了一个最简单的屏保效果----------- 效果图如下:效果很神奇,就是这个div在浏览器窗口不断的灵活移动 代码却很简单 <!DOCTYPE html> ...

  8. 低秩稀疏矩阵恢复|ADM(IALM)算法

    一曲新词酒一杯,去年天气旧亭台.夕阳西下几时回? 无可奈何花落去,似曾相识燕归来.小园香径独徘徊. ---<浣溪沙·一曲新词酒一杯>--晏殊 更多精彩内容请关注微信公众号 "优化 ...

  9. web实现点击左侧导航,右侧加载不同的网页(这种布局多用于后台管理系统)

    (1)实现方法:采用ajax实现点击左侧菜单,右侧加载不同网页(在整个页面无刷新的情况下实现右侧局部刷新,用到ajax注意需要在服务器环境下运行,从HBuilder自带的服务器中打开浏览效果即可) ( ...

  10. python中方法调用和函数调用的区别

    函数调用: 传几个参数,就会有几个实参方法调用: 默认传递一个参数self,至少要定义一个形参