Execution context
We know that execution contexts are divided into two types: global context and function context (my article explains the execution context in this articleStill confused about execution context and scope?). There is only one global context, and the function execution context is created when the function is called.
Each execution context has three properties:
- Variable Object
- Scope chain
- this
What is this
This is bound at runtime, not at writing, and its context depends on various conditions when the function is called.The binding of this has nothing to do with the location of the function declaration, it only depends on the method of the function being called.
Call location
To understand this binding process, you must first understand the call location. The call location is the location of the function's call (not the declared location). So we need to analyze the call stack (that is, the execution context stack). Let's look at a piece of code first.
function baz() { ("baz") bar() } function bar() { ("bar") foo() } function foo() { ("foo") } baz()
When the code is executed to foo() and enters the function body of foo, the current call stack is:
ECStack = [ fooContext, // foo barContext, // bar bazContext, // baz globalContext, // Global]
Through the call stack, we can clearly find the call location of the function. baz is called globally, bar is called in baz, foo is called in bar.
So how does the function determine this binding object when it is executed?
Binding rules
Determine this binding object through binding rules.
Default binding
The most commonly used call type: independent function calls.
function foo(){ () // 2 } var a = 2; foo()
When calling the function, this default binding is used, so this points to the global object.
So how do we know that the default binding is applied here? You can see how foo() is called by analyzing the call location. In the code, foo() is called directly using a function reference without any modification, so it can only use the default binding and no other rules can be applied.
so,Call a function in the global environment, and this inside the function points to the global variable window.
Implicit binding
function foo() { ( ); } var obj = { a: 2, foo: foo }; (); // 2
In this code, we see that the declaration position of foo is global, but it is added to obj as a reference property. The call location uses the obj context reference function. When foo is called, it is contained in the obj object and the foothold points to the obj object. When a function references a context object, the implicit binding rule binds this in the function call to this context object.
This in the execution context of the method points to the object itself by calling an object inside it through an object.
Let's look at a special example
function foo() { () } var obj = { a: 2, foo } var bar = var a = "mick" bar() // mick
bar is a reference, but in fact, it refers to the foo function itself, so at this time bar() is actually a function call without any modification, so the default binding is applied.
Let's look at another situation
function foo() { () } function doFoo(fn) { fn() } var obj = { a: 2, foo } var a = "mick" doFoo() // mick
This in nested functions will not be inherited from outer functions.This always points to the object that last called it
Show bindings
You can use call, apply or bind methods. If you are interested in the implementation principles of these three methods, you can take a lookThis handwritten call, apply, bind
function foo() { () } var obj = { a: 2 } (obj) // 2
Through the call method, you can force this to bind to obj when calling foo.
new binding
Here we will first talk about what happens when calling a function in new
- Create a brand new object
- This new object will be executed [[prototype]] link
- This new object will be bound to this function call
- If the function does not return another object, the function call in the new expression will automatically return the new object.
function foo(a){ = a } var bar = new foo(2) ()
When we use new to call foo, we will construct a new object and bind it to this in the foo call.
special case
function foo() { () } var a = 2 var o = { a: 3, foo: foo } var p = { a: 4 } () // 3 ;( = )() // 2
Assignment expression =
The return value of the object function is a reference, so the call location is foo() instead of() or(). So here is the default binding.
Interview questions
Let's look at the interview questions below
var name = 'window' var person1 = { name: 'person1', foo1: function () { () }, foo2: () => (), foo3: function () { return function () { () } }, foo4: function () { return () => { () } } } var person2 = { name: 'person2' } person1.foo1() person1.(person2) person1.foo2() person1.(person2) person1.foo3()() person1.(person2)() person1.foo3().call(person2) person1.foo4()() person1.(person2)() person1.foo4().call(person2)
Let's analyze it one by one.
-
person.foo1()
This is an implicit binding. This of foo1 is bound to person, so print person1 -
person1.(person2)
Show binding, foo1's this changes this through call, pointing to person, so print person2 -
person.foo2()
Because foo2 is an arrow function, its this pointer is the pointer of this on the previous layer, that is, window, window -
person1.(person2)
The same principle as above is also window -
person1.foo3()()
A function is returned internally, which is actually a reference to a function. At this time, this should point to window, so print window -
person1.(person2)()
Through call, this pointing of foo3 is changed, and it has nothing to do with the returned function, so this still points to window and prints window -
person1.foo3().call(person2)
This pointer of the internal return function of foo3 is changed through call, so person2 is printed -
person1.foo4()()
The return is an arrow function. This of the arrow function is the pointing of this inside the previous layer function, so that is the pointing of foo4this. Since foo4 is included and called by person1, this points to person1 and prints person1. -
person1.(person2)()
At this time, this inside foo4 is changed to person2 through call, so the person is printed -
person1.foo4().call(person2)
This andperson1.foo4()
The same is true, print person1
I briefly talked about this binding. Welcome to leave a message on your questions. Everyone learns and improves together! ! !
This is the article about how many types of bindings do you know about this in JavaScript? This is all about this article. For more related JavaScript this binding content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!