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( ...
随机推荐
- spring security 3.x 多页面登录配置入门教程
最近在最shiro的多入口登录,搞了好久,就把spring security拿出来再炒一下,这是我以前在csdn写过的一篇博客. spring security 是一个权限控制的框架.可以很方便地实现 ...
- jquery treeTable插件使用细则
简介 treeTable是跨浏览器.性能很高的jquery的树表组件,它使用非常简单,只需要引用jquery库和一个js文件,接口也很简单. 优点 兼容主流浏览器: 支持IE6和IE6+, Firef ...
- Vijos1144小胖守皇宫【树形DP】
皇宫看守 太平王世子事件后,陆小凤成了皇上特聘的御前一品侍卫.皇宫以午门为起点,直到后宫嫔妃们的寝宫,呈一棵树的形状:某些宫殿间可以互相望见.大内保卫森严,三步一岗,五步一哨,每个宫殿都要有人全天候看 ...
- 性能测试培训:批量执行Jmeter脚本之ant调用
性能测试培训:批量执行Jmeter脚本之ant调用 poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.在poptest的load ...
- Java中一个方法只被一个线程调用一次
1.想在运行时抛出异常,终止方法的运行 private final Set<Long> THREADS = new HashSet<>(); public void someM ...
- Nodejs安装后修改全局路径配置
--以Windows平台为例,类Unix平台操作方式相同 1. 新建保存node_modules的文件夹,例如我的路径为:D:\NodeJS Lib\npm 2. 在DOS窗口输入以下代码,把缓存及储 ...
- MAT(Memory Analyzer Tool)使用心得
起因:最近在跟踪产品的性能问题,期间主要问题体现在JVM的内存回收问题,使用MAT工具进行JVM内存分析(也可对android 的应用内存分析) 问题描述: 1.部分后端服务在运行一段时间后会突然年老 ...
- Android使用本地广播
Android本地广播学习中一直被忽略,今天用到了,Mark一下 1.本地广播的定义和普通广播一样 例如 public class WakeTimesBroadcastReceiver extends ...
- JavaScript运算符优先级
图片引用自:http://www.cnblogs.com/xxcanghai/p/5189353.html
- 20分钟快速了解Redis
Redis可以说是目前最火爆的NoSQL数据库! 过去几年,Memcached很盛行,现在有很多公司已将Memcached替换成了Redis.当然,很多人替换并不清楚为什么,只是感觉不想让主流抛弃,这 ...