Maison > interface Web > js tutoriel > Introduction pertinente à cela, postuler, appeler et lier en JS

Introduction pertinente à cela, postuler, appeler et lier en JS

巴扎黑
Libérer: 2017-09-20 09:28:54
original
1307 Les gens l'ont consulté

Ceci, postuler, appeler et lier en JS est une question d'entretien classique. Il est préférable de comprendre la différence entre la direction de ceci et appeler, postuler et lier. Suivons l'éditeur de Script House pour en apprendre davantage, postuler, appeler et lier

C'est une autre question d'entretien classique~/(ㄒoㄒ)/~~C'est aussi l'un des nombreux pièges dans ES5 One, dans ES6, les erreurs causées par cela peuvent être grandement évitées, mais afin de conserver un ancien code, il est préférable de comprendre la différence entre le pointage de celui-ci et l'appel, l'application et la liaison.

Le pointeur de this

Dans ES5, en fait, le pointeur de this adhère toujours à un principe : cela pointe toujours vers l'objet celui qui l'a appelé en dernier, allez, lis-le trois fois après moi : cela pointe toujours vers le dernier objet qui l'a appelé, cela pointe toujours vers le dernier objet qui l'a appelé, cela pointe toujours vers le dernier objet qui l'a appelé. Souvenez-vous de cette phrase, vous en connaissez déjà la moitié.

Jetons un coup d'œil à l'exemple le plus simple :

Exemple 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
Copier après la connexion

Je crois que tout le monde sait pourquoi ce journal est windowsName, car selon la phrase tout à l'heure "cela pointe toujours vers le dernier objet qui l'a appelé", on regarde le dernier endroit où a est appelé a();, l'objet qui n'a pas été appelé auparavant est l'objet global window, qui est équivalent à window.a(); Notez que nous n'utilisons pas le mode strict ici. Si le mode strict est utilisé, l'objet global n'est pas défini et l'erreur Uncaught TypeError: Cannot read property 'name' of undefined sera signalée.

Regardez à nouveau cet exemple :

Exemple 2 :


var name = "windowsName";
 var a = {
  name: "Cherry",
  fn : function () {
   console.log(this.name);  // Cherry
  }
 }
 a.fn();
Copier après la connexion

Dans cet exemple, la fonction fn est appelée par l'objet a , donc la valeur imprimée est la valeur de name dans a. Est-ce un peu plus clair~

Faisons un petit changement :

Exemple 3 :


var name = "windowsName";
 var a = {
  name: "Cherry",
  fn : function () {
   console.log(this.name);  // Cherry
  }
 }
 window.a.fn();
Copier après la connexion

Ici, la raison de l'impression Cherry est également dû à la phrase qui vient de se produire "cela pointe toujours vers l'objet qui l'a appelé en dernier", et le dernier objet qui l'a appelé est toujours l'objet a.

Reprenons cet exemple :

Exemple 4 :


 var name = "windowsName";
 var a = {
  // name: "Cherry",
  fn : function () {
   console.log(this.name);  // undefined
  }
 }
 window.a.fn();
Copier après la connexion

Pourquoi undéfini est-il imprimé ici ? En effet, comme nous venons de le décrire, fn est appelé par l'objet a, ce qui signifie que le this interne de fn est l'objet a et que name n'est pas défini dans l'objet a, donc la valeur de this.name dans log n'est pas définie.

Cet exemple illustre encore : cela pointe toujours vers l'objet qui l'a appelé en dernier, car l'objet qui a appelé fn en dernier était a, donc même s'il n'y a pas d'attribut name dans a, il ne continuera pas à rechercher ceci à partir du nom de l'objet précédent, mais sortie directement indéfinie.

Regardons un exemple plus déroutant :

Exemple 5 :


 var name = "windowsName";
 var a = {
  name : null,
  // name: "Cherry",
  fn : function () {
   console.log(this.name);  // windowsName
  }
 }
 var f = a.fn;
 f();
Copier après la connexion

