bind
bind()
方法创建一个新的函数,在 bind()
被调用时,这个新函数的 this
被指定为 bind()
的第一个参数,而其余参数将作为新函数的参数,供调用时使用。
参数
thisArg
调用绑定函数时作为 this
参数传递给目标函数的值。
- 如果使用
new
运算符构造绑定函数,则忽略该值。 - 当使用
bind
在setTimeout
中创建一个函数(作为回调提供)时,作为thisArg
传递的任何原始值都将转换为object
。 - 如果
bind
函数的参数列表为空,或者thisArg
是null
或undefined
,执行作用域的this
将被视为新函数的thisArg
。
arg1, arg2, ...
当目标函数被调用时,被预置入绑定函数的参数列表中的参数。
返回值
返回一个原函数的拷贝,并拥有指定的 this
值和初始参数。
描述
bind() 函数会创建一个新的绑定函数(bound function,BF)。绑定函数是一个 exotic function object(怪异函数对象,ECMAScript 2015 中的术语),它包装了原函数对象。调用绑定函数通常会导致执行包装函数。
绑定函数具有以下内部属性:
- [[BoundTargetFunction]] - 包装的函数对象(即新生成的函数)。
- [[BoundThis]] - 在调用包装函数时始终作为 this 值传递的值。
- [[BoundArguments]] - 列表,在对包装函数做任何调用都会优先用列表元素填充参数列表。
- [[Call]] - 执行与此对象关联的代码。通过函数调用表达式调用。内部方法的参数是一个this值和一个包含通过调用表达式传递给函数的参数的列表。
当调用绑定函数**[[BoundTargetFunction]]**时,它调用 [[BoundTargetFunction]] 上的内部方法 **[[Call]]**,就像这样 Call(*boundThis*, *args*)。其中,boundThis 是 [[BoundThis]],args 是 [[BoundArguments]] 加上通过函数调用传入的参数列表。
绑定函数也可以使用 new
运算符构造,它会表现为目标函数已经被构建完毕了似的。提供的 this
值会被忽略,但前置参数仍会提供给模拟函数。
用法
改变this指向(创建绑定this指向的函数)
1 | let a = 'outterA' |
偏函数
通俗的讲,偏函数就是指通过一个初始函数A
,创建出另外的函数A1
,A2
,这两个函数含有了初始参数1,2。这里使用bind
是利用了他的两个特点。
bind
返回的是绑定函数,区别与Function.prototype.call()
,Function.prototype.apply()
的立即执行- 其接受的是参数列表,并且会与绑定函数调用时的参数合并作用
[[call]]
原函数,区别于Function.prototype.apply()
1 | function add(arg1, arg2){ |
改变setTimeout,setInterval的this指向
由于setTimeout
,setInterval
的函调函数中this
的指向总是window
(即使在严格模式下)。所以可以使用bind
改变回调函数中的this
指向。
1 | let obj = { |
作为构造函数使用的绑定函数
与偏函数用法类似,相当于为构造器提供默认参数。
1 | function Point(x, y){ |
快捷调用
一些特定的函数被绑定在特定数据类型种,最典型的例子就是Array.prototype.slice
,其只能由数组调用。实际上这个函数也接受类数组的对象(array-like object),这个时候实际上是要改变this的调用。
一般的用法:
1 | let slice = Array.prototype.slice |
在使用bind
后,由于其可以生成绑定函数,所以将要使用的函数作为this
就可以不用每次都使用apply
。
1 | let unboundSlice = Array.prototype.slice; |
兼容性
Pollyfill
法一:
1 | // Does not work with `new (funcA.bind(thisArg, args))` |
这里利用了Function.prototype.apply
构造一个函数,运行及执行apply
方法,达到bind
的特点。
法二:
1 | // Yes, it does work with `new (funcA.bind(thisArg, args))` |
call
call()
方法使用一个指定的 this
值和单独给出的一个或多个参数来调用一个函数。
注意:该方法的语法和作用与 apply()
方法类似,只有一个区别,就是 call()
方法接受的是一个参数列表,而 apply()
方法接受的是一个包含多个参数的数组。
参数
thisArg
可选的。在 function
函数运行时使用的 this
值。请注意,this
可能不是该方法看到的实际值:如果这个函数处于非严格模式下,则指定为 null
或 undefined
时会自动替换为指向全局对象,原始值会被包装。
arg1, arg2, ...
指定的参数列表。(与bind
一样)
描述
call
方法相较于bind
,他会生成一个绑定函数并立即调用。
用法
基本方法:改变this
指向
1 | let obj = { |
使用 call
方法调用父构造函数
使用call
方法绑定this
对象为自己子类中,则可以完成对父构造器的调用。达到简单的继承效果。
1 | function Product(name, price){ |
为匿名函数指定this
对象
1 | let obj = { |
兼容性
Pollyfill
1 | if (!Function.prototype.call) { |
apply
apply()
方法调用一个具有给定this
值的函数,以及以一个数组(或类数组对象)的形式提供的参数。
参数
thisArg
必选的。在
func
函数运行时使用的this
值。请注意,this
可能不是该方法看到的实际值:如果这个函数处于非严格模式下,则指定为null
或undefined
时会自动替换为指向全局对象,原始值会被包装。argsArray
可选的。一个数组或者类数组对象,其中的数组元素将作为单独的参数传给
func
函数。如果该参数的值为null
或undefined
,则表示不需要传入任何参数。从ECMAScript 5 开始可以使用类数组对象。
返回值
调用有指定**this
**值和参数的函数的结果。
描述
apply
与call()
非常相似,不同之处在于提供参数的方式。apply
使用参数数组而不是一组参数列表。apply
可以使用数组字面量(array literal),如fun.apply(this, ['eat', 'bananas'])
,或数组对象, 如fun.apply(this, new Array('eat', 'bananas'))
。你也可以使用
arguments
对象作为argsArray
参数。arguments
是一个函数的局部变量。 它可以被用作被调用对象的所有未指定的参数。 这样,你在使用apply函数的时候就不需要知道被调用对象的所有参数。 你可以使用arguments来把所有的参数传递给被调用对象。 被调用对象接下来就负责处理这些参数。从 ECMAScript 第5版开始,可以使用任何种类的类数组对象,就是说只要有一个
length
属性和(0..length-1)
范围的整数属性。例如现在可以使用NodeList
或一个自己定义的类似{'length': 2, '0': 'eat', '1': 'bananas'}
形式的对象。需要注意:Chrome 14 以及 Internet Explorer 9 仍然不接受类数组对象。如果传入类数组对象,它们会抛出异常。
用法
基本方法:改变this
指向
1 | let obj = { |
函数数组参数变为列表参数+使用内置函数
1 | let arr = [2,3,4,5,7] |
在ES6中扩展运算符(spread)···
来实现函数数组参数变为列表参数:
1 | let arr = [2,3,4,5,7] |
兼容性
Pollyfill
1 | if (!Function.prototype.apply) { |