Maison  >  Article  >  interface Web  >  Explication détaillée et résumé des méthodes d'appel, d'application et de liaison en Javascript

Explication détaillée et résumé des méthodes d'appel, d'application et de liaison en Javascript

巴扎黑
巴扎黑original
2016-12-22 13:51:451459parcourir

Le contenu suivant sera divisé dans les sous-sections suivantes :

1. La source de la méthode call/apply/bind

2. Function.prototype.call()

3. Function.prototype.apply()

 3.1 : Trouver le nombre maximum dans le tableau

 3.2 : Remplacer les éléments vides du tableau par non définis

3.3 : Convertir un objet de type tableau

4.Function.prototype.bind()

5. Objet pour lier la fonction de rappel

6. , apply et bind méthodes

1. L'origine de la méthode call/apply/bind

Tout d'abord, lors de l'utilisation des méthodes call, apply et bind, il nous est nécessaire de savez-vous d'où viennent ces trois méthodes ? Pourquoi ces trois méthodes peuvent-elles être utilisées ?

Les trois méthodes call, apply et bind sont en fait héritées de Function.prototype et sont des méthodes d'instance.

console.log(Function.prototype.hasOwnProperty('call')) //true
console.log(Function.prototype.hasOwnProperty('apply')) //true
console.log(Function.prototype.hasOwnProperty('bind')) //true

Dans le code ci-dessus, true est renvoyé, indiquant que les trois méthodes sont héritées de Function.prototype. Bien entendu, les objets, fonctions et tableaux ordinaires héritent tous des trois méthodes de l'objet Function.prototype, ces trois méthodes peuvent donc être utilisées dans des objets, des tableaux et des fonctions.

La notion d'héritage vous sera partagée dans le futur.

2.Function.prototype.call()

Pour la méthode d'appel d'une instance de fonction, vous pouvez spécifier le pointeur de ceci à l'intérieur de la fonction (c'est-à-dire la portée dans laquelle la fonction est exécuté), puis dans le champ spécifié Dans la portée de la fonction, appelez la fonction. Et la fonction sera exécutée immédiatement.

Regardez un exemple pour comprendre ce passage.

var keith = {
rascal: 123
};
var rascal = 456;
function a() {
console.log(this.rascal);
}
a(); //456
a.call(); //456
a.call(null); //456
a.call(undefined); //456
a.call(this); //456
a.call(keith); //123

Dans le code ci-dessus, si le mot-clé this dans la fonction a pointe vers l'objet global, le résultat renvoyé est 456. On voit que si la méthode d'appel n'a pas de paramètres, ou si les paramètres sont nuls ou indéfinis ou ceci, cela équivaut à pointer vers l'objet global. Si vous utilisez la méthode call pour pointer le mot-clé this vers l'objet Keith, c'est-à-dire que la portée dans laquelle la fonction est exécutée est l'objet Keith, le résultat renvoyé est 123.

La méthode call() peut transmettre deux paramètres. Le premier paramètre spécifie le pointeur de ceci à l'intérieur de la fonction (c'est-à-dire la portée dans laquelle la fonction est exécutée), et le deuxième paramètre est le paramètre qui doit être transmis lorsque la fonction est appelée.

function keith(a, b) {
 console.log(a + b);
 }
keith.call(null, 1, 2); //3

Le premier paramètre est obligatoire et peut être nul, indéfini ou this, mais ne peut pas être vide. Défini sur null, non défini, cela indique que la fonction Keith est actuellement dans la portée globale. Le deuxième paramètre doit être ajouté un par un. Lors de l'application, il doit être ajouté sous la forme d'un tableau.

Une application de la méthode call consiste à appeler la méthode native de l'objet. Peut également être utilisé pour convertir des objets de type tableau en tableaux.

var obj = {};
 console.log(obj.hasOwnProperty('toString')); //false
 obj.hasOwnProperty = function() {
 return true;
 }
 console.log(obj.hasOwnProperty('toString')); //true
 console.log(Object.prototype.hasOwnProperty.call(obj, 'toString')); //false

