本文共 13278 字,大约阅读时间需要 44 分钟。
javascript指南
by Ashay Mandwarya ?️??
由Ashay Mandwarya提供吗?
The this
keyword hands-down is one of the most widely used and yet misunderstood in JavaScript. I’ll try to change that today.
this
关键字hand-down是JavaScript中使用最广泛但仍被误解的关键字之一。 我今天将尝试更改它。
Let’s go back to the good old school days, when we learned about pronouns.
让我们回到过去的美好时光,那时我们了解了代词。
Phelps is swimming fast because he wants to win the race.
菲尔普斯游刃有余,因为他想赢得比赛。
Note the use of the pronoun “he”. We don’t directly address Phelps here but use the pronoun he to refer to Phelps. Similarly JavaScript uses the this
keyword as a referent to refer to the object in context i.e the subject.
注意代词“ he”的使用。 我们在这里没有直接提及菲尔普斯,而是使用他代词来指代菲尔普斯。 类似地,JavaScript使用this
关键字作为引用来引用上下文中的对象, 即subject 。
Example:
例:
var car= {make: "Lamborghini",model: "Huracán",fullName: function () {console.log(this.make+" " +this.model);console.log(car.make+ " " +car.model);}}car.fullName();
In the above code, we have an object car
which has the properties make
, model
and fullName
. The value of fullName
is a function which prints the full name of the car using 2 different syntaxes.
在上面的代码中,我们有一个对象car
,其属性为make
, model
和fullName
。 fullName
的值是一个函数,它使用两种不同的语法来打印汽车的全名。
Using this
=> this.make+” “ +this.mod
el the t
his refers to the object in context which is c
ar so this.ma
ke is effectively car.m
ake and so is this.mo
del .
使用this
=&g t; this.make+” “ +this.mod
t; this.make+” “ +this.mod
EL the t
他是指对象在上下文中,其is c
AR so this.ma
Ke是有效ly car.m
AKE等is this.mo
德尔。
Using dot notation, we can access the properties of objects, car.make
& car.model
.
使用点符号,我们可以访问对象的属性car.make
和car.model
。
this
就是它! (this
is it!)Now that we have understood what is this
and it’s most basic usage, let’s make some rules of thumb so we can always remember.
现在我们已经明白了什么是this
,它是最基本的用法,让我们的一些经验法则,以便我们能够永远记住。
this
关键字引用了它所属的对象。 (The JS this
keyword refers to the object it belongs to.)var car={make:'....'func:()=>{console.log(this.make)}}
The this
in the above snippet belongs to the object car.
以上代码段中的this
属于对象车。
call()
, and apply().
call()
和apply().
Inside a method
方法内部
When this
is used inside a method, it refers to the owner object.
在方法内部使用this
方法时,它引用所有者对象。
Functions defined inside an object are called methods. Let’s take our car example again.
在对象内部定义的函数称为方法。 让我们再以汽车为例。
var car= {make: "Lamborghini",model: "Huracán",fullName: function () {console.log(this.make+" " +this.model);console.log(car.make+ " " +car.model);}}car.fullName();
fullName()
here is a method. The this
inside this method belongs to car
.
fullName()
这是一个方法。 在this
里面这个方法属于car
。
Inside a function
函数内部
this
inside a function is a bit complicated. First thing to understand is that, like all objects have properties, likewise functions have properties too. Whenever that function is executed, it gets the this
property, which is a variable with the value of the object that invokes it.
this
函数里面有一点复杂。 首先要了解的是,就像所有对象都具有属性一样,函数也同样具有属性。 每当执行该函数时,它都会获得this
属性, this
属性是一个变量,具有调用它的对象的值。
this is really just a shortcut reference for the “antecedent object” — the invoking object. — javascriptissexy.com
这实际上只是“先行对象”(调用对象)的快捷方式引用。 — javascriptissexy.com
If the function is not invoked by an object then the this
inside the function belongs to the global object, which is called window. In this case this will refer to the values defined in the global scope. Let’s see an example for better understanding:
如果该函数未由对象调用,则函数内部的this
属于全局对象,称为窗口。 在这种情况下,这将引用在全局范围内定义的值。 让我们看一个更好理解的例子:
var make= "Mclaren";var model= "720s"function fullName(){ console.log(this.make+ " " + this.model);}
var car = { make:"Lamborghini", model:"Huracán", fullName:function () { console.log (this.make + " " + this.model); }} car.fullName(); // Lmborghini Huracán window.fullName(); // Mclaren 720S fullName(); // Mclaren 720S
Here make, model
and fullName
are defined globally, while car
object has an implementation of fullName
as well. When invoked by the car
object this referred to the properties defined inside the object. On the other hand, the other two function callings are the same and return the globally defined properties.
这里, make, model
和fullName
是全局定义的,而car
对象也具有fullName
的实现。 当由car
对象调用时,这是指对象内部定义的属性。 另一方面,其他两个函数调用相同,并且返回全局定义的属性。
Alone
单独
When used alone not inside any function or object, this
refers to the global object.
当单独使用而不是在任何函数或对象内使用时, this
指的是全局对象。
The this
here refers to the global name property.
这里的this
是指全局名称属性。
In an event
在事件中
Events can be of any type, but for the sake of simplicity and clarity, let’s take a click event.
事件可以是任何类型,但是为了简单明了,让我们点击事件。
Whenever a button is clicked and an event is raised, it can call another function to do a certain task based on the click. If this
is used inside that function, it will refer to the element which raised the event. In the DOM, all the elements are stored as objects. That is why when an event is raised it refers to that element, because that webpage element is actually an object inside the DOM.
每当单击按钮并引发事件时,它都可以调用其他函数来基于单击来执行某些任务。 如果this
是该函数内部使用,它将指的是引发事件的元素。 在DOM中,所有元素都存储为对象。 这就是为什么在引发事件时它引用该元素的原因,因为该网页元素实际上是DOM中的一个对象 。
Example:
例:
call(), apply() & bind()
call(),apply()和bind()
bind: allows us to set the this
value on methods.
bind:允许我们在方法上设置this
值。
call & apply: allow us to borrow functions and set the this
value on function invocation.
致电并申请:允许我们借用功能并设置this
函数调用的值。
Call, Bind and Apply are in themselves a topic of another post. They are very important, and explaining them here is not possible as we should know all about this
to know the usage of these functions.
呼叫,绑定和应用本身就是另一篇文章的主题。 它们非常重要,在这里无法对其进行解释,因为我们应该了解所有this
知识,才能了解这些功能的用法。
If understood well, this
make our work easier in a way. But there are some cases where it is misunderstood.
如果了解得很好, this
将使我们的工作更加轻松。 但是在某些情况下,它会被误解。
var car = {make:"Lamborghini",model:"Huracán",name:null,fullName:function () {this.name=this.make + " " + this.model;console.log (this.name);}}
var anotherCar={make:"Ferrari",model:"Italia",name:null}
anotherCar.name= car.fullName();
We get an unexpected result here. We borrowed a method that uses this
from another object, but the problem here is that the method is only assigned to anotherCar
function but is actually invoked on car
object. That’s why we get the result as Lamborghini and not Ferrari.
我们在这里得到了意外的结果。 我们从另一个对象借用了一个使用this
方法的方法,但是这里的问题是该方法仅分配给anotherCar
函数,但实际上是在car
对象上调用的。 这就是为什么我们得到的结果是兰博基尼而不是法拉利。
To resolve this, we use the call()
method.
为了解决这个问题,我们使用call()
方法。
Here the call()
method calls fullName()
on anotherCar
object which originally does not have the fullName()
function.
在这里, call()
方法对另一个最初不具有fullName()
函数的anotherCar
对象调用fullName()
。
We can also see that, when we log the car.name
and anotherCar.name
we get the result for the latter not on former, which means that the function was indeed invoked on anotherCar
and not on car
.
我们还可以看到,当我们登录car.name
和anotherCar.name
我们得到的结果不是在前者上,这意味着该函数确实是在anotherCar
而不是car
上调用的。
var cars=[{ make: "Mclaren", model: "720s"},{make: "Ferrari",model: "Italia"}]
var car = {cars:[{make:"Lamborghini", model:"Huracán"}],fullName:function () {console.log(this.cars[0].make + " " + this.cars[0].model);}}var vehicle=car.fullName;vehicle()
In the above snippet we have a global object called cars and we have the same name object inside the car object. The fullName()
method is then assigned to the vehicle variable which is then called. The variable belongs to the global object so this
calls the global cars
object instead of the cars
object because of the context.
在上面的代码片段中,我们有一个名为cars的全局对象,并且在car对象内有相同名称的对象。 然后将fullName()
方法分配给随后被调用的车辆变量。 变量属于全局对象,因此this
要求全球cars
对象,而不是cars
,因为上下文对象。
To resolve that we use .bind()
function to solve the issue.
为了解决这个问题,我们使用.bind()
函数来解决此问题。
Binding helps us with specifically setting the this
value and hence the vehicle variable explicitly points to the car object and not the global object, so this lies in the context of the car
object.
绑定可帮助我们专门设置this
值,因此,车辆变量显式指向汽车对象而不是全局对象,因此这位于car
对象的上下文中。
var car = {cars:[{make:"Lamborghini",model:"Huracán"},{ make: "Mclaren", model: "720s"},{make: "Ferrari",model: "Italia"}],fullName:function(){this.cars.forEach(()=>{console.log (this.make + " " + this.model);})}}car.fullName();
In the above snippet, the fullName()
calls upon a function which iterated through the cars array using forEach
. Inside the forEach
there is an anonymous function where this loses context. A function inside a function in JavaScript is called a closure
. Closures
are very important and widely used in JavaScript.
在上面的代码段中, fullName()
调用了一个函数,该函数使用forEach
遍历cars数组。 在forEach
内部有一个匿名函数,该函数会丢失上下文。 JavaScript中的函数内部的函数称为closure
。 Closures
非常重要,并且在JavaScript中广泛使用。
Another important concept playing a role here is scope
. A variable inside a function cannot access variables and properties outside its scope
. this
inside the anon function cannot access this
outside it. So this
has nowhere to go but to point to global object. But there, no property is defined for this
to access so undefined
is printed.
在这里起作用的另一个重要概念是scope
。 函数内部的变量无法访问其scope
之外的变量和属性。 this
在不久的内部功能无法访问this
外面。 因此,除了指向全局对象之外, this
无处可走。 但是在那里,没有this
访问定义任何属性,因此undefined
被打印。
A workaround for the above is that we can assign a variable the value of this
, outside the anonymous function and then use it inside it.
上面的解决方法是,我们可以在匿名函数外部为变量赋this
的值,然后在其内部使用它。
Here, the self variable contains the value of this
which is used with the inner function thus giving us the output.
在此,自变量包含此值, this
值与内部函数一起使用,从而为我们提供输出。
var car= {make: "Lamborghini",model: "Huracán",fullName: function (cars) {cars.forEach(function(vehicle){console.log(vehicle +" "+ this.model);})}}car.fullName(['lambo','ferrari','porsche']);
This is a revisited example, in which this
wasn't accessible so we preserved it's value by using a variable called self. Let's use arrow function to solve the same:
这是一个重新例子,在this
,所以我们用所谓的自变量保留了它的价值是无法访问。 让我们使用箭头函数来解决相同的问题:
As you can see, using an arrow function in forEach()
automatically solves the problem and we don’t have to do bind, or give the this
value to some other variable. This is because arrow functions bind their context so this
actually refers to the originating context, or the originating object.
如您所见,在forEach()
使用箭头函数可以自动解决问题,我们不必绑定,也不必将this
值赋予其他变量。 这是因为箭头功能结合它们的上下文,以便this
实际上指的是始发上下文,或始发对象。
var car= {make: "Lamborghini",model: "Huracán",fullName: function () {console.log(this.make +" "+ this.model);}}var truck= {make: "Tesla",model: "Truck",fullName: function (callback) {console.log(this.make +" "+ this.model);callback();}}truck.fullName(car.fullName);
The above code consists of two identical objects, with one containing a callback function. A callback function is a function passed into another function as an argument, which is then invoked inside the outer function to complete some kind of routine.
上面的代码由两个相同的对象组成,其中一个包含一个回调函数。 回调函数是作为参数传递给另一个函数的函数,然后在外部函数内部调用该回调函数以完成某种例程。
Here, the truck object’s fullName
method consists of a callback which is also invoked inside it. Our car object is as before. When we invoke the truck’s fullName
method with the callback(argument) as the fullName
method of the car object, we get output as Tesla Truck
and undefined undefined.
在这里,卡车对象的fullName
方法包含一个回调 ,该回调也在其内部被调用。 我们的汽车对象和以前一样。 当我们调用卡车的fullName
法回调(参数)的fullName
汽车对象的方法,我们得到的输出Tesla Truck
和undefined undefined.
After reading about this
some of you might have gotten a hunch that car.fullName
would print the model and make of the truck object, but to your disappointment, this
again played a trick on us. Here the car.fullName
is passed as an argument and is not actually invoked by the truck object. The callback invokes the car object method, but note that the actual call site for the function is the callback which binds this to the global object. It's a bit confusing, so read it again!
在阅读了this
内容后,您可能已经预感到car.fullName
会打印出卡车对象的模型和制造商,但是令您失望的是, this
再次对我们起到了欺骗作用。 这里car.fullName
作为参数传递,而卡车对象实际上并未调用。 回调调用car对象方法,但请注意,该函数的实际调用站点是将其绑定到全局对象的回调。 这有点令人困惑,所以请再次阅读!
Here to get clarity, we print this
itself. We can see that the this
of callback is given a global scope. So to get a result we create global make
and model
properties.
为了清楚起见,我们this
其本身打印出来。 我们可以看到回调的this
被赋予了全局范围。 因此,为了获得结果,我们创建了全局make
和model
属性。
Again, running the same code with global make
and model
properties we finally get the answer to the global this
. This proves that this
references the global object.
同样,使用全局make
和model
属性运行相同的代码,我们终于得到了全局this
的答案。 这证明this
引用了全局对象。
To get the results which we desire, the car.fullName
result we will again use bind()
to hard-bind the car object to the callback, which will make everything right again.
为了得到我们想要的结果car.fullName
结果,我们将再次使用bind()
硬绑定车对象的回调,这将便又让一切。
No doubt that this
is very useful, but has it's own pitfalls too. Hope I made it quite easy for you to understand. If you want more content simplified like this, follow me on Medium. Please leave your responses and share this if you liked it.
毫无疑问, this
非常有用,但也有其自身的陷阱。 希望我使您很容易理解。 如果您想像这样简化更多内容,请在Medium上关注我。 如果您喜欢,请留下您的答复并分享。
翻译自:
javascript指南
转载地址:http://mfewd.baihongyu.com/