Maison >interface Web >js tutoriel >Tout ce que vous voulez savoir à ce sujet est ici
Que ce soit dans l'utilisation quotidienne de javascript ou dans le processus d'entretien frontal, cela a un taux d'apparition très élevé. Cela illustre sans aucun doute l’importance de cela. Mais ceci est très flexible, ce qui fait que de nombreuses personnes trouvent son comportement difficile à comprendre. Cet article commence par expliquer pourquoi cela est nécessaire et résume les six règles. J'espère qu'il pourra vous aider à répondre à votre confusion.
Introduction
ceci est en fait équivalent à un paramètre. Ce paramètre peut être transmis manuellement lors du développement, ou il peut s'agir de JS ou du. troisième Entrant de trois parties.
Ce paramètre pointe généralement vers le "propriétaire" lorsque la fonction est exécutée. Ce mécanisme peut rendre la conception des fonctions plus concise et plus réutilisable.
this est lié lorsque la fonction est exécutée. Il y a six règles de liaison au total, à savoir :
Quantity new liaison : lors de l'utilisation du mot-clé new pour créer un objet, celui-ci sera lié à sur l'objet créé.
● Liaison explicite : lorsqu'elle est explicitement liée à l'aide de la méthode call, apply ou bind, il s'agit de son premier paramètre.
● Liaison implicite : lorsqu'une fonction est exécutée sur un objet, le système la liera implicitement à l'objet.
● Liaison par défaut : lorsque la fonction est exécutée indépendamment, la valeur de liaison par défaut de celle-ci en mode strict n'est pas définie, sinon il s'agit de l'objet global.
● Liaison de fonction flèche : lors de l'utilisation de fonctions fléchées, la valeur de liaison de this est égale à celle de sa fonction ordinaire externe (ou de l'objet global lui-même).
● Liaison système ou tiers : Lorsqu'une fonction est passée en paramètre à une interface fournie par le système ou un tiers, celle-ci dans la fonction passée est liée par le système ou le tiers.
Le rôle de ce
ce mécanisme fournit une manière élégante de transmettre implicitement un objet, ce qui permet une conception de fonction plus concise et mieux réutilisable.
Considérons l'exemple suivant de deux boutons qui changent leur arrière-plan en rouge lorsqu'ils sont cliqués.
function changeBackgroundColor(ele) { ele.style.backgroundColor = 'red'; } btn1.addEventListener('click',function () { changeBackgroundColor(btn1); }); btn2.addEventListener('click',function () { changeBackgroundColor(btn2); });
Ici, nous transmettons explicitement l'élément cliqué à la fonction changeBackgroundColor. Mais en fait, vous pouvez profiter de cette fonctionnalité de passage implicite du contexte pour obtenir l'élément actuellement cliqué directement dans la fonction. Comme suit :
function changeBackgroundColor() { this.style.backgroundColor = 'red'; } btn1.addEventListener('click',changeBackgroundColor); btn2.addEventListener('click',changeBackgroundColor);
Dans le premier exemple, l'élément cliqué est remplacé par ele, ce paramètre formel. Dans le deuxième exemple, il est remplacé par un mot-clé spécial this. Cela a une fonction similaire aux paramètres formels. Il s'agit essentiellement d'une référence à un objet. Sa particularité est qu'il ne nécessite pas de transfert de valeur manuel, il est donc plus simple et plus pratique à utiliser.
Six règles
En utilisation réelle, l'objet auquel cela fait référence est le plus déroutant. Cet article classe six types de scénarios et résume pour cela six règles contraignantes.
1.new liaison
Lors de l'utilisation de new pour créer un objet, ceci dans la classe fait référence à Qu'est-ce que c'est ?
class Person { constructor(name){ this.name = name; } getThis(){ return this } } const xiaoMing = new Person("小明"); console.log(xiaoMing.getThis() === xiaoMing); // true console.log(xiaoMing.getThis() === Person); // false console.log(xiaoMing.name === "小明"); // true
Dans l'exemple ci-dessus, la classe Person est créée en utilisant la syntaxe ES6. Lors du processus de création d'un objet à l'aide du nouveau mot-clé, celui-ci sera automatiquement lié à l'objet créé par le système, c'est-à-dire xiaoMing.
Règle 1 : Lorsque vous utilisez le mot-clé new pour créer un objet, celui-ci sera lié à l'objet créé.
2. Liaison explicite
Scénario 2, utilisez les méthodes call, apply et bind pour lier explicitement ce paramètre.
Prenons call comme exemple. Le premier paramètre transmis à la méthode call est l'objet référencé par celle-ci.
function foo() { console.log( this === obj ); // true console.log( this.a === 2 ); // true}const obj = { a: 2}; foo.call( obj );
Dans le cas d'un passage explicite, l'objet pointé par this est évident, qui est le premier paramètre de la méthode call, apply ou bind.
Règle 2 : Lorsqu'il est explicitement lié à l'aide de la méthode call, apply ou bind, il s'agit de son premier paramètre.
3. Liaison implicite
La différence entre la liaison implicite et la liaison explicite est que la liaison explicite Il appartient au développeur de spécifiez-le ; lorsqu'elle est implicitement liée, la fonction ou la méthode aura un "propriétaire", et ce "propriétaire" fait référence à l'objet fonction ou méthode qui est directement appelé.
Exemple 1
Regardons d'abord l'exemple le plus simple.
function bar() { console.log( this === obj ); }const obj = { foo: function () { console.log( this === obj ); }, bar: bar }; obj.foo(); // trueobj.bar(); // true
La fonction foo est directement accrochée dans l'objet obj, et la barre de fonctions est définie à l'extérieur puis accrochée à l'objet obj. Peu importe où la fonction est définie, lorsque la fonction est finalement appelée, son « propriétaire » est obj. Cela pointe donc vers l'obj "propriétaire" lorsque la fonction est appelée.
Exemple 2
Pour une compréhension plus approfondie, considérons le cas de la réaffectation d'une fonction à un nouvel objet.
function bar() { console.log( this === obj1 ); // false console.log( this === obj2 ); // true}const obj1 = { foo: function () { console.log( this === obj1 ); // false console.log( this === obj2 ); // true }, bar: bar };const obj2 = { foo: obj1.foo, bar: obj1.bar }; obj2.foo(); obj2.bar();
Dans cet exemple, les méthodes foo et bar dans obj1 sont affectées à obj2. Lorsque la fonction est appelée, le « propriétaire » est obj2 et non obj1. Cela pointe donc vers obj2.
Exemple 3
Les objets peuvent être imbriqués à plusieurs niveaux. Dans ce cas, lorsqu'une fonction est exécutée, qui est le « propriétaire » de la fonction ?
const obj1 = { obj2: { foo: function foo() { console.log( this === obj1 ); // false console.log( this === obj1.obj2 ); // true } } }; obj1.obj2.foo()
L'appelant direct dans la méthode/fonction foo est obj2, pas obj1, donc le "propriétaire" de la fonction pointe vers l'appelant direct le plus proche.
Exemple 4
如果一个方法/函数,在它的直接对象上调用执行,又同时执行了 call 方法,那么它是属于隐式绑定还是显式绑定呢?
const obj1 = { a: 1, foo: function () { console.log(this === obj1); // false console.log(this === obj2); // true console.log(this.a === 2); // true } };const obj2 = { a: 2}; obj1.foo.call(obj2); // true
由上,可以看出,如果显式绑定存在,它就不可能属于隐式绑定。
规则三:如果函数是挂在对象上执行的,这个时候系统会隐式的将 this 绑定为函数执行时的“拥有者”。
4.默认绑定
前一小段,讨论了函数作为对象的方法执行时的情况。本小段,要讨论的是,函数独立执行的情况。
在函数直接调用的情况下,this 绑定的行为,称之为默认绑定。
例一
为了简单起见,先讨论在浏览器的非严格模式的下绑定行为。
function foo() { console.log( this === window); // true} foo();
在上面的例子中,系统将 window 默认地绑定到函数的 this 上。
例二
在这里,先介绍一种我们可能会在代码中见到的显式绑定 null 的写法。
function foo() { console.log( this == window ); // true} foo.apply(null);
将例一默认绑定的情况,改为了显式绑定 null 的情况。
在实际开发中,我们可能会用到 apply 方法,并在第一个参数传入 null 值,第二个参数传入数组的方式来传递数组类型的参数。这是一种传统的写法,当然现在可以用 ES6 的写法来代替,但是这不在本文的讨论范围内。
在本例最需要关注的是,this 竟然指向的 window 而不是 null。个人测试的结果是,在函数独立调用时,或者显式调用,传入的值为 null 和 undefined 的情况下,会将 window 默认绑定到 this 上。
在函数多次调用,形成了一个调用栈的情况下,默认绑定的规则也是成立的。
例三
接着,探讨下严格模式下,this 的默认绑定的值。
"use strict"; function foo() { console.log( this === undefined ); } foo(); // true foo.call(undefined); // true foo.call(null); // false
在严格模式下,this 的默认绑定的值为 undefined。
规则四:在函数独立执行的情况下,严格模式 this 的默认绑定值为 undefined,否则默认绑定的值为 window。
5.箭头函数绑定
箭头函数实际上,只是一个语法糖,实际上箭头函数中的 this 实际上是其外层函数(或者 window/global 本身)中的 this。
// ES6 function foo() { setTimeout(() => { console.log(this === obj); // true }, 100); } const obj = { a : 1 } foo.call(obj); // ES5 function foo() { var _this = this; setTimeout(function () { console.log(_this === obj); // true }, 100); } var obj = { a : 1 } foo.call(obj);
规则五:使用箭头函数时,this 的绑定值和其外层的普通函数(或者 window/global 本身) this 绑定值相同。
6.系统或第三方绑定
在 JavaScript 中,函数是第一公民,可以将函数以值的方式,传入任何系统或者第三方提供的函数中。现在讨论,最后一种情况。当将函数作为值,传入系统函数或者第三方函数中时,this 究竟是如何绑定的。
我们在文章一开始提到的,两个按钮例子,系统自动将 this 绑定为点击的按钮。
function changeBackgroundColor() { console.log(this === btn1); // true} btn1.addEventListener('click',changeBackgroundColor);
接着测试系统提供的 setTimeout 接口在浏览器和 node 中绑定行为。
// 浏览器 setTimeout(function () { console.log(this === window); // true },0) // node setTimeout(function () { console.log(this === global); // false console.log(this); // Timeout },0)
很神奇的是,setTimeout 在 node 和浏览器中的绑定行为不一致。如果我们将 node 的中的 this 打印出来,会发现它绑定是一个 Timeout 对象。
如果是第三发提供的接口,情况会更加复杂。因为在其内部,会将什么值绑定到传入的函数的 this 上,事先是不知道的,除非查看文档或者源码。
系统或者第三方,在其内部,可能会使用前面的五种规则一种或多种规则,对传入函数的 this 进行绑定。所以,规则六,实际上一条在由前五条规则上衍生出来的规则。
规则六:调用系统或者第三方提供的接口时,传入函数中的 this 是由系统或者第三方绑定的。