Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to understand the This binding of Js

2025-03-28 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article focuses on "how to understand the This binding of Js", interested friends may wish to take a look. The method introduced in this paper is simple, fast and practical. Let's let the editor take you to learn how to understand the This binding of Js.

The this binding problem of js makes most novices confused, and some veterans feel sick, this is because this binding is "elusive" and often doesn't know why when it goes wrong, which is quite illogical.

Let's consider the following code:

Var people = {name: "Ocean Biscuit", getName: function () {console.log (this.name);}}; _ window.onload = function () {xxx.onclick = people.getName;}

You may have written or encountered the this binding problem that is quite common when moving bricks. When xxx.onclick is triggered, what will it output?

To facilitate testing, I simplified the code:

Var people = {Name: "Ocean Biscuit", getName: function () {console.log (this.Name);}}; var bar = people.getName; bar (); / / undefined

Through this small example to show you the nausea of this, I was confused when I first encountered this problem, because the this in the code pointed very clearly when it was created, pointing to its own people object, but actually pointing to the window object. This is the this binding rule that I'm going to talk to you about right now.

1. This

What is this? Before we talk about this binding, we need to figure out what this stands for.

This is one of the keywords of JavaScript. It is an internal object automatically generated by the object and can only be used inside the object. The value of this changes depending on where the function is used.

What this points to depends entirely on where and how it is called, not when it is created. (it is very semantic, what this means in English, but it actually plays a misleading role, because this is not immutable and does not always point to the current one.)

2. This binding rules

Having mastered the four binding rules described below, you can determine the direction of the this as long as you see the function call.

2. 1 default binding

Consider the following code:

Function foo () {var a = 1; console.log (this.a); / / 10} var a = 10; foo ()

This is a typical default binding. Let's take a look at the location of the foo call, the "light rod commander". For a function call that is used directly without any modification, the default binding can only be applied.

Where is it bound by default? it's usually on window, and it's undefined in strict mode.

2. 2 implicit binding

The code speaks:

Function foo () {console.log (this.a);} var obj = {a: 10, foo: foo} foo (); / /? Obj.foo () / /?

Answer: undefined 10

Are you familiar with the writing of foo (), which is the default binding we just wrote, which is equivalent to printing window.a, so output undefined

The following obj.foo () should be written frequently, which is actually the implicit binding we're going to talk about right now.

The function foo executes with a context object, obj. In this case, the this in the function is bound to the context object by default, which is equivalent to printing obj.a, so the output is 10.

If it is a chain relationship, such as xx.yy.obj.foo ();, the context takes the immediate superior of the function, that is, the one next to it, or the * * of the object chain.

2. 3 explicit binding

2. 3. 1 restrictions on implicit binding

There is a fatal limitation in our implicit binding just now, that is, the context must contain our function, for example: var obj = {foo: foo}, if the context does not contain our function with implicit binding, it is obviously an error, it is impossible for every object to add this function, then the extension, the maintainability is too poor, we then talk about directly to the function mandatory binding this.

2. 3. 2 call apply bind

Here, we will use the functions call and apply provided by js, which are used to change the this point of the function. The * parameters are all set to the this object.

The difference between the two functions:

Call starts with the second argument. All arguments are arguments to the original function.

Apply accepts only two parameters, and the second argument must be an array, which represents the argument list of the original function.

For example:

Function foo (foo.apply b) {console.log (aforb);} foo.call (null,' Ocean', 'biscuit'); / / Ocean Biscuit foo.apply (null, ['Ocean', 'Biscuit']) is written here if this is not important; / / Ocean Biscuit

In addition to the call,apply function, there is also a function bind that changes this, which is different from call,apply.

Bind has only one function and does not execute immediately, but simply binds a value to the function's this and returns the bound function. Example:

Function foo () {console.log (this.a);} var obj = {a: 10}; foo = foo.bind (obj); foo (); / / 10