Vous avez peut-être des questions ici, pourquoi pas ? Cherry, c'est parce que bien que la méthode fn de l'objet a soit affectée à la variable f, elle n'est pas appelée. Alors lisez cette phrase après moi : "cela pointe toujours vers l'objet qui l'a appelé en dernier", car f ne l'a tout simplement pas appelé. , donc fn() est toujours appelé par window à la fin. Cela pointe donc vers la fenêtre.

Nous pouvons voir à partir des cinq exemples ci-dessus que l'intérêt de ceci ne peut pas être déterminé lors de sa création. Dans es5, cela pointe toujours vers l'objet qui l'a appelé en dernier.

Regardons un autre exemple :

Exemple 6 :


 var name = "windowsName";
 function fn() {
  var name = 'Cherry';
  innerFunction();
  function innerFunction() {
   console.log(this.name);  // windowsName
  }
 }
 fn()
Copier après la connexion

Vous devriez être capable de comprendre pourquoi c'est le cas après avoir lu ceci (o゚▽゚)o.

Comment changer le point de ceci

J'ai résumé les méthodes suivantes pour changer le point de ceci :

Utilisez la fonction flèche d'ES6

et utilisez _this = this à l'intérieur de la fonction

Utilisez apply, call, bind

new pour instancier un objet

Exemple 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
Copier après la connexion

signalera une erreur sans utiliser la fonction flèche, car le dernier objet à appeler setTimeout est window , mais il n'y a pas de fonction func1 dans la fenêtre.

Nous allons transformer cet exemple en démo dans cette section de modification de ce pointeur.

Fonctions fléchées

Comme nous le savons tous, les fonctions fléchées de l'ES6 peuvent éviter les pièges liés à leur utilisation dans ES5. Le this d'une fonction fléchée pointe toujours vers ceci lorsque la fonction est définie, pas lorsqu'elle est exécutée. , la fonction flèche doit se souvenir de cette phrase : "Il n'y a pas de liaison this dans la fonction flèche, et sa valeur doit être déterminée en recherchant la chaîne de portée. Si la fonction flèche est incluse par une fonction non-flèche, cette liaison est la fonction non-flèche la plus proche est this, sinon, ceci n'est pas défini".

Exemple 8 :


 var name = "windowsName";
 var a = {
  name : "Cherry",
  func1: function () {
   console.log(this.name)  
  },
  func2: function () {
   setTimeout( () => {
    this.func1()
   },100);
  }
 };
 a.func2()  // Cherry
Copier après la connexion

Utilisez _this = this dans la fonction

Si vous n'utilisez pas ES6, alors ceci way Cela devrait être le moyen le plus simple et sans erreur. Nous enregistrons d'abord l'objet qui appelle cette fonction dans la variable _this, puis utilisons ce _this dans la fonction, afin que _this ne change pas.

Exemple 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
Copier après la connexion

这个例子中,在 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
Copier après la connexion

使用 call

例 11:


 var a = {
  name : "Cherry",
  func1: function () {
   console.log(this.name)
  },
  func2: function () {
   setTimeout( function () {
    this.func1()
   }.call(a),100);
  }
 };
 a.func2()   // Cherry
Copier après la connexion

使用 bind

例 12:


var a = {
  name : "Cherry",
  func1: function () {
   console.log(this.name)
  },
  func2: function () {
   setTimeout( function () {
    this.func1()
   }.bind(a)(),100);
  }
 };
 a.func2()   // Cherry
Copier après la connexion

apply、call、bind 区别

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

在 MDN 中定义 apply 如下;

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

语法:


fun.apply(thisArg, [argsArray])
Copier après la connexion

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[, ...]]])
Copier après la connexion

所以 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
Copier après la connexion

例 14:


var a ={
  name : "Cherry",
  fn : function (a,b) {
   console.log( a + b)
  }
 }
 var b = a.fn;
 b.call(a,1,2)  // 3
Copier après la connexion

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)
Copier après la connexion

我们会发现并没有输出,这是为什么呢,我们来看一下 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
Copier après la connexion

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal