Maison  >  Article  >  interface Web  >  Utilisation élégante de This en js

Utilisation élégante de This en js

php中世界最好的语言
php中世界最好的语言original
2018-06-04 10:05:101407parcourir

Cette fois, je vais vous présenter l'utilisation élégante de This en js. Quelles sont les précautions pour l'utilisation élégante de This en js. Ce qui suit est un cas pratique, jetons un coup d'œil.

Lorsqu'une fonction est appelée, un enregistrement d'activité (contexte d'exécution) est créé.

Cet enregistrement contiendra des informations telles que l'endroit où la fonction a été appelée (pile d'appels), la méthode d'appel de la fonction, les paramètres transmis, etc.

C'est l'un des attributs enregistrés et sera utilisé lors de l'exécution de la fonction.

Cela n'indique ni la fonction elle-même ni la portée de la fonction.

Il s'agit en fait d'une liaison qui se produit lorsque la fonction est appelée, et ce vers quoi elle pointe dépend entièrement de l'endroit où la fonction est appelée.
En mode strict, lorsqu'une fonction générale est appelée, cela pointe vers undefined.

1. Pourquoi utiliser ceci

Cela fournit un moyen plus élégant de « transmettre » implicitement une référence à un objet, afin que l'API puisse être conçue pour être plus concise et facile à reproduire. .
par exemple :

var me = {  
    name: "fenfei"  };  
  
//不使用this,调用  function speak(name){  
    console.log("Hello, I'm "+ name);  
}  
speak(me.name);     //Hello, I'm fenfei  
  //使用this,调用  function speak(){  
    console.log("Hello, I'm "+ this.name);  
}  
speak.call(me);     //Hello, I'm fenfei


2. Deux malentendus à ce sujet

(1) cela pointe vers la fonction elle-même
(2) ) cela indique la portée de la fonction.

Scope n'est pas accessible via le code JavaScript, il existe dans le moteur JavaScript. Chaque fois que vous mélangez cela avec des recherches lexicales, n'oubliez pas que c'est impossible !

Ceci est lié au moment de l'exécution, pas au moment de l'écriture. Son contexte dépend de diverses conditions lorsque la fonction est appelée. La liaison de ceci n'a rien à voir avec l'emplacement de la déclaration de fonction, elle dépend uniquement de l'emplacement appelant de la fonction (c'est-à-dire de la manière dont la fonction est appelée) !

3. Règles de liaison

1) Liaison par défaut

Le type d'appel de fonction le plus couramment utilisé : appel de fonction indépendant. Considérez cette règle comme la règle par défaut lorsqu'aucune autre règle ne peut être appliquée.
par exemple :

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

2) Règles implicites

La règle de liaison implicite est de savoir s'il y a un objet de contexte à l'emplacement appelant, ou s'il appartient ou est inclus par un objet.

function foo() {  console.log(this.a);
}var obj = {    a: 2,    foo: foo
};
obj.foo(); // 2

. Lorsque foo() est appelé, this est lié à obj, donc this.a et obj.a sont identiques.

Mais parfois, une perte implicite se produit.

function foo() {  console.log(this.a);
}var obj = {    a: 2,    foo: foo
};var bar = obj.foo; // 函数  var a = "oops, global"; //bar(); // "oops, global"

. Bien que bar soit une référence à obj.foo, il fait en réalité référence à la fonction foo elle-même.
Donc, bar() à ce stade est en fait un appel de fonction sans aucune modification, avec une liaison par défaut appliquée.
3) Afficher la liaison

appeler et postuler
. En JavaScript, appeler et postuler sont comme les parents de celui-ci. Ils doivent vivre là où ils habitent, et ils doivent obéir ! Lorsqu'il n'y a pas de paramètres, l'objet actuel est window
par exemple :

var name="全局";var xpg={    name:"局部"};function getName(){
    alert(this.name);
}
getName(xpg);//全局getName.call(xpg);//局部getName.call();//全局

. Parmi eux, c'est dans la fonction getName. Peu importe où il se trouve, vous devez trouver l'emplacement lorsque la fonction est en cours d'exécution. A ce moment, la position de la fonction getName lorsqu'elle est en cours d'exécution, pour
(1) getName(xpg);//global
Évidemment, l'objet où se trouve la fonction getName est window, donc la maison de cela doit être dans la fenêtre, c'est-à-dire pointer vers objet fenêtre, alors this.name renvoyé par getName est en fait window.name, donc l'alerte est "globale" !
(2) getName.call(xpg);//Partial
. Parmi eux, call spécifie que la maison de this est l'objet xpg, car celui-ci est forcé de s'installer uniquement dans xpg, alors cela pointe vers l'objet xpg à ce moment-là, this.name est en fait xpg.name, donc l'alerte sort comme "local" !

