面试官:能解释一下javascript中bind、apply和call这三个函数的用法吗
作者:小土豆biubiubiu
掘金: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这三个函数的用法吗的更多相关文章
- javascript中bind,apply,call的相同和不同之处
javasctipt中bind,apply,call的相同点是: 1,都是用来改变this的指向; 2,都可以通过后续参数进行传参; 3,第一个参数都是指定this要指向的对象; 不同点: 1,调用方 ...
- 面试系列-面试官:你能给我解释一下javascript中的this吗?
一.前言 关于javascript中的this对象,可能已经被大家说烂了. 即使是这样,我依然决定将这篇文章给水出来.毕竟全国在新型肺炎的影响下,公司没法正常复工. 除了刷刷手机,还是要适当的学习一下 ...
- 博文推荐】Javascript中bind、call、apply函数用法
[博文推荐]Javascript中bind.call.apply函数用法 2015-03-02 09:22 菜鸟浮出水 51CTO博客 字号:T | T 最近一直在用 js 写游戏服务器,我也接触 j ...
- JavaScript中bind、call、apply函数用法详解
在给我们项目组的其他程序介绍 js 的时候,我准备了很多的内容,但看起来效果不大,果然光讲还是不行的,必须动手.前几天有人问我关于代码里 call() 函数的用法,我让他去看书,这里推荐用js 写服务 ...
- javascript中call,apply,bind的用法对比分析
这篇文章主要给大家对比分析了javascript中call,apply,bind三个函数的用法,非常的详细,这里推荐给小伙伴们. 关于call,apply,bind这三个函数的用法,是学习java ...
- php中print_r、var_dump和var_export几个函数的用法区别
php中print_r.var_dump和var_export几个函数的用法区别
- JavaScript中bind、call、apply函数使用方法具体解释
在给我们项目组的其它程序介绍 js 的时候,我准备了非常多的内容,但看起来效果不大,果然光讲还是不行的,必须动手. 前几天有人问我关于代码里 call() 函数的使用方法.我让他去看书,这里推荐用js ...
- javascript中的apply,call,bind详解
apply.call 在 javascript 中,call 和 apply 都是为了改变某个函数运行时的上下文(context)而存在的,换句话说,就是为了改变函数体内部 this 的指向. Jav ...
- 面试官:能手写实现call、apply、bind吗?
1 call.apply.bind 用法及对比 1.1 Function.prototype 三者都是Function原型上的方法,所有函数都能调用它们 Function.prototype.call ...
随机推荐
- 「洛谷P1233」木棍加工 解题报告
P1233 木棍加工 题目描述 一堆木头棍子共有n根,每根棍子的长度和宽度都是已知的.棍子可以被一台机器一个接一个地加工.机器处理一根棍子之前需要准备时间.准备时间是这样定义的: 第一根棍子的准备时间 ...
- 「学习笔记」ST表
问题引入 先让我们看一个简单的问题,有N个元素,Q次操作,每次操作需要求出一段区间内的最大/小值. 这就是著名的RMQ问题. RMQ问题的解法有很多,如线段树.单调队列(某些情况下).ST表等.这里主 ...
- ScheduledThreadPoolExecutor中定时周期任务的实现源码分析
ScheduledThreadPoolExecutor是一个定时任务线程池,相比于ThreadPoolExecutor最大的不同在于其阻塞队列的实现 首先看一下其构造方法: public Schedu ...
- 基于springboot+thymeleaf+springDataJpa自带的分页插件实现完整的动态分页
实现百度搜索使用的前五后四原则,效果如下. 下面贴出代码,复制到前端即可,只需要域中放置page对象就可以.(springdatajpa自带的page 注意:第一页是按0开始算的) <div c ...
- Python 任务自动化工具:nox 的配置与 API
英文 | Configuration & API 出处 | nox 官方文档 译者 | 豌豆花下猫@Python猫 Github地址:https://github.com/chinesehua ...
- 一款精美的Toast第三方库的简单使用
以前一直用的安卓原生Toast,个人感觉Toast这东西,没必要花功夫,知道看到了Toasty这东西,立刻被圈粉了,真的非常好看. 项目地址 我们都知道,安卓原生Toast的用法是 Toast.mak ...
- Python使用requests爬取一个网页并保存
#导入 requests模块import requests #设置请求头,让网站监测是浏览器 headers = { 'user-agent': 'Mozilla/5.0 (Windows NT 6. ...
- 一步一步教你PowerBI利用爬虫获取天气数据分析
对于爬虫大家应该不会陌生,我们首先来看一下爬虫的定义:网络爬虫是一种自动获取网页内容的程序,是搜索引擎的重要组成部分.网络爬虫为搜索引擎从万维网下载网页,自动获取网页内容的应用程序.看到定义我们应该已 ...
- 枚举 xor
题意:输入整数n(1<=n<=3千万),有多少对整数(a,b)满足:1<=b<=a<=n,且gcd(a,b)=a XOR b.例如:n=7时,有4对:(3,2),(5,4 ...
- 《C# 爬虫 破境之道》:第二境 爬虫应用 — 第三节:处理压缩数据
续上一节内容,本节主要讲解一下Web压缩数据的处理方法. 在HTTP协议中指出,可以通过对内容压缩来减少网络流量,从而提高网络传输的性能. 那么问题来了,在HTTP中,采用的是什么样的压缩格式和机制呢 ...