This is another classic interview question, also one of the world “s remaining questions, which may well avoid this in ES6, but for some older code maintenance, it’s best to know the difference between this and call, apply and bind.
This article was first published on my personal website: cherryblog.site/
This point
In ES5, in fact, this always points to the same principle: this always points to the object that called it last, here, read after me three times: this always points to the object that called it last, this always points to the object that called it last, this always points to the object that called it last. Remember that, you already know half of this.
Let’s look at the simplest example: example 1:
var name = "windowsName";
function a() {
var name = "Cherry";
console.log(this.name); // windowsName
console.log("inner:" + this); // inner: Window
}
a();
console.log("outer:" + this) // outer: WindowCopy the code
This is always the name of the object that called it last, so let’s look at where a() was called last; , the object not previously called is the global object window, which is equivalent to window.a(); Uncaught TypeError: Cannot read property ‘name’ of undefined: Cannot read property ‘name’ of undefined: Cannot read property ‘name’ of undefined
Here’s another example: Example 2:
var name = "windowsName";
var a = {
name: "Cherry".fn : function () {
console.log(this.name); // Cherry
}
}
a.fn();Copy the code
In this case, the function fn is called by the object A, so the printed value is the value of the name in A. Is not a little clear ~
Let’s make one small change: example 3:
var name = "windowsName";
var a = {
name: "Cherry".fn : function () {
console.log(this.name); // Cherry}}window.a.fn();Copy the code
The reason for printing Cherry here is because “this always points to the last object that called it,” which is still object A.
Let’s look at this example again: example 4:
var name = "windowsName";
var a = {
// name: "Cherry",
fn : function () {
console.log(this.name); // undefined}}window.a.fn();Copy the code
Why is undefined printed here? This is because, as just described, fn is called from object A, that is, fn’s internal this is object A, and there is no name defined in object A, so log’s this.name value is undefined.
This always points to the last object to call it, because the last object to call fn is a, so even if a does not have the name attribute, it will not continue looking for this.name, but will print undefined directly.
Here’s another example: example 5:
var name = "windowsName";
var a = {
name : null.// name: "Cherry",
fn : function () {
console.log(this.name); // windowsName}}var f = a.fn;
f();Copy the code
Here you may be wondering why not Cherry, because the fn method of object A was assigned to the variable f, but it was not called. Then repeat this sentence after me: “This always points to the object that last called it.” Since f was not called, fn() is still called by window. So this refers to window.
As we can see from the above five examples, the reference to this is not determined at creation time. In ES5, this always refers to the last object that calls it.
Here’s another example:
var name = "windowsName";
function fn() {
var name = 'Cherry';
innerFunction();
function innerFunction() {
console.log(this.name); // windowsName
}
}
fn()Copy the code
Now that I have read about it, I can understand why (o゚▽゚) O.
How to change the direction of this
There are several ways to change the direction of this:
- Use ES6’s arrow function
- Used inside a function
_this = this
- use
apply
,call
,bind
- New instantiates an object
Example 7:
var name = "windowsName";
var a = {
name : "Cherry".func1: function () {
console.log(this.name)
},
func2: function () {
setTimeout( function () {
this.func1()
},100); }}; a.func2()// this.func1 is not a functionCopy the code
In the absence of the arrow function, an error is reported because the last object to call setTimeout is window, but func1 does not exist in window.
We’re going to change the point of this and we’re going to use this example as a demo in this section.
Arrow function
It is well known that the arrow function in ES6 can avoid the pit of using this in ES5. The this of the arrow function always points to this when the function is defined, not when it is executed. If the arrow function is contained by a non-arrow function, this is bound to this of the nearest non-arrow function. Otherwise, this is undefined.
Example 8:
var name = "windowsName";
var a = {
name : "Cherry".func1: function () {
console.log(this.name)
},
func2: function () {
setTimeout( (a)= > {
this.func1()
},100); }}; a.func2()// CherryCopy the code
Used inside a function_this = this
If you’re not using ES6, this is probably the easiest way to do it without any errors. You save the object that called the function in the variable _this, and then use the _this throughout the function, so that _this doesn’t change. Example 9:
var name = "windowsName";
var a = {
name : "Cherry".func1: function () {
console.log(this.name)
},
func2: function () {
var _this = this;
setTimeout( function() {
_this.func1()
},100); }}; a.func2()// CherryCopy the code
In this example, in func2, we first set var _this = this; In this case, this is an object a that calls func2, in order to prevent setTimeout in Func2 from being called by window, which causes this in setTimeout to be window. We assign this(pointing to variable a) to a variable _this, so that in func2 we use _this to refer to object a.
Use apply, call, and bind
This can also be changed using the apply, call, or bind functions. We’ll see how this works later.
Use the apply
Example 10:
var a = {
name : "Cherry".func1: function () {
console.log(this.name)
},
func2: function () {
setTimeout( function () {
this.func1()
}.apply(a),100); }}; a.func2()// CherryCopy the code
Use the call
Example 11:
var a = {
name : "Cherry".func1: function () {
console.log(this.name)
},
func2: function () {
setTimeout( function () {
this.func1()
}.call(a),100); }}; a.func2()// CherryCopy the code
Use the bind
Example 12:
var a = {
name : "Cherry".func1: function () {
console.log(this.name)
},
func2: function () {
setTimeout( function () {
this.func1()
}.bind(a)(),100); }}; a.func2()// CherryCopy the code
Distinguish apply, call, and bind
We’ve shown that apply, call, and bind can all change the reference to this, but they are slightly different.
Define apply in MDN as follows;
The apply() method calls a function with a specified value of this and parameters provided as an array (or array-like object)
Grammar:
fun.apply(thisArg, [argsArray])
- ThisArg: The value of this specified when fun is run. Note that the value specified is not necessarily the actual value of this when the function is executed. If the function is in non-strict mode, null or undefined automatically points to the global object (which in the browser is the window object) and the value is the original value (number, string, Boolean) points to an autowrap object for the original value.
- ArgsArray: An array or array-like object whose array elements are passed as separate arguments to fun. If the value of this parameter is null or undefined, no parameters need to be passed. Array-like objects are available starting with ECMAScript 5. See the bottom of this article for browser compatibility.
The difference between apply and call
In fact, apply and Call are similar, except that the parameters passed in are different.
The syntax for call is:
fun.call(thisArg[, arg1[, arg2[, ...]]])Copy the code
So the difference between apply and Call is that call takes a list of arguments, whereas apply takes an array of arguments.
Example 13:
var a ={
name : "Cherry".fn : function (a,b) {
console.log( a + b)
}
}
var b = a.fn;
b.apply(a,[1.2]) / / 3Copy the code
Example 14:
var a ={
name : "Cherry".fn : function (a,b) {
console.log( a + b)
}
}
var b = a.fn;
b.call(a,1.2) / / 3Copy the code
Bind is different from apply and call
Let’s try our example with bind
var a ={
name : "Cherry".fn : function (a,b) {
console.log( a + b)
}
}
var b = a.fn;
b.bind(a,1.2)Copy the code
We will see that there is no output. Why is this? Let’s look at the documentation on the MDN:
The bind() method creates a new function, sets its this keyword to the supplied value when called, and provides a given sequence of arguments before any supply when the new function is called.
So we can see that bind creates a new function that we must call manually:
var a ={
name : "Cherry".fn : function (a,b) {
console.log( a + b)
}
}
var b = a.fn;
b.bind(a,1.2) ()/ / 3Copy the code
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = update = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Function calls in JS
(innerFunction) (innerFunction) (window) (innerFunction) (innerFunction) (innerFunction) (innerFunction) (innerFunction) (innerFunction) (innerFunction) (innerFunction) (innerFunction) (innerFunction) (innerFunction) (innerFunction) Example 6:
var name = "windowsName";
function fn() {
var name = 'Cherry';
innerFunction();
function innerFunction() {
console.log(this.name); // windowsName
}
}
fn()Copy the code
Example 7:
var name = "windowsName";
var a = {
name : "Cherry".func1: function () {
console.log(this.name)
},
func2: function () {
setTimeout( function () {
this.func1()
},100); }}; a.func2()// this.func1 is not a functionCopy the code
There are four ways to call a function
- As a function call
- Functions are called as methods
- The constructor is used to call the function
- Calling functions as function methods (call, apply)
As a function call
Example 1:
var name = "windowsName";
function a() {
var name = "Cherry";
console.log(this.name); // windowsName
console.log("inner:" + this); // inner: Window
}
a();
console.log("outer:" + this) // outer: WindowCopy the code
So the simplest thing to do is to use a function that doesn’t belong to any object, it’s just a function, and in JavaScript in the browser in non-strict mode the default is to use the global object window, and in strict mode it’s undefined.
However, this is a global function that can easily cause name conflicts, so it is not recommended.
Functions are called as methods
So more often than not, functions are used as methods of objects. Example 2:
var name = "windowsName";
var a = {
name: "Cherry".fn : function () {
console.log(this.name); // Cherry
}
}
a.fn();Copy the code
Here we define an object a that has a property (name) and a method (fn).
Object A then calls its fn method through the. Method.
And then we always remember the phrase “this always refers to the last object that called it,” so this in FN refers to a.
The constructor is used to call the function
If a function call is preceded by the new keyword, the constructor is called. This looks like a new function is being created, but in fact JavaScript functions are recreated objects:
// Constructor:
function myFunction(arg1, arg2) {
this.firstName = arg1;
this.lastName = arg2;
}
// This creates a new object
var a = new myFunction("Li"."Cherry");
a.lastName; / / return "Cherry"Copy the code
This leads to another classic interview question: add | intersect | intersect | intersect | new; the pseudocode adds:
var a = new myFunction("Li"."Cherry");
new myFunction{
var obj = {};
obj.__proto__ = myFunction.prototype;
var result = myFunction.call(obj,"Li"."Cherry");
return typeof result === 'obj'? result : obj;
}Copy the code
- Create an empty object obj;
- Points the implicit stereotype of the newly created empty object to the display stereotype of its constructor.
- Use call to change the direction of this
- If there is no return value or a non-object value is returned, obj is returned as a new object; If the return value is a new object then return the object directly.
So we can see that in the new process, we are using call to change the direction of this.
Call functions as function methods
In JavaScript, functions are objects.
A JavaScript function has its properties and methods. Call () and apply() are predefined function methods. Two methods can be used to call a function, and the first argument to both methods must be the object itself
In JavaScript strict mode, when the function is called, the first argument becomes the value of this, even if the argument is not an object. In JavaScript non-strict mode, if the value of the first argument is null or undefined, it is replaced by a global object.
Example 6:
var name = "windowsName";
function fn() {
var name = 'Cherry';
innerFunction();
function innerFunction() {
console.log(this.name); // windowsName
}
}
fn()Copy the code
Is the call to innerFunction() one of the first calls: as a function call (it is called as a function call, not mounted on any object, so in non-strict mode this refers to the window for functions that are not mounted on any object)?
Then look at example 7. Example 7:
var name = "windowsName";
var a = {
name : "Cherry".func1: function () {
console.log(this.name)
},
func2: function () {
setTimeout( function () {
this.func1()
},100); }}; a.func2()// this.func1 is not a functionCopy the code
A simpler way to think about it is “this of an anonymous function always points to window,” so you can think of it as “this always points to the last object that called it,” so let’s find the last object that called the anonymous function, which is embarrassing, because anonymous function names, So there is no way to call anonymous functions from other objects. So anonymous function this always points to window.
If you want to know how anonymous functions are defined, first of all, we usually write anonymous functions that are self-executing, by adding () to them and making them self-executing. The second is that although anonymous functions cannot be called by other objects, they can be called by other functions, such as setTimeout in example 7.