bind()
. La méthode bind est fournie à partir d'es5, donc ie9+ ne prend en charge que
par exemple :

function f(){  
   return this.a;  
} 
var g = f.bind({a : "test"});   
//想把某个对象作为this的时候,就把它传进去,得到一个新对象gconsole.log(g()); // test      
 //重复调用的时候,this已经指向bind参数。
 //这对于我们绑定一次需要重复调用依然实现绑定的话,会比apply和call更加高效(看下面这个例子)var o = {a : 37, f : f, g : g};

console.log(o.f(), o.g()); passe L'appel d'attribut de l'objet, cela pointe vers l'objet o; //Ce qui est spécial, c'est que même si nous appelons la méthode nouvellement liée en tant qu'attribut d'objet, //o.g() suivra toujours la liaison précédente, donc la réponse est que le test n'est pas g

4) nouvelle liaison

nouvelle cette liaison ne peut pas être modifiée !

La nouvelle fonction appelante effectuera automatiquement les opérations suivantes :
(1) Créer (ou construire) un tout nouvel objet
(2) Ce nouvel objet sera exécuté [[Prototype]] connexion ;
(3) Ce nouvel objet sera lié à celui de l'appel de fonction
(4) Si la fonction ne renvoie pas d'autres objets, alors l'appel de fonction dans la nouvelle expression retournera automatiquement ce nouvel objet ; .
par exemple :

function Person(name,age) {  this.name = name  this.age = age  console.log("我也只不过是个普通函数")
}
Person("zxt",22) // "我也只不过是个普通函数"console.log(name) // "zxt"console.log(age) // 22var zxt = new Person("zxt",22) // "我也只不过是个普通函数"console.log(zxt.name) // "zxt"console.log(zxt.age) // 22

Dans l'exemple ci-dessus, une fonction Personne est d'abord définie, qui peut être appelée soit normalement, soit sous la forme d'un constructeur.
. Lorsqu'elle est appelée normalement, elle sera exécutée comme une fonction normale et une chaîne sera affichée.
. S'il passe par un nouvel opérateur, un nouvel objet est construit.
. Lors d'un appel normal, comme mentionné précédemment, les règles de liaison par défaut sont appliquées et celles-ci sont liées à l'objet global. À ce stade, deux attributs, nom et âge, seront ajoutés à l'objet global.
. Lorsqu'elle est appelée via l'opérateur new, la fonction renverra un objet. À partir du résultat de sortie, on peut voir que cet objet est lié à l'objet renvoyé.

Par conséquent, ce qu'on appelle la nouvelle liaison signifie que lorsqu'une fonction est appelée via l'opérateur new, un nouvel objet sera généré, et celui-ci dans le constructeur sera lié à cet objet.

4. Priorité

nouvelle liaison>callapply et autres liaisons d'affichage>liaison implicite>liaison par défaut.

了解了函数调用中this绑定的四条规则,需要做的就是找到函数的调用位置并判断对应哪条规则。

(1)函数是否是new绑定?如果是,this绑定的是新创建的对象。
var bar = new Foo();
(2)函数是否通过call、apply显示绑定或硬绑定?如果是,this绑定的是指定的对象。
var bar = foo.call(obj);
(3)函数是否在某个上下文对象中隐式调用?如果是,this绑定的是那个上下文对象。
var bar = obj.foo();
(4)上述全不是,则使用默认绑定。如果在严格模式下,就绑定到undefined,否则绑定到全局window对象。
var bar = foo();

new绑定和call、apply无法一起使用,因此不能使用new foo.call(obj).

五、this绑定例外

1)被忽略的绑定

如果你把null或者undefined作为this的绑定对象传入call、apply或者bind。
这些值在调用时会被忽略,实际应用的是默认绑定规则。
eg:

function foo() {  console.log(this.a);
}var a = 2;
foo.call(null); // 2

2)间接引用
eg:

function foo() {  console.log(this.a);
}var a = 2; 
var o = { a: 3, foo: foo }; 
var p = { a: 4 }; 
o.foo(); // 3(p.foo = o.foo)(); // 2

