javascript步骤
Every frontend developer at some point of his career has stumbled into this
in JavaScript and my bet is the first experience wasn’t very clear.
每个前端开发人员在其职业生涯的某个阶段都已经在JavaScript中碰到了this
,我敢打赌,第一次体验并不是很清楚。
It turns out that in fact this
in JavaScript can be understood and that we can even follow a simple 4 step procedure to determine it’s value. Let’s solve this riddle.
事实证明,其实this
在JavaScript中可以理解的,我们甚至可以遵循一个简单的4步程序,以确定它的价值。 让我们解决这个难题。
介绍 (Introduction)
If you are looking into this
it probably means one of the three things:
如果您正在研究this
则可能意味着以下三件事之一:
you stumbled upon some bug, lost hours and have thought to yourself that it’s finally time to understand
this
. Or maybe you have to support some legacy project您偶然发现了一些错误,浪费了很多时间,并自以为是
this
了解this
。 也许您必须支持一些旧项目you are preparing for a job interview or some sort of an exam (yes,
this
will be asked :) )您正在准备面试或某种形式的考试(是的,
this
将被要求:))- you are just curious about JavaScript 您只是对JavaScript感到好奇
As a disclaimer, I know a lot of developers who (without fully understanding this
) still manage to write production quality code.
作为免责声明,我知道许多开发人员(在没有完全理解this
)仍然设法编写生产质量代码。
For instance, if you work in React for not a long time, chances are that you operate on functional components and hooks only and haven’t seen this
for a long time.
例如,如果您在React中工作了很长时间,那么您很可能只在功能组件和钩子上操作,而且很长一段时间都没有看到this
。
I personally believe that it’s worth to have an understanding of the basics as this
is really not that difficult and at some point of your career it will definitely pay off.
我个人认为,对基础知识有所了解是值得的,因为this
并不是那么困难,并且在您的职业生涯的某个阶段肯定会有所收获。
TL; DR (TL;DR)
To determine value of this
we just have to follow simple 4 step procedure. It comes down to inspecting where and how it’s called.
要确定this
值,我们只需遵循简单的4步过程。 它取决于检查它的调用位置和调用方式。
The first condition that we meet determines this
value.
我们满足的第一个条件决定了this
值。
Did we use
new
keyword i.e.new MyFunction()
?我们是否使用过
new
关键字,即new MyFunction()
?Did we use
call, bind, apply
i.e.myObject.myFunction.call(myObject2)
?我们是否使用过
call, bind, apply
myObject.myFunction.call(myObject2)
?Did we use the dot notation i.e.
myObject.myFunction()
?我们是否使用了点表示法即
myObject.myFunction()
?Did we use free function invocation i.e.
window.myFunction()
or justmyFunction()
?我们是否使用自由函数调用,即
window.myFunction()
或仅myFunction()
?
Above does not apply for arrow functions. For arrow functions we have to inspect this
value of the surrounding context.
以上不适用于箭头功能。 对于箭头函数,我们必须检查周围上下文的this
值。
Have a read below for more detailed explanation.
请在下面阅读以获取更详细的说明。
遵守规则 (Rules to follow)
There are four rules that we need to inspect in order to determine this
.Disclaimer — none of these values apply to arrow functions — more on that later on.
为了确定this
规则,我们需要检查四个规则。免责声明-这些值均不适用于箭头功能-稍后会详细介绍。
1. The new
keyword.
1. new
关键字。
JavaScript has the keyword new
. If we use it when we call the function, this
inside the function is new object.
JavaScript具有关键字new
。 如果在调用函数时使用它,则函数内部的this
对象为新对象。
function Example() {
console.log(this); // {}
this.value = 'puma';
console.log(this); // { value: 'puma' }
}new Example()
As an important side note — if we are to call the Example()
without the new
keyword, in the browser enviroment we would create ourselves a Window.value
variable, which can easily lead to bugs (look into point 4 for more details).
作为重要的Window.value
说明—如果不使用new
关键字调用Example()
,则在浏览器环境中,我们将为自己创建一个Window.value
变量,该变量很容易导致错误(更多信息请参见第4点)。
Example();// function invoked without the new keyword refers this to Window
// Window { parent: Window, opener: null, top: Window ... }
If we are in strict (‘use-strict’) mode (on production level we must be), things change a bit:
如果我们处于严格(“ 使用严格”)模式(必须处于生产级别),那么情况会有所变化:
Example(); // undefinedwindow.Example()
// Window { parent: Window, opener: null, top: Window ... }
2. The trio call, bind, apply
. If either of them is used, this
inside the function is the object in the argument.
2.三重call, bind, apply
。 如果使用它们中的, this
功能是内部参数中的对象。
function exampleFunction() { console.log(this);}const obj = { value: 'puma'};const boundedFunction = exampleFunction.bind(obj);boundedFunction(); // { value: 'puma' }exampleFunction.call(obj); // { value: 'puma' }exampleFunction.apply(obj); // { value: 'puma' }exampleFunction(obj) // Window
// undefined in strict mode
3. Calling function as object or class method.
3.调用函数作为对象或类方法。
This is actually quite intuitive.
这实际上是非常直观的。
Whenever we have an object that has a method and we use a dot notation to invoke the function, this
is the object to the left of the dot i.e.
每当我们有一个具有方法的对象并且我们使用点符号来调用该函数时, this
就是点左侧的对象,即
const myObject = {
value: 'puma',
myFunction: function() {
console.log(this);
}
};myObject.myFunction(); // this is the object to left of the dot// -> { value: 'puma', myFunction: ƒ }
4. Free function invocation
4. 自由函数调用
This is very similar to point 3. If we create a function not as a method, it automatically becomes a property of global object, window
.
这与第3点非常相似。如果我们创建的函数不是方法 ,则它会自动成为全局对象window
的属性。
function myFunction() {
console.log(this);
}myFunction();window.myFunction();// if not in strict mode
// this is doing exactly the same thing
// output if called in browser// Window {stop: ƒ, open: ƒ, alert: ƒ, ...}
In this scenario, this
is a global object — window
. Remember how in point 3 we said myObject.myFunction
? We have said that this
is an object that is on the left hand side of the dot i.e. myObject
. Same rule applies when we say window.myFunction
. Should we say myFunction
what we implicitly say is window.myFunction
.
在这种情况下, this
是一个全局对象window
。 还记得我们在第3点中所说的myObject.myFunction
吗? 我们已经说过, this
是一个位于点左侧的对象,即myObject
。 当我们说window.myFunction
时,同样的规则适用。 我们应该说myFunction
,我们隐式说的是window.myFunction
。
console.log(myFunction === window.myFunction); // true
This looks slightly different in the strict
mode:
在strict
模式下,这看起来略有不同:
'use strict';function myFunction() {
console.log(this);
}myFunction(); // undefined
window.myFunction(); // Window { ... }
5. If multiple rules apply, the one on the top takes precedence. For instance, rule 2 (call
) takes precedence over rule 3 (the dot notation).
5.如果有多个规则,则顶部的规则优先。 例如,规则2( call
)优先于规则3( 点表示法)。
new keyword
call, bind, apply
myObject.myFunction
window.myFunction
箭头功能 (Arrow functions)
Arrow functions are a special case. One of the key reasons they were created, was to simplify this
.
箭头功能是一种特殊情况。 创建它们的关键原因之一就是简化了this
。
Rules introduced earlier are ignored, and this
value receives the value
of the surrounding scope.
前面介绍的规则将被忽略,并且this
值接收周围范围的value
。
In simple terms, we can go level above the arrow function and inspect this
value in that level. The arrow function has the same this
value i.e.
简而言之,我们可以在箭头功能之上进行检查,并在该级别中检查this
值。 箭头功能具有相同的this
值,即
const myObject = { value: "puma", createArrowFunction: function () { return () => console.log(this); },};const arrowFunction = myObject.createArrowFunction();arrowFunction();// { value: "puma", createArrowFunction: ƒ }
We often meet with arrow functions in React be it class or functional components.
我们经常在React中遇到箭头函数,无论是类还是功能组件。
As a side note, you cannot use new
with arrow functions — they cannot be used as a constructor.
附带说明,您不能使用带箭头的new
函数-它们不能用作构造函数。
const myArrowFunction = () => console.log(this)new myArrowFunction();// Uncaught TypeError: myArrowFunction is not a constructor
练习题 (Exercises)
Let’s put the theory into practice and try to determine this
value.
让我们将理论付诸实践,并尝试确定this
值。
第一次练习 (First exercise)
const myObject = { value: "puma", myFunction: function () { console.log(this); },};const printThis = myObject.myFunction;myObject.myFunction(); // { value: "puma", printThis: ƒ }printThis(); // in non strict mode: Window {stop: ƒ, open: ƒ, alert: ƒ, ...}
ok, so what is going on here?
好的,这是怎么回事?
myObject.myFunction()
myObject.myFunction()
To understand the result let’s go through the rules we have learned at the beginning of the article:
为了了解结果,让我们仔细阅读本文开头所学的规则:
First rule — have we used new
keyword? No, moving on.Second rule — have we used call, bind, apply
? No, moving on.Third rule — have we used dot notation? Yes, we have. This is why this
has the value of object from left hand side of the dot.
第一条规则-我们是否使用了new
关键字? 不,继续前进。第二条规则-我们使用过call, bind, apply
吗? 不,继续。第三条规则-我们是否使用点符号? 是的我们有。 这就是为什么this
从点的左侧开始具有object的值。
printThis()
printThis()
This is in fact a common interview question. Let’s inspect the rules one more time:
这实际上是一个常见的面试问题。 让我们再检查一次规则:
First rule — new
keyword? No, moving on.Second rule — call, bind, apply
? No, moving on.Third rule — dot notation? No, moving on.Fourth rule — free function invocation — yes. This is the rule that we have met. In strict mode, we would get undefined
value, in not strict mode we will get globalWindow
object.
第一法则- new
关键字? 不,继续前进。第二条规则- call, bind, apply
? 不,继续前进。第三条规则- 点符号? 不,继续。第四条规则- 自由函数调用 -是的。 这是我们遇到的规则。 在严格模式下,我们将获得undefined
值,在非严格模式下,我们将获得全局的Window
对象。
第二次练习 (Second exercise)
To start with, I haven’t seen code like that for a long time. Sometimes we do however have to support legacy projects. Or pass a job interview and questions related to this
are still very common one.
首先,我已经很长时间没有看到类似的代码了。 但是有时我们确实必须支持旧项目。 或通过求职面试,与this
相关的问题仍然很常见。
const myObject = { value: "puma", myFunction: function () { console.log(this); },};const myObject2 = { value: "Will I overwrite myObject.value?" };myObject.myFunction.call(myObject2);// { value: "Will I overwrite myObject.value?" }
In order to understand what is going on here, let’s go through the rules once again:
为了了解这里发生的情况,让我们再次仔细阅读规则:
Have we used
new
? No, moving on.我们使用过
new
吗? 不,继续前进。Have we used
call, bind, apply
? Yes, we have. This rule tells us thatthis
value will take themyObject2
. This is our answer but for the sake of understanding we will go one level down.我们是否使用过
call, bind, apply
? 是的我们有。 该规则告诉我们,this
值将采用myObject2
。 这是我们的答案,但是为了理解,我们将下一层。Have we used dot notation? Yes, we have. But Rule 2 is more important hence take precedence.
我们使用点符号了吗? 是的我们有。 但是规则2更重要,因此优先。
关于库的警告 (A word of caution about libraries)
This article applies to Vanilla JavaScript concepts. Some libraries change behaviour of this
. For instance, jQuery binds this
to the DOM element triggering an event in the callback to that event i.e.
本文适用于Vanilla JavaScript概念。 一些库会更改this
行为。 例如,jQuery this
绑定到DOM元素,从而在该事件的回调中触发一个事件,即
<button class = "click-me"> jQuery bind this to me </button>$('.click-me').on('click', function() {});
If a library changes this
behaviour, always verify it’s documentation. Most likely it’s using bind
to bound.
如果图书馆this
了更改 行为,请始终验证其文档。 最有可能的是使用bind
绑定。
摘要 (Summary)
As we can see, determining this
value is not that difficult if we follow a simple procedure.
如我们所见,如果遵循简单的过程,确定this
值并不困难。
The first condition that we meet determines this
value.
我们满足的第一个条件决定了this
值。
Did we use
new
keyword i.e.new MyFunction()
?我们是否使用过
new
关键字,即new MyFunction()
?Did we use
call, bind, apply
i.e.myObject.myFunction.call(myObject2)
?我们是否使用过
call, bind, apply
myObject.myFunction.call(myObject2)
?Did we use the dot notation i.e.
myObject.myFunction()
?我们是否使用了点表示法即
myObject.myFunction()
?Did we use free function invocation i.e.
window.myFunction()
or justmyFunction()
?我们是否使用自由函数调用,即
window.myFunction()
或仅myFunction()
?
Above does not apply for arrow functions. In that case, we have to inspect this
value of the surrounding context.
以上不适用于箭头功能。 在这种情况下,我们必须检查周围环境的this
值。
Happy debugging and enjoy the interview!
调试愉快,享受采访!
javascript步骤