The author is watching the JavaScript you don't know recently, and the explanation about this
is very exciting. JavaScript
in this
this
is a core concept, and some students will be a little vague and afraid of it. A lot, makes us think this
is no pattern to be found, like a ghost
If you haven't figured it out yet this
, or are vague about it, this article is specially prepared for you. If you are relatively familiar with it, then you can also use it as a review to consolidate your knowledge points
This article is a reading note, and of course it also adds a lot of my personal understanding. I think it will definitely be helpful to everyone.
execution context
Before understanding this
, let's take a look at what is an execution context
In short, an execution context is an abstraction of the environment in which JavaScript
code is evaluated and executed. Whenever Javascript code is running, it is running in the execution context
There are three execution context types in JavaScript
- Global execution context - This is the default or base context, any code that is not inside a function is in the global context. It does two things: creates a global
window
object (in the browser case), and setsthis
to a value equal to this global object. There is only one global execution context in a program - Function Execution Context — Whenever a function is called, a new context is created for that function. Each function has its own execution context, but is created when the function is called. There can be any number of function contexts
-
eval
Function Execution Context — Executed ineval
The code inside the function will also have its own execution context, but because JavaScript developers do not often useeval
, so I won't discuss it here
Here we first draw a conclusion that this in both non-strict mode and strict mode points to the top-level object (window in the browser)
console.log(this === window); // true
'use strict'
console.log(this === window); // true
this.name = 'vnues';
console.log(this.name); // vnues
Later, our discussion is more on the function execution context
what exactly is this? why use this
this
is bound at runtime, not at writing time, its context depends on various conditions when the function is called
Remember: The binding of this
has nothing to do with where the function is declared, it only depends on how the function is called
When a function is called, an active record (sometimes called an execution context) is created. This record will contain information about where the function was called (call stack), how the function was called, parameters passed in, etc. this
is one of the attributes of the record, which will be used during function execution
Look at an example to understand why to use this
, sometimes, we need to implement code like the following:
function identify(context) {
return context.name.toUpperCase();
}
function speak(context) {
var greeting = "Hello, I'm " + identify(context);
console.log(greeting);
}
var me = {
name: "Kyle"
};
speak(me); //hello, 我是 KYLE
The problem with this code is that it needs to display and pass the context object. If the code becomes more and more complex, this method will make your code look very confusing. Using this
is more elegant
var me = {
name: "Kyle"
};
function identify() {
return this.name.toUpperCase();
}
function speak() {
var greeting = "Hello, I'm " + identify.call(this);
console.log(greeting);
}
speak.call(me); // Hello, 我是 KYLE
Four binding rules for this
Let's look at the binding rules in the context of functions, there are the following four
- default binding
- implicit binding
- explicit binding
-
new
binding
default binding
The most commonly used function call type: independent function call, this is also the one with the lowest priority, this matter this
points to the global object. Note: If you use strict mode ( strict mode
), the global object will not be able to use the default binding, so this
will be bound to undefined
as shown below
var a = 2; // 变量声明到全局对象中
function foo() {
console.log(this.a); // 输出 a
}
function bar() {
'use strict';
console.log(this); // undefined
}
foo();
bar();
implicit binding
We can also say at the beginning: The binding of this
has nothing to do with the position of the function declaration, it only depends on how the function is called
Let's look at an example first:
function foo() {
console.log(this.a);
}
var obj = {
a: 2,
foo: foo
};
obj.foo(); // 2
When calling obj.foo()
, this
points to the obj object. When a function reference has a context object, the implicit binding rules bind the function call this
to this context object. Because when calling foo()
this
is bound to obj, this.a and obj.a are the same
Remember: only the top or last level in the chain of object property references affects where the call is made
function foo() {
console.log(this.a);
}
var obj2 = {
a: 42,
foo: foo
};
var obj1 = {
a: 2,
obj2: obj2
};
obj1.obj2.foo(); // 42
indirect reference
Another caveat is that it is possible (intentionally or not) to create an "indirect reference" to a function, in which case calling the function will apply the default binding rules
function foo() {
console.log(this.a);
}
var a = 2;
var o = { a: 3, foo: foo };
var p = { a: 4 };
o.foo(); // 3
(p.foo = o.foo)(); // 2
Another caveat is that it is possible (intentionally or not) to create an "indirect reference" to a function, in which case calling the function will apply the default binding rules
The return value of the assignment expression p.foo = o.foo
is a reference to the target function, so the call location is foo()
instead of p.foo()
or o.foo()
According to what we said before, the default bindings are applied here
show binding
When analyzing implicit binding, we must include a property inside an object that points to a function, and indirectly reference the function through this property, thus indirectly (implicitly) binding this
to this object. So what if we don't want to have a function reference inside an object, but want to force a function to be called on an object?
Javascript
provides apply
, call
and bind
methods that allow us to implement
The difference is that call()
and apply()
are immediate functions and accept arguments in different forms:
-
call(this, arg1, arg2, ...)
-
apply(this, [arg1, arg2, ...])
And bind()
creates a new wrapper function and returns instead of executing it immediately
-
bind(this, arg1, arg2, ...)
See the following example:
function foo(b) {
console.log(this.a + '' + b);
}
var obj = {
a: 2,
foo: foo
};
var a = 1;
foo('Gopal'); // 1Gopal
obj.foo('Gopal'); // 2Gopal
foo.call(obj, 'Gopal'); // 2Gopal
foo.apply(obj, ['Gopal']); // 2Gopal
let bar = foo.bind(obj, 'Gopal');
bar(); // 2Gopal
this ignored
如果你把null
undefined
this
call
、 apply
bind
, these values will be ignored when calling, and the default binding rules are actually applied
function foo() {
console.log(this.a);
}
var a = 2;
foo.call(null); // 2
Use this usage to "expand" an array using apply(..)
and pass it as a parameter to a function.
Similarly, bind(..)
can curry parameters (preset some parameters)
function foo(a, b) {
console.log("a:" + a + ", b:" + b);
}
// 把数组“展开”成参数
foo.apply(null, [2, 3]); // a:2, b:3
// 使用 bind(..) 进行柯里化
var bar = foo.bind(null, 2);
bar(3); // a:2, b:3
newbinding
When we use the constructor new
an instance, what does this instance this
point to?
Let's first look at using new
to call a function, or what operation will be performed when a constructor call occurs, as follows:
- Create (or construct) a brand new object
- This new object will be connected by [[prototype]], binding the object (instance)
__proto__
and the constructorprototype
- This new object will be bound to the function call
this
- If the function does not return another object, then the function call in the new expression will automatically return the new object
The principle implementation is similar to the following:
function create (ctr) {
// 创建一个空对象
let obj = new Object()
// 链接到构造函数的原型对象中
let Con = [].shift.call(arguments)
obj.__proto__ = Con.prototype
// 绑定this
let result = Con.apply(obj, arguments);
// 如果返回是一个对象,则直接返回这个对象,否则返回实例
return typeof result === 'object'? result : obj;
}
Note: let result = Con.apply(obj, arguments);
actually means that the new object will be bound to the function call this
function Foo(a) {
this.a = a;
}
var bar = new Foo(2);
console.log(bar.a); // 2
Special Case - Arrow Functions
The four rules we introduced earlier already cover all normal functions. But ES6 introduced a special function type that cannot use these rules: arrow functions
Arrow functions do not use the four standard rules of this
, but are determined according to the outer (function or global) scope at the time of definition this
. That is to say, the arrow function will not create its own this
, it will only inherit from the upper level of its own scope chain this
function foo() {
// 返回一个箭头函数
// this 继承自 foo()
return (a) => {
console.log(this.a);
}
};
var obj1 = {
a: 2
};
var obj2 = {
a: 3
};
var bar = foo.call(obj1);
bar.call(obj2); // 2, 不是 3 !
foo()
The internally created arrow function will capture the foo()
when calling this
. foo()
的this
到obj1
, bar
(引用箭头函数)的this
Set to obj1
, the binding of arrow functions cannot be modified. ( new
also doesn't work!)
Summary - this priority
Determine whether it is an arrow function, if it is, follow the rules of arrow function
Otherwise, if you want to determine the this
binding of a running function, you need to find the direct calling location of the function. After finding it, you can apply the following four rules in order to determine the binding object of this
- Called by
new
? bind to the newly created object - Called by
call
orapply
(orbind
)? Binds to the specified object - Called by a context object? Bind to that context object
- Default: bind to
undefined
in strict mode, otherwise bind to the global object
As shown below:
refer to
- [[Translation] Understanding Execution Context and Execution Stack in JavaScript]( https://juejin.im/post/6844903682283143181#heading-1 )
- JavaScript Rollup You Don't Know
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。