Home > Web Front-end > JS Tutorial > body text

Relevant introduction to this, apply, call, and bind in JS

巴扎黑
Release: 2017-09-20 09:28:54
Original
1254 people have browsed it

This, apply, call, and bind in JS are a classic interview question. It is best to understand the difference between the direction of this and call, apply, and bind. Let's follow the editor of Script House to learn the knowledge of this, apply, call, and bind

This is another classic interview question~/(ㄒoㄒ)/~~It is also one of the many pitfalls in ES5 One, in ES6, errors caused by this may be greatly avoided, but in order to maintain some old code, it is best to understand the difference between the pointing of this and call, apply, and bind.

The pointing of this

In ES5, in fact, the pointing of this always adheres to one principle: this always points to the object that last called it , come on, read it three times after me: this always points to the last object that called it, this always points to the last object that called it, this always points to the last object that called it. Remember this sentence, you already know half of this.

Let’s take a 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: Window
Copy after login

I believe everyone knows why the log is windowsName, because according to the sentence just now "this always points to the object that last called it", we look at the last place where a was called a();, the object that was not called before is the global object window, which is equivalent to window. a(); Note that we are not using strict mode here. If strict mode is used, the global object is undefined, and the error Uncaught TypeError: Cannot read property 'name' of undefined will be reported.

Look at this example again:

Example 2:


var name = "windowsName";
 var a = {
  name: "Cherry",
  fn : function () {
   console.log(this.name);  // Cherry
  }
 }
 a.fn();
Copy after login

In this example, function fn is called by object a, So the printed value is the value of name in a. Is it a little clearer~

Let’s make a small change:

Example 3:


var name = "windowsName";
 var a = {
  name: "Cherry",
  fn : function () {
   console.log(this.name);  // Cherry
  }
 }
 window.a.fn();
Copy after login

Print Cherry here The reason is also because of the sentence just now "this always points to the object that last called it", and the last object that called it is still object a.

Let’s take a 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 after login

Why is undefined printed here? This is because, as just described, fn is called by object a, which means that the internal this of fn is object a, and name is not defined in object a, so the value of this.name in log is undefined. .

This example still illustrates: this always points to the object that last called it, because the object that last called fn was a, so even if there is no name attribute in a, it will not continue to search for this from the previous object. name, but output undefined directly.

Let’s look at a more confusing 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 after login

You may have questions here, why not Cherry? This is because although the fn method of the a object is assigned to the variable f, it is not called. Then read this sentence after me: "this always points to the object that last called it." Since the f just now was not called, so fn() is still called by window in the end. So this points to window.

We can see from the above five examples that the point of this cannot be determined when it is created. In es5, this always points to the object that last called it.

Let’s look at another example:

Example 6:


 var name = "windowsName";
 function fn() {
  var name = 'Cherry';
  innerFunction();
  function innerFunction() {
   console.log(this.name);  // windowsName
  }
 }
 fn()
Copy after login

You should be able to understand why this is happening after reading it now (o゚▽゚)o.

How to change the point of this

I summarized the following methods to change the point of this:

Use the arrow function of ES6

Use _this = this inside the function

Use apply, call, bind

new to instantiate one 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 function
Copy after login

If the arrow function is not used, an error will be reported, because the last object to call setTimeout is window, but There is no func1 function in window.

We will transform this example as a demo in this section of changing this pointer.

Arrow function

As we all know, ES6’s arrow function can avoid the pitfalls of using this in ES5. The this of an arrow function always points to this when the function is defined, not when it is executed. , the arrow function needs to remember this sentence: "There is no this binding in the arrow function, and its value must be determined by looking up the scope chain. If the arrow function is included by a non-arrow function, this binding is the nearest non-arrow function. function's this, otherwise, this is undefined".

Example 8:


 var name = "windowsName";
 var a = {
  name : "Cherry",
  func1: function () {
   console.log(this.name)  
  },
  func2: function () {
   setTimeout( () => {
    this.func1()
   },100);
  }
 };
 a.func2()  // Cherry
Copy after login

Use _this = this inside the function

