JavaScript 中的箭头函数
先决条件:JavaScript 中的 this
在这篇文章中,讨论了 JavaScript 中更多与this相关的函数。
this 和箭头函数:
ES6 中引入的箭头函数提供了一种在 JavaScript 中编写函数的简洁方法。
它提供的另一个显着优势是它不绑定自己的this
。换句话说,箭头函数内的上下文是词法或静态定义的。
我们的意思是什么?
与其他函数不同, this
内部箭头函数的值不依赖于它们的调用方式或定义方式。它仅取决于其封闭上下文。
让我们试着用一个例子来理解:
输出:
[object Object]
undefined is undefined years old
我们得到未定义的输出而不是正确的输出信息的原因是因为被定义为 setTimeout 回调的function()
有一个正常的函数调用,正如我们所知,这意味着它的上下文被设置为全局上下文或其他单词this
的值设置为 window 对象。
发生这种情况是因为每个常规的非箭头函数根据它们的调用定义了自己的this
或上下文。封闭对象/函数的上下文不会影响这种自动定义自己的上下文的趋势。
我们如何解决这个问题?
想到的一个明显的解决方案是,如果函数没有定义自己的上下文怎么办?如果它从info()
继承上下文怎么办,因为这意味着这个函数() 获得了在info()
定义的this
嗯,这正是箭头功能do.They保留的价值this
从他们的封闭
语境。
也就是说,在上面的例子中,如果定义为setTimeout()
回调的函数是一个箭头函数,它将从它的封闭上下文中继承this
的值 – info()
输出:
[object Object]
John is 21 years old
因此,无论是使用函数调用还是方法调用来调用箭头函数,它都会从其封闭上下文中保留this
的 ] 值。换句话说,箭头函数的this
值与其直接在其外部的值相同。
如果在任何封闭函数之外使用,箭头函数继承全局上下文,从而将this
的值设置为全局对象。
这在单独的方法中:
当来自任何对象的方法与其分离或存储在变量中时,例如: let separated = People.info
,它会丢失对其调用对象的引用。
请注意info
之后缺少左括号和右括号。这表明我们没有立即调用该方法。
例如 :
输出:
[object Object] John is 21 years old
[object Window] undefined is undefined years old
一旦我们通过将info()
与person1
对象存储在person1
其从person1
对象中separated
,我们就会丢失对person1
对象的所有引用。
我们不能再通过在分离方法中使用this
访问父对象,因为分离方法的上下文被重置为全局上下文。
因此,当我们调用separated()
我们看到this
现在被设置为全局窗口对象。
我们如何解决这个问题?
一种方法是在bind
方法存储在separated
时将对象的值与方法bind
。这确保了所有引用this
指的是此绑定对象甚至在分离的方法。
这可以使用bind()
来完成,如下所示:
输出:
[object Object] John is 21 years old
[object Object] John is 21 years old
注意:我们可以使用任何对象将bind()
到方法info()
,而不是 code.person1,并且输出会相应地改变。将方法绑定到它的父对象不是强制性的。
如果你已经走到这一步,你会注意到我们提到了bind()
几次。
现在让我们研究一下什么是bind(), call() and apply()
。
绑定、调用和应用
bind()、call() 和 apply() 都用于修改函数的上下文。所有这三个都有助于明确指定函数内this
的值。
但是,它们各自的工作方式存在某些差异。让我们研究这些差异。
绑定()
bind() 允许我们通过将对象绑定到该函数来显式定义this
在函数内将具有的值。
绑定对象用作它绑定到的函数的上下文( this
值)。
要使用它,我们主要需要两个东西——一个绑定到函数的对象和一个绑定这个对象的函数。
绑定的一般语法是:
boundfunction = someFunction.bind(someObject, additionalParams);
bind() 指令中使用的第一个参数用作this
值,它后面的参数是可选的,用作绑定函数的参数。
输出:
Orange is orange
Banana is Yellow
请注意,我们使用方法调用: fruit1.displayInfo
在fruit1 上调用displayInfo(),因此可能期望它具有fruit1
的上下文。然而,情况似乎并非如此,因为“香蕉是黄色”而不是“橙色是橙色”被记录下来。
发生这种情况是因为我们使用bind()
命令将 displayInfo() 中this
的值显式绑定到bindingObj
。
正如我们所见,将对象显式绑定到函数会覆盖其正常的上下文规则,并将所有this
值强制设置为其中的绑定对象。
通常,在传递函数时,它会丢失上下文。例如:
输出:
[object Window] undefined
为了防止在作为回调传递的函数内部重置上下文,我们明确地将this
的值绑定到与passAround()
内部相同的值,即: binding
到binding
对象:
输出:
[object Object] John
调用()和应用()
call() and apply()
通过显式指定this
应该存储在函数的值来执行类似于 bind 的任务。
然而,它们与bind()
之间的一个主要区别是call() and apply()
立即调用函数,而不是简单地准备一份带有this
值的函数副本以备将来使用。
语法:
打电话:
function.call(thisValue, arg1, arg2, ...)
申请:
function.apply(thisValue, [ arg1, arg2, ...])
这两种情况下的第一个参数是我们希望被调用函数具有的this
值。
本质上,这两种方法之间的唯一区别在于,在apply
,第二个参数是一个参数数组对象,而在call
,所有参数都以逗号分隔的格式发送。
例如:
输出:
[object Object] Banana is yummy
[object Object] Orange is sour
注意: call()
和apply()
都是默认函数对象原型上可用的方法。
这与事件侦听器
在用作事件侦听器回调的函数内部, this
保存触发事件的元素的值。
如果这里使用的回调函数是一个箭头函数并且我们的事件侦听器嵌套在另一个方法中,则this
将引用外部嵌套方法的上下文,并且我们无法再使用this
访问添加事件侦听器的元素,就像我们在前面的代码示例中所做的那样。
幸运的是,这可以通过在元素上使用currentTarget
方法轻松解决,如下所示:
输出:
[object HTMLButtonElement] Correctly identified!
正如我们所见,使用currentTarget
允许我们访问添加事件侦听器的元素,同时this
允许我们访问封闭函数的上下文——即: this
允许我们成功调用 displayInfo() 方法。