人只有献身于社会,才能找出那短暂而有风险的生命的意义。 ——<阿尔伯特·爱因斯坦>
作者:Ashish Lahoti
译者:cl9000
来源:https://codingnconcepts.com/javascript/call-vs-bind-vs-apply/
这是JavaScript
面试中经常被问到的问题。这篇文章描述了函数原型方法call()
、apply()
和bind()
及其语法、用法和实际示例。
Function.prototype是什么?
首先,我们需要了解这三个函数的调用、应用和绑定都是函数的原型。这是什么意思?
让我们打印函数的结构来理解它。
1 | console.dir(Function); |
1 | ▼ ƒ Function() |
您可以看到,apply
、bind
和call
是Function
的原型函数,这意味着您可以在定义的任何新函数上使用这三个函数。
何时使用call()、bind()和apply()
当您定义一个新函数并从代码中的某个地方调用它时,它将在上下文中执行。这个上下文称为 this
,它指向一个对象。这个对象根据调用函数的方式而变化。
1 | var a = 1; |
Output
2
3
4
在上面的代码片段中,我们在三个不同的上下文中调用了同一个increment()
函数,这改变了this
引用,并产生了三个不同的输出。
- 第一个
increment()
函数在全局上下文中被调用,并绑定到全局对象。如果您在浏览器中工作,window
是全局对象。 - 接下来的两个
increment()
函数在隐式上下文中被调用,这个函数绑定到调用函数的对象。这被称为隐式上下文,因为函数与对象紧密耦合(在object
内部定义),当从obj.ƒn()
这样的对象调用函数时,这个引用在编译时绑定到object
。
有时,我们可能希望在显式上下文中调用函数,这样我们就可以在运行时调用函数时控制该引用。这就是call()
、apply()
和bind()
发挥作用的地方。让我们使用call()
、apply()
和bind()
方法来调用相同的increment()
函数。
1 | var increment = function(){ |
Output
5
6
5
6
5
6
从上面的代码片段注意几点:-
- 所有这三个
call()
、apply()
和bind()
都是Function
的原型,所以你可以在任何函数increment.call()
、increment.apply()
和increment.bind()
上使用它们。 - 这三个
call()
、apply()
和bind()
在运行时提供不同的对象上下文(obj1、obj2)
,并产生不同的输出。 call()
和apply()
立即执行一个函数,bind()
则返回一个可以稍后执行的绑定函数。
现在我们已经理解了这些原型函数的基本用法,让我们通过示例来看看它们的语法和实际用法。
call()
语法
1 | functionName.call(thisArg, arg1, arg2, ...) |
当使用call()
调用函数时,
this
指的是thisArg
- 逗号分隔的参数
arg1, arg2…
是函数的参数
记住:“call()参数用逗号分隔”。
实际使用情况
1. 借用其他对象的功能
在Javascript
中,每个对象都可以有原型函数,这些函数实际上只在该对象上执行。使用call()
方法,您可以借用这些对象的功能,并在不同的对象上执行它。
让我们来看看数组原型函数
1 | console.dir(Array); |
1 | Output |
让我们借用数组原型方法的功能call()
函数:-
1 | Array.prototype.concat.call([1,2,3], [4,5]); |
Output
[1, 2, 3, 4, 5]
1:2:3:4:5
同样借用car
对象的start
功能,将其用于aircraft
1 | var car = { |
2. 链构造函数
1 | function Box(height, width) { |
在上面的代码片段中,我们可以看到如何在当前this
上下文中通过调用父构造函数来链构造函数.
apply()
语法
1 | functionName.apply(thisArg, [arg1, arg2, ...]) |
当使用apply()
方法调用函数时,
this
指的是thisArg
- 第二个参数是一个值数组[arg1, arg2,…],是函数的参数
记住:
apply()
接受数组形式的参数
实际用法
apply()
函数的实际用法与call()
函数相同。它们之间唯一的区别是,apply()
接受args
作为数组,而call()
接受args
作为逗号分隔的值。
可以使用apply()
函数将参数作为数组传递,调用任何接受参数作为逗号分隔值的函数。
1 | Math.min(1, 2, 3, 4, 5); //args as comma separated |
bind()
语法
1 | functionName.bind(thisArg) |
当使用bind()方法调用函数时,
- this指的是thisArg
- 返回可以稍后调用的新的绑定函数
记住:
bind()
不会立即调用函数。它返回一个新的可以稍后调用的绑定函数。
实际用法
1. 上下文界限
1 | var Button = function(content) { |
Output
OK clicked
undefined clicked
OK clicked
2. 函数与参数绑定
1 | var logProp = function(prop) { |
Output
5
5
10
10
另外一个例子
1 | var sum = function(a, b) { |
Output
15
Call vs Bind vs Apply
函数对象、函数objects
、函数calls
、call
、apply
和bind
的比较:
函数执行时间 | this 绑定时间 |
|
---|---|---|
function object ƒ | future | future |
function call ƒ() | now | now |
ƒ.call() | now | now |
ƒ.apply() | now | now |
ƒ.bind() | future | now |
让我们看一下最后一个例子,并一起使用call()
、apply()
和bind()
方法.
1 | let numObj1 = {num: 1}; |
output:
11
12
11
12
11
12
参考
- 原文 - https://codingnconcepts.com/javascript/call-vs-bind-vs-apply/
- MDN - https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function
关注【公众号】,了解更多。
关注【公众号】,了解更多。
关注【公众号】,了解更多。
赞赏一下 坚持原创技术分享,您的支持将鼓励我继续创作!