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,其实很简单的更多相关文章

  1. 简单模拟实现javascript中的call、apply、bind方法

    目录 引子 隐式丢失 硬绑定 实现及原理分析 总体实现(纯净版/没有注释) 写在最后 引子 读完<你不知道的JavaScript--上卷>中关于this的介绍和深入的章节后,对于this的 ...

  2. call、apply和 bind的简单使用方法

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

  3. JS核心系列:浅谈 call apply 与 bind

    在JavaScript 中,call.apply 和 bind 是 Function 对象自带的三个方法,这三个方法的主要作用是改变函数中的 this 指向,从而可以达到`接花移木`的效果.本文将对这 ...

  4. JS中call、apply、bind使用指南,带部分原理。

    为什么需要这些?主要是因为this,来看看this干的好事. box.onclick = function(){ function fn(){ alert(this); } fn();}; 我们原本以 ...

  5. js里function的apply vs. bind vs. call

    js里除了直接调用obj.func()之外,还提供了另外3种调用方式:apply.bind.call,都在function的原型里.这3种方法的异同在stackoverflow的这个答案里说的最清楚, ...

  6. JS中的call、apply、bind方法

    JS中的call.apply.bind方法 一.call()和apply()方法 1.方法定义 call方法: 语法:call([thisObj[,arg1[, arg2[,   [,.argN]]] ...

  7. js中call、apply、bind那些事

    前言 回想起之前的一些面试,几乎每次都会问到一个js中关于call.apply.bind的问题,比如- 怎么利用call.apply来求一个数组中最大或者最小值 如何利用call.apply来做继承 ...

  8. js的call,apply,bind的使用与区别

    在原生js中会有三个很常见的函数,call,apply,bind 他们的作用就是改变当前函数的this指针, 但是细微来说他们还是有不同的. 1)call,apply都是执行某一函数,发现this有变 ...

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

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

随机推荐

  1. 关于压缩jar包时提示*.*没有这个文件或目录的问题以及解决办法:

    关于压缩jar包时提示.没有这个文件或目录的问题以及解决办法: 问题描述: 我在打包jar时,CMD中进入到包的上一层目录. 在命令提示符中输入 提示如下: 从提示中可知没有找到我们想要打包的clas ...

  2. JDK中日期和时间的几个常用类浅析(五)

    LocalDateTime   LocalDateTime是JDK8中才引入的类,用来表示不包含时区信息的本地日期和时间.我们可以把LocalDateTime看作是LocalDate和LocalTim ...

  3. XJOI练习2神奇的供水系统

    神奇的供水系统 在游遍神秘岛过程中,Z4发现每一个小岛上都有若干个奇怪的类似小水缸似的立方体,这另到Z4相当迷惑不解!这天晚上,忽然下起了一场大雨,在中心岛小树屋上类似那个圆形石槽中间的小孔中涌出了一 ...

  4. Nginx基础学习(一)—Nginx的安装

    一.Nginx介绍 1.什么是Nginx?      Nginx是一款高性能的http 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器.由俄罗斯的程序设计师Igor Sysoev所开 ...

  5. 微信小程序,前端大梦想(二)

    微信小程序的视图与渲染  今天我们从四个方面来了解小程序:   •组件的基本使用  •数据绑定  •渲染标签  •模板的使用     一.组件的基本使用:  微信小程序为我们的开发提供了丰富的UI组件 ...

  6. Angular.js学习笔记(三)

    一.过滤器 1.uppercase,lowercase 大小写转换{{ "lower cap string" | uppercase }} // 结果:LOWER CAP STRI ...

  7. get方式提交中文乱码(两次编码,一次解码)

    1.编码XMLHttpRequest //建立连接 xmlhttp.open("get","${pageContext.request.contextPath}/serv ...

  8. 浅谈echo、print、var_dump()、print_r()的区别

    1.echo 和 print 的区别 共同点:首先echo 和 print 都不是严格意义上的函数,他们都是语言结构;他们都只能输出 字符串,整型跟int型浮点型数据.不能打印复合型和资源型数据: 而 ...

  9. Caffe学习系列(四)之--训练自己的模型

    前言: 本文章记录了我将自己的数据集处理并训练的流程,帮助一些刚入门的学习者,也记录自己的成长,万事起于忽微,量变引起质变. 正文: 一.流程 1)准备数据集  2)数据转换为lmdb格式  3)计算 ...

  10. 【Tomcat源码学习】-5.请求处理

    前四章节,主要对Tomcat启动过程中,容器加载.应用加载.连接器初始化进行了相关的原理和代码流程进行了学习.接下来开始进行接受网络请求后的相关处理学习.   一.整体流程      基于上一节图示进 ...