赋值表达式p.foo = o.foo的返回值是目标函数的引用,因此调用位置是foo()而不是p.foo()或者o.foo()。
3)当前对象不明确时的this

当没有明确的执行时的当前对象时,this指向全局对象window。
例如对于全局变量引用的函数上我们有:

var name = "Tom";var Bob = {    name: "Bob",    show: function(){
        alert(this.name);
    }
}var show = Bob.show;
show();  //Tom

。你可能也能理解成show是window对象下的方法,所以执行时的当前对象时window。但局部变量引用的函数上,却无法这么解释:

var name = "window";var Bob = {    name: "Bob",    showName: function(){
        alert(this.name);
    }
};var Tom = {    name: "Tom",    showName: function(){        var fun = Bob.showName;
        fun();
    }
};
Tom.showName();  //window

4)在浏览器中setTimeout、setInterval和匿名函数执行时的当前对象是全局对象window:

var name = "Bob";  
var nameObj ={  
      name : "Tom",  
      showName : function(){  
          alert(this.name);  
      },  
      waitShowName : function(){  
          setTimeout(this.showName, 1000);  
      }  
 };  
 nameObj.waitShowName();

5)软绑定
eg:

var count=2;var obj={    count:0,    cool:function coolFn(){        console.log(this.count);//0
         var self=this;        if(self.count<1){
            setTimeout(function timer(){
                self.count++;                console.log("awesome?");                console.log(self.count);//1
                console.log(this.count);//2
            },100);
        }
    }
};
obj.cool();

6)dom事件中的this

(1)直接在dom元素中使用
1eb9ebab541c78a07af4b7a6c86d652c

分析:对于dom元素的一个onclick(或其他如onblur等)属性,它为所属的html元素所拥有,直接在它触发的函数里写this,this应该指向该html元素。

(2)给dom元素注册js函数

a、不正确的方式

<script type="text/javascript">
  function thisTest(){
  alert(this.value); // 弹出undefined, this在这里指向??}</script><input id="btnTest" type="button" value="提交" onclick="thisTest()" />

。分析:onclick事件直接调用thisTest函数,程序就会弹出undefined。
因为thisTest函数是在window对象中定义的, 所以thisTest的拥有者(作用域)是window,thisTest的this也是window。而window是没有value属性的,所以就报错了。

b、正确的方式

<input id="btnTest" type="button" value="提交" /><script type="text/javascript">
  function thisTest(){
  alert(this.value); 
}document.getElementById("btnTest").onclick=thisTest; 
//给button的onclick事件注册一个函数</script>

。分析:在前面的示例中,thisTest函数定义在全局作用域(这里就是window对象),所以this指代的是当前的window对象。
而通过document.getElementById(“btnTest”).onclick=thisTest;这样的形式,其实是将btnTest的onclick属性设置为thisTest函数的一个副本,在btnTest的onclick属性的函数作用域内,this归btnTest所有,this也就指向了btnTest。

因为多个不同的HTML元素虽然创建了不同的函数副本,但每个副本的拥有者都是相对应的HTML元素,各自的this也都指向它们的拥有者,不会造成混乱。
eg:

<input id="btnTest1" type="button" value="提交1" onclick="thisTest()" /><input id="btnTest2" type="button" value="提交2" /><script type="text/javascript">function thisTest(){this.value="提交中";
}var btn=document.getElementById("btnTest1");
alert(btn.onclick); //第一个按钮函数var btnOther=document.getElementById("btnTest2");
btnOther.onclick=thisTest;
alert(btnOther.onclick); //第二个按钮函数</script>

其弹出的结果是:

//第一个按钮function onclick(){
  thisTest()
}//第二个按钮function thisTest(){  this.value="提交中";
}

7)this词法(ES6:箭头函数)

箭头函数不使用function关键字定义,而是使用“胖箭头”的操作符=>定义;箭头函数不使用this的四种标准规则,而是根据外层(函数或者全局)作用域来决定this。
eg:

function foo(){    return (a)=>{        //this继承自foo
        console.log(this.a);
    };
}var obj1={    a:2}var obj2={    a:3}var bar=foo.call(obj1);
bar.call(obj2);//2不是3!

foo()内部创建的箭头函数会捕获调用时foo()的this。由于foo()的this被绑定到obj1,bar(引用箭头函数)的this也被绑定到obj1,而箭头函数的绑定无法修改。(new的也不能!)

相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

推荐阅读:

怎样利用JS做出引用传递与值传递

使用JS实做出加密解密操作

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!

Déclaration:
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