If you do not use ES6, then this way should be The simplest error-free way is to first save the object that calls this function in the variable _this, and then use this _this in the function, so that _this will not 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()  // Cherry
Copy after login

这个例子中,在 func2 中,首先设置 var _this = this;,这里的 this 是调用 func2 的对象 a,为了防止在 func2 中的 setTimeout 被 window 调用而导致的在 setTimeout 中的 this 为 window。我们将 this(指向变量 a) 赋值给一个变量 _this,这样,在 func2 中我们使用 _this 就是指向对象 a 了。

使用 apply、call、bind

使用 apply、call、bind 函数也是可以改变 this 的指向的,原理稍后再讲,我们先来看一下是怎么实现的:

使用 apply

例 10:


 var a = {
  name : "Cherry",
  func1: function () {
   console.log(this.name)
  },
  func2: function () {
   setTimeout( function () {
    this.func1()
   }.apply(a),100);
  }
 };
 a.func2()   // Cherry
Copy after login

使用 call

例 11:


 var a = {
  name : "Cherry",
  func1: function () {
   console.log(this.name)
  },
  func2: function () {
   setTimeout( function () {
    this.func1()
   }.call(a),100);
  }
 };
 a.func2()   // Cherry
Copy after login

使用 bind

例 12:


var a = {
  name : "Cherry",
  func1: function () {
   console.log(this.name)
  },
  func2: function () {
   setTimeout( function () {
    this.func1()
   }.bind(a)(),100);
  }
 };
 a.func2()   // Cherry
Copy after login

apply、call、bind 区别

刚刚我们已经介绍了 apply、call、bind 都是可以改变 this 的指向的,但是这三个函数稍有不同。

在 MDN 中定义 apply 如下;

apply() 方法调用一个函数, 其具有一个指定的this值,以及作为一个数组(或类似数组的对象)提供的参数

语法:


fun.apply(thisArg, [argsArray])
Copy after login

thisArg:在 fun 函数运行时指定的 this 值。需要注意的是,指定的 this 值并不一定是该函数执行时真正的 this 值,如果这个函数处于非严格模式下,则指定为 null 或 undefined 时会自动指向全局对象(浏览器中就是window对象),同时值为原始值(数字,字符串,布尔值)的 this 会指向该原始值的自动包装对象。

argsArray:一个数组或者类数组对象,其中的数组元素将作为单独的参数传给 fun 函数。如果该参数的值为null 或 undefined,则表示不需要传入任何参数。从ECMAScript 5 开始可以使用类数组对象。浏览器兼容性请参阅本文底部内容。

apply 和 call 的区别

其实 apply 和 call 基本类似,他们的区别只是传入的参数不同。

call 的语法为:


fun.call(thisArg[, arg1[, arg2[, ...]]])
Copy after login

所以 apply 和 call 的区别是 call 方法接受的是若干个参数列表,而 apply 接收的是一个包含多个参数的数组。

例 13:


var a ={
  name : "Cherry",
  fn : function (a,b) {
   console.log( a + b)
  }
 }
 var b = a.fn;
 b.apply(a,[1,2])  // 3
Copy after login

例 14:


var a ={
  name : "Cherry",
  fn : function (a,b) {
   console.log( a + b)
  }
 }
 var b = a.fn;
 b.call(a,1,2)  // 3
Copy after login

bind 和 apply、call 区别

我们先来将刚刚的例子使用 bind 试一下


 var a ={
  name : "Cherry",
  fn : function (a,b) {
   console.log( a + b)
  }
 }
 var b = a.fn;
 b.bind(a,1,2)
Copy after login

我们会发现并没有输出,这是为什么呢,我们来看一下 MDN 上的文档说明:

bind()方法创建一个新的函数, 当被调用时,将其this关键字设置为提供的值,在调用新函数时,在任何提供之前提供一个给定的参数序列。

所以我们可以看出,bind 是创建一个新的函数,我们必须要手动去调用:


var a ={
  name : "Cherry",
  fn : function (a,b) {
   console.log( a + b)
  }
 }
 var b = a.fn;
 b.bind(a,1,2)()   // 3
Copy after login

The above is the detailed content of Relevant introduction to this, apply, call, and bind in JS. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template