(the bind function is very special. Let's discuss its source code next time.)

2. 3. 2 explicit binding

To get to the point, let's go to the code, using the example of implicit binding above:

Function foo () {console.log (this.a);} var obj = {a: 10 / / remove the foo} foo.call (obj); / / 10

We removed the function from the context object in the implicit binding example, and obviously we can't use the context now. Function to call a function, you see the explicit binding code foo.call (obj) in the code, which looks strange and different from the function calls we have known before.

Call is actually a function on foo that executes while changing the direction of the this.

(friends who want to understand more about [call apply bind this hard binding, soft binding, arrow function binding] and more cool techs are welcome to follow my comments or this article. Recently, I will do a separate issue and write an article together. (for those who don't want to read it, don't worry, it won't affect your understanding of this article.)

2. 4 new binding

2. 4. 1 what is new

Those who have studied object-oriented must be familiar with new. Both new of js and new of traditional object-oriented language are used to create a new object, but their mechanisms are completely different.

To create a new object without a concept, that is constructor, the traditional object-oriented constructor is a special function in the class, to create an object using the form of new class name () to call the constructor in the class, but not in js.

A function in js that is decorated with new is a "constructor", precisely a constructor call to a function, because there is no such thing as a "constructor" in js.

So what does js do for us after using new to make the construction call to the function:

Create a new object.

Point the _ _ proto__ property of this new object to the prototype property of the original function. (that is, inheriting the prototype of the original function)

Bind the new object to the this of this function.

Returns the new object, if the function does not return any other objects.

The third is the new binding that we're going to talk about next.

2. 4. 2 new binding

No beep, look at the code:

Function foo () {this.a = 10; console.log (this);} foo (); / / window object console.log (window.a); / 10 default binding var obj = new foo (); / / the default name of the new object created by / / foo {a: 10} is the function name / then equivalent to foo {a: 10}; var obj = foo Console.log (obj.a); / / 10 new binding

After calling the function with new, the function names and creates a new object with its own name, and returns.

Special note: if the original function returns an object type, you will not be able to return the new object, and you will lose the new object bound to this, for example:

Function foo () {this.a = 10; return new String ("troublemaker");} var obj = new foo (); console.log (obj.a); / / undefined console.log (obj); / / "troublemaker"

2. 5 this binding priority

The process is some boring code testing, I wrote the priority directly (if you want to see the testing process, you can write a private message, I'll write a detailed test code for you)

New binding > Show binding > implicit binding > default binding

3. Summary

1. If the function is modified by new

This binds the newly created object, for example: var bar = new foo (); this in the function foo is a newly created object called foo, and then assigns the object to bar, which is called new binding.

two。 If the function is called using call,apply,bind

This binds * parameters of call,apply,bind. Example: foo.call (obj); this in foo is obj, which is called explicit binding.

3. If the function is called under a context object

This binds to that context object, for example: var obj = {foo: foo}; obj.foo (); this in foo is obj. This kind of binding is called implicit binding.

4. If neither, even use the default binding

Example: function foo () {...} foo (), the this in foo is window. (bind to undefined by default in strict mode).

This kind of binding is called default binding.

4. Analysis of interview questions

1.

Var x = 10; var obj = {x: 20, f: function () {console.log (this.x); / /? Var foo = function () {console.log (this.x);} foo (); / /?}}; obj.f ()

-answer-

Answer: 20 10

Parsing: test site 1. This default binding 2. This implicit binding

Var x = 10; var obj = {x: 20, f: function () {console.log (this.x); / / 20 / / typical implicit binding, where f's this points to context obj, that is, output 20 function foo () {console.log (this.x);} foo () / / 10 / / some people take it for granted that foo is in function f and also executes in f. / / then this must point to obj. If you take a closer look at the this binding rules we are talking about, it is easy to / / find this kind of 'light commander'. Is the default binding that we demonstrated at the beginning, where this binds window}} Obj.f ()

two。

Function foo (arg) {this.a = arg; return this}; var a = foo (1); var b = foo (10); console.log (a.a); / /? Console.log (b.a); / /?

-answer-

Answer: undefined 10

Analysis: test site 1. Global pollution 2. This default binding

This question is very interesting, the questions are basically focused on * undefined, this is actually a small trap of the topic, but the process of stack pursuit is absolutely wonderful

Let's analyze what's going on here step by step:

When foo (1) executes, it should not be difficult to see that it is the default binding. This points to window, which is equivalent to window.a = 1 window.a return window in the function.

Var a = foo (1) is equivalent to window.a = window. Many people ignore that var an is window.an and replace the one that has just been assigned.

So the value of a here is window, and A.An is also window, that is, window.a = window; window.a.a = window

Foo (10), like * times, is the default binding. At this time, assign window.a to 10. Note that this is the key here. The original window.a = window is now assigned to 10 and becomes a value type, so now A.A = undefined. (to verify this, just var b = foo (10); delete, A.An or window here)

Var b = foo (10); equivalent to window.b = window

The values of all variables in this question, a = window.a = 10, a.a = undefined, b = window, b.a = window.a = 10

3.

Var x = 10; var obj = {x: 20, f: function () {console.log (this.x);}}; var bar = obj.f; var obj2 = {x: 30, f: obj.f} obj.f (); bar (); obj2.f ()

-answer-

Answer: 20 10 30

Analysis: legendary delivery questions, test sites, identification of this binding

Var x = 10; var obj = {x: 20, f: function () {console.log (this.x);}}; var bar = obj.f; var obj2 = {x: 30, f: obj.f} obj.f (); / / 20 / / with context, this is obj, implicit binding bar () / / 10 / / the default binding of 'light commander' (obj.f is just a normal assignment operation) obj2.f (); / / 30 / / regardless of the twists and turns of the f function, this is only related to the location and mode of execution, that is, what we call binding rules

4. * *

Function foo () {getName = function () {console.log (1);}; return this;} foo.getName = function () {console.log (2);}; foo.prototype.getName = function () {console.log (3);}; var getName = function () {console.log (4);}; function getName () {console.log (5);} foo.getName (); / /? GetName () / /? Foo (). GetName (); /? GetName () / /? New foo.getName () / /? New foo (). GetName (); /? New new foo (). GetName (); /?

-answer-

Answer: 2 4 1 1 2 3 3

Parsing: test site 1. New binding 2. Implicit binding 3. Default binding 4. Variable pollution (words may not be accurate)

Function foo () {getName = function () {console.log (1);}; / / the getName here will be created on the global window return this;} foo.getName = function () {console.log (2);}; / / this getName is different from the above, foo.prototype.getName = function () {console.log (3);} is added directly to the foo / / this getName is added directly to the prototype of foo. When creating a new object with new, it will be directly added to the new object var getName = function () {console.log (4);}; / / like getName in the foo function, function getName () {console.log (5) will be created on the global window. } / / same as above, but this function will not be used, because the priority of the function declaration is raised * *, so the above function expression will always replace / / this function of the same name, unless getName () is called before the function expression is assigned, but in this case, the function call comes after the function expression / So this function can ignore / / through the above analysis of getName, basically the answer has come out foo.getName () / / 2 / / for convenience, I will use the output value to abbreviate each getName function / / there is a doubt that it is between 2 and 3, and I think it should be 3, but actually set the property on / / foo.prototype directly It has no effect on the properties of the current object. If you want to make / / use it, you can call foo.prototype.getName (). What you need to know here is that / / 3 does not overwrite 2, and the two do not conflict (when you create an object using new The / / Prototype here will automatically bind to the new object, that is, the second function of the construction call with new) getName () / / 4 / / when it comes to function promotion, unknown partners only need to know that 5 will be covered by 4. / although 5 is below 4, js is not completely top-down. For those who want to know more about it, please read the link to foo (). GetName () / / 1 / / the foo function execution here accomplishes two things, 1. Set window.getName to 1, / / 2. Return window, so it is equivalent to window.getName (); output 1 getName (); / / 1 / / the above function just set window.getName to 1, so output 1 new foo.getName () as above / / 2 / / new makes a construction call to a function, that is, foo.getName, and the construction call is also called ah / / should it be executed or executed, and then returns a new object Output 2 (although the newly created object is not received here, we can guess that it is an object named foo.getName / and there is a getName function in the _ _ proto__ property, which is the 3 function set above) new foo () .getName () / / 3 / / what's special here is that new makes a construction call to a function. It directly finds the nearest function, foo (), and returns the new object, which is equivalent to var obj = new foo (). / / obj.getName (); this makes it clear that the output is the getName 3 that was previously bound to prototype, because using new will inherit the prototype of the function to the new object new new foo () .getName () / / 3 / / , this looks scary. Let's break it down: / / var obj = new foo (); / / var obj1 = new obj.getName () / / well, take a closer look, isn't this the combination of the previous two questions? obj has getName 3, that is, the output 3 / / obj is an object named foo, and obj1 is an object named obj.getName.

5. This binding for arrowhead functions (updated on September 18, 2017)

The arrow function, a special function, does not use the function keyword, but uses = >, the scientific name Fat Arrow (2333), which is different from the ordinary function:

Instead of using the four bindings we described above, the arrow function determines the this entirely based on the external scope. (its parent uses our rules)

The this binding of the arrow function cannot be modified (this feature is very cool (funny))

Let's take a look at the code to consolidate it:

Function foo () {return () = > {console.log (this.a);}} foo.a = 10; / / 1. The arrow function associates the parent scope this var bar = foo (); / / foo binds bar () by default; / / undefined , is there a partner who takes it for granted that var baz = foo.call (foo); / / foo explicit binding baz (); / 10 / / 2. The arrow function this cannot be modified / / here we use the above baz var obj = {a: 999} baz.call (obj) that has been bound to foo; / / 10

Come on, let's do some practical work, remember our previous example, changing it to the form of an arrow function (which can completely solve the disgusting this binding problem):

Var people = {Name: "Ocean Biscuit", getName: function () {console.log (this.Name);}}; var bar = people.getName; bar (); / / undefined

= modified =

Var people = {Name: "Ocean Biscuit", getName: function () {return () = > {console.log (this.Name);}; var bar = people.getName (); / / isn't it nice to get a function that points to people forever without thinking about this? Bar (); / / Ocean Biscuit

Some people may wonder why they put another layer on the outside of the arrowhead function and just write it. Why bother? in fact, this is also a bad place for many people to use the arrowhead function. Come on, cookies will take you to fly (but break my nb, insert me in the waist):

Var obj= {that: this, bar: function () {return () = > {console.log (this);}}, baz: () = > {console.log (this);}} console.log (obj.that); / / window obj.bar () (); / / obj obj.baz (); / / window

Let's make it clear that the current scope of obj is window, such as obj.that = = window.

If you don't wrap it without function (function has its own function scope), the parent scope of the default binding is window.

The purpose of wrapping with function is to bind the arrow function to the current object. The scope of the function is the current object, and then the arrow function automatically binds the this in the scope of the function, that is, obj.

At this point, I believe you have a deeper understanding of "how to understand the This binding of Js". You might as well do it in practice. Here is the website, more related content can enter the relevant channels to inquire, follow us, continue to learn!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report