Dans le code ci-dessus, hasOwnProperty est une méthode héritée par l'objet obj. Si cette méthode est remplacée, le résultat correct ne sera pas obtenu. La méthode call peut résoudre ce problème. Elle place la définition originale de la méthode hasOwnProperty sur l'objet obj pour l'exécution, de sorte que peu importe s'il existe ou non une méthode du même nom sur obj, cela n'affectera pas le résultat. Il convient de noter que hasOwnProperty est une méthode de l'objet natif d'Object.prototype et que call est une méthode héritée de Function.prototype.

3.Function.prototype.apply()

La méthode apply est similaire à la méthode call, elle change également le point de celle-ci (la portée où la fonction est exécutée), puis. dans la portée spécifiée, appelez cette fonction. La fonction sera également exécutée immédiatement. La seule différence est qu'il reçoit un tableau en paramètre lors de l'exécution de la fonction.

Le premier paramètre de la méthode apply est également l'objet vers lequel cela pointe. S'il est défini sur null ou undefined ou this, cela équivaut à spécifier l'objet global. Le deuxième paramètre est un tableau, et tous les membres du tableau sont utilisés tour à tour comme paramètres et transmis à la fonction d'origine lors de l'appel. Les paramètres de la fonction d'origine doivent être ajoutés un par un dans la méthode call, mais dans la méthode apply, ils doivent être ajoutés sous forme de tableau.

Regardez les nuances de l'appel et postulez.

function keith(a, b) {
 console.log(a + b);
 }
 keith.call(null, 2, 3); //5
 keith.apply(null, [2, 3]); //5

Dans le code ci-dessus, le premier paramètre est nul, pointant vers la portée globale ; le deuxième paramètre est passé sous une forme légèrement différente.

La méthode d'application a les applications suivantes.

3.1 : Trouver le nombre maximum dans le tableau

var a = [2, 4, 5, 7, 8, 10];
console.log(Math.max.apply(null, a)); //10
console.log(Math.max.call(null,2, 4, 5, 7, 8, 10)); //10 

Javascript ne fournit pas de méthode pour trouver la valeur maximale dans le tableau. Utilisez-le en combinaison avec. la fonction héritée de Function Les méthodes apply et Math.max de .prototype peuvent renvoyer la valeur maximale du tableau.

3.2 : Changez l'élément vide du tableau en non défini

Utilisez la méthode apply pour utiliser le constructeur Array pour changer l'élément vide du tableau en non défini.

console.log(Array.apply(null, [1, , 3])); // [1, undefined, 3]

La différence entre les éléments vides et non définis est que le La méthode forEach ignorera les éléments vides, mais n'ignorera pas les éléments indéfinis et nuls. Par conséquent, en parcourant les éléments internes, vous obtiendrez des résultats différents.

var a = [1, , 3];
 a.forEach(function(index) {
 console.log(index); //1,3 ,跳过了空元素。
 })
 Array.apply(null,a).forEach(function(index){
 console.log(index); ////1,undefined,3 ,将空元素设置为undefined
 })

3.3 : Convertir un objet de type tableau

De plus, en utilisant la méthode slice de l'objet tableau, vous pouvez convertir un objet de type tableau ( tel qu'un objet arguments) est un vrai tableau. Bien entendu, une application importante de la méthode slice consiste à convertir des objets de type tableau en tableaux réels. Call et apply peuvent tous deux implémenter cette application.

console.log(Array.prototype.slice.apply({0:1,length:1})); //[1]
console.log(Array.prototype.slice.call({0:1,length:1})); //[1]
console.log(Array.prototype.slice.apply({0:1,length:2})); //[1,undefined]
console.log(Array.prototype.slice.call({0:1,length:2})); //[1,undefined]
function keith(a,b,c){
 return arguments;
 }
console.log(Array.prototype.slice.call(keith(2,3,4))); //[2,3,4]

