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( ...
随机推荐
- 机器学习:Python中如何使用支持向量机(SVM)算法
(简单介绍一下支持向量机,详细介绍尤其是算法过程可以查阅其他资) 在机器学习领域,支持向量机SVM(Support Vector Machine)是一个有监督的学习模型,通常用来进行模式识别.分类(异 ...
- jQuery购物车
效果图 HTML代码:(非表格方式) <div class="nav2"> <input type="checkbox" class=&quo ...
- Linux简介与厂商版本下
2. Linux的厂商版本 在Linux内核基础上,我们还有许多厂商版本.即使有了内核和GNU软件,Linux的安装和编译并不是简单的工作,Linux厂商就是瞄准了这个市场.这些厂商会在Linux内核 ...
- Android中java层使用LocalSocket和底层进行通讯
原始文件:frameworks\base\services\java\com\android\server\NativeDaemonConnector.java private void listen ...
- jQuery基础学习(一)—jQuery初识
一.jQuery概述 1.jQuery的优点 jQuery是一个优秀的JavaScript库,极大地简化了遍历HTML文档.操作DOM.处理事件.执行动画和开发Ajax的操作.它有以下几点优 ...
- Spring Dubbo 开发笔记(一)——概述
概述: Spring Dubbo 是我自己写的一个基于spring-boot和dubbo,目的是使用Spring boot的风格来使用dubbo.(即可以了解Spring boot的启动过程又可以学习 ...
- Java中集合框架,Collection接口、Set接口、List接口、Map接口,已经常用的它们的实现类,简单的JDK源码分析底层实现
(一)集合框架: Java语言的设计者对常用的数据结构和算法做了一些规范(接口)和实现(实现接口的类).所有抽象出来的数据结构和操作(算法)统称为集合框架. 程序员在具体应用的时候,不必考虑数据结构和 ...
- javascript原型的意义
prototype属性: 这个属性包含一个对象(以下简称"prototype对象"),所有实例对象需要共享的属性和方法,都放在这个对象里面:那些不需要共享的属性和方法,就放在构造函 ...
- 使用opencv实现自定义卷积
对图像进行卷积是图像处理的基本操作,最近在研究图像滤波,经常要用到自定义卷积,所以实现了一下 #include "opencv2/imgproc/imgproc.hpp" #inc ...
- Spring-data-redis操作redis知识汇总
什么是spring-data-redis spring-data-redis是spring-data模块的一部分,专门用来支持在spring管理项目对redis的操作,使用java操作redis最常用 ...