You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
var fruit = {
fruitName:"apple"
}
function getFruit() {
console.log("I like "+this.fruitName)
}
getFruit(); // log I like undefined
getFruit.call(fruit) // log I like apple
getFruit.apply(fruit) // log I like apple
var newBind = getFruit.bind(fruit)
newBind(); // log I like apple
Uh oh!
There was an error while loading. Please reload this page.
call,apply and bind in JavaScript
文章尽量使用大量实例进行讲解,它们的使用场景。同时,也会由浅入深的引导出一些理论,毕竟这几个常用方法,在MDN上都能找到合理的解释
基本功能
改变this的指向
当 getFruit 并非作为一个对象的属性,而是直接当做一个函数来调用,里面的
this
就会被绑定到全局对象上,即window上, 所以直接调用getFruit
,里面的this
指向了全局对象上,返回undefined
。后面,通过调用函数上的
call
和apply
方法,该变this
指向,函数里面的this
指向fruit
。区别:
bind
同样实现了改变this
指向的功能,但是它不会立即执行,而是会重新创建一个绑定函数,新函数被调用时,使用bind()
方法里面的第一个参数作为this
接受参数
这三个方法,从接受的第二参数开始,都直接传递给函数,但是接受参数的方法却很大的不同。
call,从第二个参数开始,以参数列表的形式展示,
apply,则把传递的函数参数,放在一个数组里面作为第二个参数。
bind,从第二个参数开始,同样以参数列表的形式,但是会提前放在新绑定函数的参数之前
应用场景
通常,我们在改变函数上下文之前,都会使用类似
that = this
,或者self,_this
,来把this赋值给一个变量。利用.bind()
,可以传入外层的上下文。循环中利用闭包来处理回调
每次循环,都会产生一个立即执行的函数,函数内部的局部变量j保存不同时期i的值,循环过程中,setTimeout回调按顺序放入消息队列中,等for循环结束后,堆栈中没有同步的代码,就去消息队列中,执行对应的回调,打印出j的值。
同理,可以利用
bind
,每次都创建新的函数,并且已经预先设置了参数,传入不同的指针实质上,可以看成通过
call()
或者apply()
方法,在即将新建的对象,即这里的newPerson
上,执行超类型的构造函数,分别在当前上下文this
上添加name
和age
属性。借用了Object原生的toString()方法,打印出对应变量的构造函数名,
首先,利用
this.splice.apply()
,其中splice
,可以直接从数组中移除或者插入变量。apply()
则以数组的形式传递参数,需要利用concat
拼接数组。当函数被调用时,在函数内部会得到类数组
arguments
,它拥有一个length属性,但是没有任何数组的方法。所以,将slice
方法中的this
指向arguments
,获取到arguments
的长度,从而确定方法的start
和end
下标,得到一个数组变量。同样适用的还有,DOM里面的NodeList对象,它也是一种类数组对象。
深入理解
实现bind 方法
bind
方法在ECMAScript5里面被引入,前面提到过,调用该方法时,返回一个新的函数,可以简单使用下面方法实现其改变this
指向的功能。接着,就可以利用
concat
把bind传递的预置参数拼接到新函数的参数列表中。参考链接
The text was updated successfully, but these errors were encountered: