Der folgende Inhalt wird in die folgenden Unterabschnitte unterteilt:
1. Die Quelle der Call/Apply/Bind-Methode
2. Function.prototype.call()
3. Function.prototype.apply()
3.1: Finden Sie die maximale Anzahl im Array
3.2: Ändern Sie die leeren Elemente des Arrays in undefiniert
3.3: Konvertieren eines Array-ähnlichen Objekts
4.Function.prototype.bind()
5. Objekt zur Bindung der Rückruffunktion
6 , Apply- und Bind-Methoden
1. Der Ursprung der Call/Apply/Bind-Methode
Bei der Verwendung der Call-, Apply- und Bind-Methoden müssen wir Folgendes tun Wissen Sie, woher diese drei Methoden kommen? Warum können diese drei Methoden verwendet werden?
Die drei Methoden call, apply und bind werden tatsächlich von Function.prototype geerbt und sind Instanzmethoden.
console.log(Function.prototype.hasOwnProperty('call')) //true console.log(Function.prototype.hasOwnProperty('apply')) //true console.log(Function.prototype.hasOwnProperty('bind')) //true
Im obigen Code wird true zurückgegeben, was darauf hinweist, dass die drei Methoden von Function.prototype geerbt werden. Natürlich erben alle gewöhnlichen Objekte, Funktionen und Arrays die drei Methoden im Function.prototype-Objekt, sodass diese drei Methoden in Objekten, Arrays und Funktionen verwendet werden können.
Das Konzept der Vererbung wird in Zukunft mit Ihnen geteilt.
2.Function.prototype.call()
Für die Aufrufmethode einer Funktionsinstanz können Sie den Zeiger dieser innerhalb der Funktion angeben (d. h. den Bereich, in dem die Funktion ausgeführt wird). wird ausgeführt) und dann im angegebenen Bereich der Funktion die Funktion aufrufen. Und die Funktion wird sofort ausgeführt.
Schauen Sie sich ein Beispiel an, um diese Passage zu verstehen.
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
Wenn im obigen Code das Schlüsselwort this in der a-Funktion auf das globale Objekt zeigt, ist das Rückgabeergebnis 456. Es ist ersichtlich, dass, wenn die Aufrufmethode keine Parameter hat oder die Parameter null oder undefiniert sind oder dies der Fall ist, dies einem Verweis auf das globale Objekt entspricht. Wenn Sie die Aufrufmethode verwenden, um das Schlüsselwort this auf das Keith-Objekt zu verweisen, d. h. der Bereich, in dem die Funktion ausgeführt wird, das Keith-Objekt ist, ist das Rückgabeergebnis 123.
Die Methode call() kann zwei Parameter übergeben. Der erste Parameter gibt den Zeiger innerhalb der Funktion an (dh den Bereich, in dem die Funktion ausgeführt wird), und der zweite Parameter ist der Parameter, der beim Aufruf der Funktion übergeben werden muss.
function keith(a, b) { console.log(a + b); } keith.call(null, 1, 2); //3
Der erste Parameter ist erforderlich und kann null, undefiniert oder this sein, darf aber nicht leer sein. Auf null (undefiniert) gesetzt bedeutet dies, dass sich die Funktion keith zu diesem Zeitpunkt im globalen Gültigkeitsbereich befindet. Der zweite Parameter muss einzeln hinzugefügt werden. Bei der Anwendung muss es in Form eines Arrays hinzugefügt werden.
Eine Anwendung der Aufrufmethode besteht darin, die native Methode des Objekts aufzurufen. Kann auch verwendet werden, um Array-ähnliche Objekte in Arrays umzuwandeln.
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
Im obigen Code ist hasOwnProperty eine vom obj-Objekt geerbte Methode. Wenn diese Methode überschrieben wird, wird nicht das richtige Ergebnis erhalten. Die Aufrufmethode kann dieses Problem lösen. Sie fügt die ursprüngliche Definition der hasOwnProperty-Methode zur Ausführung auf das Objekt obj ein, sodass das Ergebnis unabhängig davon, ob es eine Methode mit demselben Namen auf obj gibt, nicht beeinträchtigt wird. Es ist zu beachten, dass hasOwnProperty eine Methode des nativen Objekts von Object.prototype ist und call eine von Function.prototype geerbte Methode ist.
3.Function.prototype.apply()
Die Apply-Methode ähnelt der Call-Methode. Sie ändert auch den Punkt davon (den Bereich, in dem die Funktion ausgeführt wird) und dann Rufen Sie diese Funktion im angegebenen Bereich auf. Die Funktion wird auch sofort ausgeführt. Der einzige Unterschied besteht darin, dass es bei der Ausführung der Funktion ein Array als Parameter erhält.
Der erste Parameter der Apply-Methode ist auch das Objekt, auf das dies zeigt. Wenn er auf null oder undefiniert oder this gesetzt ist, entspricht dies der Angabe des globalen Objekts. Der zweite Parameter ist ein Array, und alle Mitglieder des Arrays werden nacheinander als Parameter verwendet und beim Aufruf an die ursprüngliche Funktion übergeben. Die Parameter der Originalfunktion müssen in der Aufrufmethode einzeln hinzugefügt werden, in der Apply-Methode müssen sie jedoch in Form eines Arrays hinzugefügt werden.
Schauen Sie sich die Nuancen der Ausschreibung an und bewerben Sie sich.
function keith(a, b) { console.log(a + b); } keith.call(null, 2, 3); //5 keith.apply(null, [2, 3]); //5
Im obigen Code ist der erste Parameter null und zeigt auf den globalen Bereich; der zweite Parameter wird in einer etwas anderen Form übergeben.
Die Apply-Methode hat die folgenden Anwendungen.
3.1: Finden Sie die maximale Zahl im Array
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 bietet keine Methode, um den maximalen Wert im Array zu finden. Verwenden Sie es in Kombination mit Die von Function geerbte Funktion. Die Methoden apply und Math.max von .prototype können den Maximalwert des Arrays zurückgeben.
3.2: Ändern Sie das leere Element des Arrays in undefiniert
Verwenden Sie die Methode „Apply“, um mit dem Array-Konstruktor das leere Element des Arrays in „undefiniert“ zu ändern.
console.log(Array.apply(null, [1, , 3])); // [1, undefiniert, 3]
Der Unterschied zwischen leeren Elementen und undefiniert ist, dass die Die forEach-Methode überspringt leere Elemente, undefinierte und null jedoch nicht. Daher erhalten Sie beim Durchlaufen der inneren Elemente unterschiedliche Ergebnisse.
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: Konvertieren eines Array-ähnlichen Objekts
Darüber hinaus können Sie mit der Slice-Methode des Array-Objekts ein Array-ähnliches Objekt konvertieren ( (z. B. Argumentobjekt) ist ein echtes Array. Eine wichtige Anwendung der Slice-Methode besteht natürlich darin, arrayähnliche Objekte in echte Arrays umzuwandeln. Sowohl call als auch apply können diese Anwendung implementieren.
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]
Die Parameter der Call- und Apply-Methoden im obigen Code sind alle Objekte, aber die Rückgabeergebnisse sind alle Arrays, in die die Objekte konvertiert werden Arrays Zweck. Wie Sie dem obigen Code entnehmen können, ist die Voraussetzung für das Funktionieren dieser Methode, dass das verarbeitete Objekt über ein Längenattribut und einen entsprechenden numerischen Schlüssel verfügen muss.
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关键字详解