javascript理解
介绍(Introduction)
I guess this is the most confusing concept in javascript, how to findthis
(context) of a function. And the misconception is to look where the function is declared or defined. this
is a binding made for each function invocation.
我猜这是javascript中最令人困惑的概念,如何找到函数的this
(上下文)。 误解是看该函数的声明或定义位置。 this
是对每个函数调用的绑定。
To understand
this
binding, we have to understand the call-site: the location in code where a function is called (not where it's declared). We must inspect the call-site to answer the question: what'sthis
a reference to?要了解
this
绑定,我们必须了解call-site :代码在代码中调用函数的位置(而不是在声明函数的位置)。 我们必须检查呼叫站点以回答问题:this
是指什么?
如何使用呼叫站点找出“此”? (How to figure out “this” using call-site?)
Now we understood that, this
(context) is dependent on the call-site and to find out the context
javascript has some rules to decide.
现在我们了解到, this
(上下文)取决于调用站点,并且要找出context
javascript有一些规则可以决定。
规则1-默认绑定 (Rule 1 — Default Binding)
// function declaration
function foo() {
console.log(this.a);
}var a = 1;// call-site
foo(); // 1
The first rule which is most commonly used: standalone function invocation. We see that when foo()
is called this.a
is referring to global variable a
Why? Because foo()
is called with a plain, un-decorated function reference so this
will refer to the global object.And in case of strict mode, this
will be undefined and the above scenario will throw a Reference Error.
最常用的第一条规则:独立函数调用。 我们看到当foo()
称为this.a
引用全局变量a
为什么? 因为foo()
被调用,一个普通的,未修饰的函数参照所以this
将是指全球object.And在严格模式的情况下, this
将是未定义的,并且上述情况将引发参考错误。
规则2 –隐式绑定 (Rule 2 — Implicit Binding)
function foo() {
console.log(this.a)
}var a = 5;var bar = {
a: 1,
foo: foo
}//call-site
bar.foo(); // 1
Second rule, here we are using a reference to call the function. In the above example if you see, the call-site uses the bar
context to reference the function, so you could say that the bar
object "owns" or "contains" the function reference at the time the function is called. So this
will refer to object bar
and output will be 1
.
第二条规则,这里我们使用引用来调用函数。 在上面的示例中,如果您看到的话,调用站点将使用bar
上下文来引用该函数,因此可以说在调用函数时bar
对象“拥有”或“包含”该函数引用。 因此, this
将引用对象bar
并且输出将为1
。
规则3 –隐性失落 (Rule 3 — Implicit Lost)
function foo() {
console.log(this.a)
}var a = "global";var bar = {
a: "local",
foo: foo
}var wiz = bar.foo;//call-site
wiz(); // global
In this rule there is slight confusion that even though wiz
is a reference to bar.foo
infact, it is just another reference to foo
itself. So as we discussed from the start this
depends on the call-site only and in above case which is a plain, un-decorated call and thus the default binding applies.this.a
is resulting in global
.
在此规则中,有一点混乱,即使wiz
实际上是对bar.foo
的引用,也只是对foo
本身的另一个引用。 因此,正如我们从一开始就讨论的那样, this
取决于呼叫站点,在上述情况下,这是一个普通的,未经修饰的呼叫,因此默认绑定适用。 this.a
是导致global
。
规则4-显式绑定 (Rule 4 — Explicit Binding)
As you all are aware we can explicitly provide context to a function call using call, apply and bind.
众所周知,我们可以使用call , apply和bind为函数调用显式提供上下文。
// function declaration
function foo() {
console.log(this.a);
}var obj = {
a: "Obj reference"
};foo.call(obj); // Obj reference
In this rule, as we see the above case we are explicitly providing context for function foo
using call method of functions. So this
will refer to object obj
as provided by call method and same applies for apply method also. But let’s take one example for bind to clear out confusions if any.
在此规则中,如我们看到的上述情况,我们使用函数的调用方法为foo
显式提供上下文。 因此, this
将引用调用方法提供的对象obj
,同样适用于apply方法。 但是,让我们以绑定为例,以消除混乱(如果有)。
function foo() {
console.log(this.a);
}var obj = {
a: "Obj reference"
};var bar = foo.bind(obj);
bar(); // Obj reference
In this scenario, you will be tempted to consider it as default rule but it is different because we hard binded the context of function bar
using bind and after that it will not depend on its call-site actually. That is the reason it is considered as a different rule.If you know above 4 rules you can easily figure out the context of a function invocation at anytime, anyplace in your code.
在这种情况下,您很容易将其视为默认规则,但这是不同的,因为我们使用bind硬绑定了功能bar
的上下文,此后它实际上并不依赖于其调用位置。 这就是将其视为不同规则的原因。 如果您了解上述4条规则,则可以随时随地轻松地在代码中找出函数调用的上下文。
箭头功能/粗箭头 (Arrow Functions/ Fat Arrow)
Now one more thing we all should know that breaks all the above rules and introduced in ES6, that are Arrow Functions a.k.a Fat Arrow.
现在,我们都应该知道另一件事,那就是打破了上述所有规则并在ES6中引入,即Arrow Functions aka Fat Arrow。
Arrow functions use context
of its lexical scope. In simpler way, arrow-functions adopt the this
binding from the enclosing (function or global) scope. Let’s the below example to clear out more -
箭头函数使用其词法范围的context
。 以更简单的方式,箭头函数从封闭的(函数或全局)范围采用this
绑定。 让我们在下面的示例中清除更多内容-
function foo() {
// return an arrow function
return (a) => {
// `this` here is lexically adopted from `foo()`
console.log( this.a );
};
}
var obj1 = {
a: 2
};
var obj2 = {
a: 3
};
var bar = foo.call( obj1 );
bar.call( obj2 ); // 2, not 3!
So when we wrote var bar = foo.call( obj1 );
, if you see the declaration of function foo()
it doesn’t involve any arrow function so according to the standard 4 rules we calledfoo
with reference to object obj1
and its return function is assigned to bar
. Now the next line bar.call( obj2 );
even though we are calling the return function with reference to object obj2
but it is declared as an arrow function so it will use the context of function foo
which we set to object obj1
i.e Output will be 2 not 3
.
因此,当我们编写var bar = foo.call( obj1 );
,如果您看到函数foo()
的声明,则其中不包含任何箭头函数,因此根据标准4规则,我们将foo
引用为对象obj1
并将其返回函数分配给bar
。 现在下一行bar.call( obj2 );
即使我们引用对象obj2
来调用return函数,但是它被声明为箭头函数,所以它将使用我们设置为对象obj1
的函数foo
的上下文,即Output将为2 not 3
。
概要 (Summary)
To find out context or
this
of a function invocation is dependent on its call-site (location where function is called).要了解上下文或
this
函数调用的是依赖于它的调用点(位置在那里函数被调用)。- To figure out context from call-site, we have some standard rules which we discussed. 为了弄清呼叫站点的上下文,我们讨论了一些标准规则。
Arrow Functions doesn’t follow any standard rule,they adopt the
this
binding from the enclosing (function or global) scope.Arrow Functions不遵循任何标准规则,它们从封闭的(函数或全局)范围采用
this
绑定。
翻译自: https://medium.com/swlh/understanding-this-in-javascript-166164e7fa2b
javascript理解