Js this direction is the most commonly encountered in the work, but also the question will be asked in the written test or interview, so this article sorted out JS this direction for reference.

This article starts with the interview question, then moves on to JavaScript’s this point, and finally ends with the interview question.

The interview questions

var length = 10;

function fn ({
    console.log(this.length);
}

var obj = {
    length5.methodfunction (fn{
        fn();
        arguments[0]();
    }
};

obj.method(fn, 1);
Copy the code

Q: What is the output of the browser?

The answer is: print a 10, then a 2.

Resolution:

  1. In this case, fn is passed in as an argument to method, but its caller is still window, so it prints 10.
  2. arguments0; This is not a very common statement, so maybe you have some confusion here. Arguments are a special kind of object. In the function, we don’t have to specify the parameter name to access it. You can think of it as an implicit form of parameter passing.
  3. When performing arguments0; When, fn() is actually called. In this case, the fn function this refers to arguments, the special object. The obj.method method takes 2 arguments, so arguments length is clearly 2.

What is this

This is a keyword in JavaScript. It is usually applied inside a function, depending on the context in which the function is called, and how the function is called. Who it points to depends entirely on the point at which the function is called.

So, this is bound at run time, not at write time. The value of this changes depending on where the function is used. But the general rule is that this always refers to the object on which the function is called.

Js this points to

How do I determine if this points to? It can be judged in the following order:

// 1. Is the function called in new (new binding)? If so, this binds to the newly created object.
var bar = new foo();

// 2. Is the function called by call, apply, or hard bind? If so, this binds to the specified object.
var bar = foo.call(obj2);

// 3. Is the function called in a context object (implicit binding)? If so, this binds to that context object.
var bar = obj1.foo();

// 4. If not, use the default binding. If in strict mode, it is bound to undefined, otherwise it is bound to global objects
var bar = foo();
Copy the code

Don’t understand new binding, display binding, hard binding, implicit binding, default binding? It doesn’t matter, look below:

1. Default binding. Bind to undefined in strict mode, otherwise bind to global object.

Explanation:

The most common type of function call is: standalone function call. Think of this rule as the default rule when no other rule can be applied. Such as:

function foo ({
  console.log(this.a)
}
var a = 2;
foo(); / / 2
Copy the code

In this case, foo is called with the default binding applied, so this refers to the global object, and the variable declared in global scope (var a = 2, for example) is a property of the same name of the global object, so this.a is resolved to the global variable A when foo() is called.

So how do we know the default binding is applied here?

In the code, foo() is called directly with an undecorated function reference, so only the default binding can be used and no other rules can be applied.

If strict mode is used, you cannot use a global object for the default binding, so this is bound to undefined:

function foo({
  "use strict";
  console.log(this.a);
}
var a = 2;
foo(); // An error will be reported. TypeRrror: This is undefined.
Copy the code

There is one more important detail here, though the binding rules for this depend entirely on where it is called, but the default binding can only be global if foo() is not running in strict mode, and calling foo() in strict mode does not affect the default binding:

function foo({
  console.log(this.a);
}
var a = 2;
(function ({
  "use strict";
  foo(); / / 2}) ()Copy the code

In general, you should not mix strict and non-strict modes in your code. The whole procedure is either strict or not. However, third-party libraries may sometimes be used that are not as strict as your own code, so be sure to pay attention to these compatibility details.

2. Implicit binding. Called by a context object and bound to that context object.

Explanation:

Determine if the calling location has a context object, or is owned or contained by an object, as in:

function foo ({
  console.log(this.a)
}

var obj = {
  a2.foo: foo
}

obj.foo(); / / 2
Copy the code

The call location references the function using the OBJ context, so the OBJ object can be said to “own” or “contain” the function when it is called.

When a function reference has a context object, the implicit binding rule binds this in the function call to that context object. So this.a and obj. A are the same.

Only the last or upper level of the object attribute reference chain is involved in the call location, such as:

function foo({
  console.log( this.a );
}

var obj2 = {
  a42.foo: foo,
}

var obj1 = {
  a2.obj2: obj2,
}

obj1.obj2.foo(); / / 42
                
Copy the code

Implicit loss

Implicitly bound functions lose the binding object, that is, they apply the default binding binding to bind this to the global object or undefined. As follows:

function foo({
  console.log(this.a);
}

var obj = {
  a2.foo: foo
}

var bar = obj.foo; // Function alias
var a = 'global'// A is the value attribute of the global object
bar(); // 'global'
Copy the code

Although bar is a reference to obj.foo, it actually refers to the foo function itself, so bar() at this point is really a function call without any decorations, so the default binding is applied.

Implicit loss also occurs when a callback function is passed in:

function foo ({
  console.log(this.a);
}
function doFoo (fn{
  // fn actually refers to foo
  fn();
}

var obj = {
  a2.foo: foo
}

var a = 'global';
doFoo( obj.foo ); // 'global'
Copy the code

As in the previous example, fn refers to foo itself, so fn() is really an undecorated function call, so the default binding is applied.

The built-in setTimeout() function implementation in the JS environment is similar to the following pseudocode:

function setTimeout(fn, delay{
  // Wait delay milliseconds
  fn();
}
Copy the code

So functions passed to timers also apply the default binding.

3. Display the binding. The binding is shown by Call /apply/bind to the executing object.

Explanation:

We can explicitly specify this binding objects using the call and apply methods, as in:

function foo ({
  console.log(this.a);
}
var obj = {
  a2
}

foo.call(obj); / / 2
foo.apply(obj); / / 2
Copy the code

Through the foo. Call (…). , we can force foo to bind its this to obj when calling foo.

Hard binding

Call/apply still does not solve the problem of lost bindings, but it can be solved by displaying a variant of the binding, such as:

function foo({
  console.log(this.a);
}

var obj = {
  a2
}

var bar = function ({
  foo.call(obj);
}

bar(); / / 2
setTimeout(bar, 100); / / 2
bar.call( window ); / / 2. A force-bound bar can no longer modify its this.
Copy the code

Why does this happen?

Because we created the function bar() and manually called foo.call(obj) inside it, we forced foo’s this to be bound to obj. No matter how bar is later called, it will always manually call foo on obj. This binding is explicitly forced and is therefore called hard binding.

Since hard binding is a very common pattern, ES5 provides the method bind, which uses methods:

function foo(something{
  console.log(this.a, something);
  return this.a + something;
}
var obj = {
  a2,}var bar = foo.bind(obj);
var b = bar(3);/ / 2, 3
console.log(b); / / 5
Copy the code

Bind returns a new function that sets the specified argument to the context of this and calls the original function.

4. New binding. Called by new, bound to the newly created object.

Explanation:

When a function is called with new, or when a constructor call occurs, the following action is automatically performed:

  1. Create (construct) a brand new object.
  2. The new object will be connected by [[Prototype]].
  1. This new object is bound to the function call’s this.
  2. If the function returns no other object, the function call in the new expression automatically returns the new object.
function foo(a{
  this.a = a;
}
var bar = new foo(2);
console.log(bar.a); / / 2
Copy the code

Call foo(…) with new We construct a new object and bind it to foo(…). Call to this.

Note: Instead of using the four standard binding rules, arrow functions in ES6 determine this based on the current lexical scope. Specifically, arrow functions inherit the this binding of the outer function call (whatever this is bound to). This is actually the same mechanism as self=this in previous ES6 code.

Another interview question

Finally, let’s reinforce the concept and usage of this. Here’s an interview question:

window.val = 1;

var obj = {
    val2.dblfunction ({
        this.val *= 2; 
        val *= 2;       
        console.log('val:', val);
        console.log('this.val:'.this.val); }};// Say the following output
 obj.dbl();
 var func = obj.dbl;
 func();
Copy the code

The answer is output: 2, 4, 8, 8.

Resolution:

  1. Perform obj. DBL (); When this.val’s this points to obj, and val on the next line points to window. So, window.val prints 2 and obj.val prints 4.
  2. The last line func(); The caller to is Window. So now this.val’s this points to the window.
  1. Remember that window.val is already 2, so this.val *= 2; The result is 4.
  2. val *= 2; The result of this is 8. So, the end result is output 8 and 8.

Finally, listen to a sweet song to relax and recall what you have learned.

Click on the followingPlay the music

Xu Xinyu – Love 105°C you (full female voice version). Mp3 00:00 03:15# Let life be a little more lively

Long press the QR code to pay attention and work together.

Help with the missing person notice

Wechat public number reply add group study together.