Les paramètres des méthodes d'appel et d'application dans le code ci-dessus sont tous des objets, mais les résultats renvoyés sont tous des tableaux, ce qui convertit les objets en but des tableaux. Comme vous pouvez le voir dans le code ci-dessus, le principe du fonctionnement de cette méthode est que l'objet en cours de traitement doit avoir un attribut de longueur et une clé numérique correspondante.

4.Function.prototype.bind()

bind方法用于指定函数内部的this指向(执行时所在的作用域),然后返回一个新函数。bind方法并非立即执行一个函数。

var keith = {
 a: 1,
 count: function() {
 console.log(this.a++);
 }
 };
 keith.count(); //1
 keith.count(); //2
 keith.count(); //3

上面代码中,如果this.a指向keith对象内部的a属性,如果这个方法赋值给另外一个变量,调用时就会出错。

var keith = {
a: 1,
count: function() {
console.log(this.a++);
}
};
var f = keith.count;
f(); //NaN

上面代码中,如果把count方法赋值给f变量,那么this对象指向不再是keith对象了,而是window对象。而window.a默认为undefined,进行递增运算之后undefined++就等于NaN。

为了解决这个问题,可以使用bind方法,将keith对象里的this绑定到keith对象上,或者是直接调用。

var f = keith.count.bind(keith);
f(); //1
f(); //2
f(); //3
keith.count.bind(keith)() //1
keith.count.bind(keith)() //2
keith.count.bind(keith)() //3

   

 当然,this也可以绑定到其他对象上。

var obj = {
a: 100
};
var f = keith.count.bind(obj);
f(); //100
f(); //101
f(); //102

同样,我们也可以给bind方法传递参数,第一个参数如果为null或者undefined或者this,会将函数内部的this对象指向全局环境;第二个为调用时需要的参数,并且传递参数的形式与call方法相同。

function keith(a, b) {
return a + b;
}
console.log(keith.apply(null,[1,4])); //5
console.log(keith.call(null,1,4)); //5
console.log(keith.bind(null, 1, 4)); //keith()
console.log(keith.bind(null, 1, 4)()); //5

上面代码中,可以看出call,apply,bind三者的区别:call和apply方法都是在调用之后立即执行的。而bind调用之后是返回原函数,需要再调用一次才行,有点像闭包的味道,如果对闭包概念不熟悉,可以浏览这两篇文章:深入理解javascript函数参数与闭包,浅谈JavaScript的闭包函数。

5.绑定回调函数的对象

在这篇文章javascript中this关键字详解中,有谈及到如果在回掉函数中使用this对象,那么this对象是会指向DOM对象,也就是button对象。如果要解决回调函数中this指向问题,可以用如下方法。

var o = {
 f: function() {
 console.log(this === o);
 }
 }
 $('#button').on('click', function() {
 o.f.apply(o);
 //或者 o.f.call(o);
 //或者 o.f.bind(o)();
 });

点击按钮以后,控制台将会显示true。由于apply方法(或者call方法)不仅绑定函数执行时所在的对象,还会立即执行函数(而bind方法不会立即执行,注意区别),因此不得不把绑定语句写在一个函数体内。

6.call,apply,bind方法的联系和区别

  其实用于指定函数内部的this指向的问题,这三个方法都差不多,只是存在形式上的差别。读者可以将以上的例子用三种方法尝试用三种方法实现。

  总结一下call,apply,bind方法:

  a:第一个参数都是指定函数内部中this的指向(函数执行时所在的作用域),然后根据指定的作用域,调用该函数。

  b:都可以在函数调用时传递参数。call,bind方法需要直接传入,而apply方法需要以数组的形式传入。

  c:call,apply方法是在调用之后立即执行函数,而bind方法没有立即执行,需要将函数再执行一遍。有点闭包的味道。

  d:改变this对象的指向问题不仅有call,apply,bind方法,也可以使用that变量来固定this的指向。如有疑问,请访问 javascript中this关键字详解


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