call,apply和bind,其实很简单
call和apply
call和aplly作用完全一样,都是在特定的上下文中调用函数,或者说改变函数内部的this指向;区别仅在于接收参数的方式不同。
var dog = {
name: "dog"
};
var cat = {
name: "cat"
};
var sayName = function (age, gender) {
console.log(this.name + "," + age + "," + gender)
};
sayName(); //undefined
sayName.call(dog, 2, "male"); //dog,2,male
sayName.call(cat, 3, "female"); //cat,3,female
sayName.apply(dog, [2, "male"]); //dog,2,male
sayName.apply(cat, [3, "female"]); //cat,3,female
我们在全局环境定义了一个sayName方法,调用该方法时会将当前环境的name属性(this.name)显示到控制台上。当我们在全局环境调用sayName()时,由于全局环境并没有this.name属性(注意,浏览器window对象上有name属性,这里指node环境),因此显示了undefined。
使用call或者apply,就可以改变函数的执行环境,或者说改变函数内部的this指向。例如sayName.call(dog),表示将sayName内部的this指向了dog对象,因此this.name显示为"dog"。当我们调用sayName.call(cat)时,sayName内部的this又指向了cat对象。
可以看出来,call与apply的作用完全相同,区别仅在于接收参数的方式不同。
fn.call(context, arg1, arg2, ...)
fn.apply(context, [arg1, arg2, ...])
call和apply接收的第一个参数都是函数的运行环境。使用call时传递给函数的参数必须逐个传入,而使用apply时函数的参数应该是一个数组,或者类数组对象(如arguments对象)。至于使用call还是apply,完全取决于采用哪种方法给函数传递参数更方便。在不需要给函数传递参数的情况下,使用哪个方法都无所谓。
bind
bind也可以改变函数内部的this指向,区别在于bind不会直接调用该函数,而是返回一个绑定了this的函数,由你来决定什么时候调用。
var dog = {
name: "dog"
};
var cat = {
name: "cat"
};
var sayName = (function (age, gender) {
console.log(this.name + "," + age + "," + gender)
}).bind(dog, 3, "male");
sayName.call(cat, 2, "female"); //dog,3,male
我们创建sayName函数时,使用bind将该函数的this指向了dog对象,同时还绑定了传入函数的参数。
现在我们调用sayName.call(cat, 2, "female"),发现不论是this对象,还是传入函数的参数,都是之前被绑定的值。
bind像call一样接受多个参数,第一个参数为context(即内部this值),后面的参数依次为函数接收的参数
用途
call和apply适合用在只需要临时改变函数运行环境的地方,可以用来共享一些方法。最经典、实用的莫过于Array.prototype.slice.call(arguments)了,利用call可以直接在类数组对象上调用Array的slice方法,方便的将类数组对象转换成真正的数组对象。
bind方法适合用在将某个函数以值的形式传递,同时该函数必须在特定的环境中执行的时候,例如一些事件处理程序,回调函数和setTimeout()、setInterval()等。例如:
var alarmClock = {
time: function () {
return new Date();
},
alarm: function () {
console.log(this.time())
}
};
setInterval(alarmClock.alarm,1000); //TypeError: this.time is not a function
setInterval(alarmClock.alarm.bind(alarmClock),1000); //Thu May 18 2017 12:32:44 GMT+0800 (中国标准时间)
当直接将alarmClock.alarm传递给setInterval()时,因为alarmClock.alarm调用的环境是setInterval,即全局环境,其中没有time方法,于是TypeError。
通过使用bind(alarmClock),就可以将alarmClock.alarm的运行环境绑定到alarmClock对象上,这样每次执行都可以获得正确的结果。
另外,bind还可以用在函数柯里化。
总结
call,apply和bind其实很简单,无非就是改变了函数内部的this指向而已,区别仅仅是使用的方法和场景不同。
call,apply和bind,其实很简单的更多相关文章
- 简单模拟实现javascript中的call、apply、bind方法
目录 引子 隐式丢失 硬绑定 实现及原理分析 总体实现(纯净版/没有注释) 写在最后 引子 读完<你不知道的JavaScript--上卷>中关于this的介绍和深入的章节后,对于this的 ...
- call、apply和 bind的简单使用方法
- call.apply:在 javascript 中,call 和 apply 都是为了改变某个函数运行时的上下文(context)而存在的,换句话说,就是为了改变函数体内部 this 的指向. J ...
- JS核心系列:浅谈 call apply 与 bind
在JavaScript 中,call.apply 和 bind 是 Function 对象自带的三个方法,这三个方法的主要作用是改变函数中的 this 指向,从而可以达到`接花移木`的效果.本文将对这 ...
- JS中call、apply、bind使用指南,带部分原理。
为什么需要这些?主要是因为this,来看看this干的好事. box.onclick = function(){ function fn(){ alert(this); } fn();}; 我们原本以 ...
- js里function的apply vs. bind vs. call
js里除了直接调用obj.func()之外,还提供了另外3种调用方式:apply.bind.call,都在function的原型里.这3种方法的异同在stackoverflow的这个答案里说的最清楚, ...
- JS中的call、apply、bind方法
JS中的call.apply.bind方法 一.call()和apply()方法 1.方法定义 call方法: 语法:call([thisObj[,arg1[, arg2[, [,.argN]]] ...
- js中call、apply、bind那些事
前言 回想起之前的一些面试,几乎每次都会问到一个js中关于call.apply.bind的问题,比如- 怎么利用call.apply来求一个数组中最大或者最小值 如何利用call.apply来做继承 ...
- js的call,apply,bind的使用与区别
在原生js中会有三个很常见的函数,call,apply,bind 他们的作用就是改变当前函数的this指针, 但是细微来说他们还是有不同的. 1)call,apply都是执行某一函数,发现this有变 ...
- javascript中call()、apply()、bind()的用法终于理解
其实是一个很简单的东西,认真看十分钟就从一脸懵B 到完全 理解! 先看明白下面: 例1 obj.objAge; //17 obj.myFun() //小张年龄undefined 例2 shows( ...
随机推荐
- zookeeper的安装与部署-集群
1.Zookeeper的下载与解压 通过后面的链接下载Zookeeper: Zookeeper下载在此我们下载zookeeper-3.4.5下载后解压至安装目录下,本文我们解压到目录:/ ...
- QTP自动化测试框架课程的目标
QTP自动化测试框架课程的目标 随着技术发展演变,qtp自动化测试工具有逐渐被其他工具和技术替换的趋势,所以我们三个POPTEST合伙人决定把qtp自动化测试的一套课程开放免费,这套qtp自动化测试课 ...
- sqoop 操作从hdfs 导入到mysql中语句
将hdfs下/dw/dms/usr_trgt下的文件导入到mysql中test数据库下usr_trgt表中 sqoop-export --connect jdbc:mysql://mysqlDB: ...
- C#重的数组、集合(ArrayList)、泛型集合(list<T>)三者比较及扩展延伸……
本来我只想总结下数组.集合(ArrayList).泛型集合(list<T>)三者的比较的,可以一写下来要扩展的知识点有点多了,只能写一个小的知识点列表了如下: 1.数组.集合(ArrayL ...
- asp.net core源码飘香:Options组件
简介: Options组件是一个小组件,但用的地方很多.它本质是将一个POCO类注册到容器中(主要在Startup中作为其他组件的配置功能提供),后续使用的时候就可以通过比如构造函数注入等获取到POC ...
- 1145: 零起点学算法52——数组中删数II
1145: 零起点学算法52--数组中删数II Time Limit: 1 Sec Memory Limit: 64 MB 64bit IO Format: %lldSubmitted: 293 ...
- Java中ArrayList,Vector,LinkedList,HashMap,HashTable,HashSet对比及总结
1.所有的集合的父类都是Collection的接口 2.Set List Map 区别 A 在Set里面:无法添加元素的顺序,所以Set里面的元素不能重复 B 在List中:有索引号,类似于数组, ...
- MySQL一个简单的存储过程demo
使用的工具是Navicat for MySQL. 首先创建一个学生表 mysql) ) ) auto_increment,age ) ) not null,primary key(s_no)); Qu ...
- node服务成长之路
我们的系统也从第一代平台开始到现在第四代平台更换中,对这四代平台做一个简单的介绍: 第一代平台,主要是集中式,以快速上线为目的:第二代平台主要是分布式改造,缓解各服务压力:第三代平台主要做服务端SOA ...
- Redis编码问题
最近搞redis存储对象出了点问题,大概说一下背景,项目原有的东东以前存的是redis,存储的直接是对象模型,没有问题,这里存储对象存储任何信息事都没有问题的.但是现在调整为存储序列化的json字符串 ...