Heim > Web-Frontend > js-Tutorial > Hauptteil

Eine kurze Diskussion über Call-, Apply- und bind_javascript-Techniken in Javascript

WBOY
Freigeben: 2016-05-16 15:11:45
Original
1325 Leute haben es durchsucht

In JavaScript sind call, apply und bind die drei Methoden, die mit dem Function-Objekt geliefert werden. Die Hauptfunktion dieser drei Methoden besteht darin, den This-Zeiger in der Funktion zu ändern, um den Effekt der „Übernahme von Blumen“ zu erzielen und Bäume entfernen‘. In diesem Artikel werden diese drei Methoden ausführlich erläutert und einige klassische Anwendungsszenarien aufgeführt.

Aufruf(thisArgs [,args...])

Diese Methode kann einen thisArgs-Parameter und eine Parameterliste übergeben. thisArgs gibt den Aufrufer der Funktion zur Laufzeit an, d. h. das this-Objekt in der Funktion, und die Parameterliste wird an die aufrufende Funktion übergeben. Der Wert von thisArgs hat die folgenden vier Situationen:

(1) Übergeben Sie nicht oder übergeben Sie null, undefiniert, dies zeigt in der Funktion auf das Fensterobjekt

(2) Übergeben Sie den Funktionsnamen einer anderen Funktion, und dieser in der Funktion zeigt auf einen Verweis auf diese Funktion

(3) Übergeben Sie grundlegende Typen wie Zeichenfolgen, Zahlen oder boolesche Typen. Dies zeigt in der Funktion auf das entsprechende Verpackungsobjekt, z. B. String, Number, Boolean

(4) Übergeben Sie ein Objekt, und dies zeigt in der Funktion auf dieses Objekt

function a(){
 console.log(this); //输出函数a中的this对象
}
function b(){} //定义函数b

var obj = {name:'onepixel'}; //定义对象obj

a.call(); //window
a.call(null); //window
a.call(undefined);//window
a.call(1); //Number
a.call(''); //String
a.call(true); //Boolean
a.call(b);// function b(){}
a.call(obj); //Object

Nach dem Login kopieren

Dies ist die Kernfunktion von call. Sie ermöglicht es Ihnen, eine undefinierte Methode für ein Objekt aufzurufen, und diese Methode kann auf die Eigenschaften im Objekt zugreifen. Auf die Vorteile dieser Vorgehensweise werde ich später noch näher eingehen Schauen Sie sich zunächst ein einfaches Beispiel an:

var a = {

 name:'onepixel', //定义a的属性

 say:function(){ //定义a的方法
  console.log("Hi,I'm function a!");
 }
};

function b(name){
 console.log("Post params: "+ name);
 console.log("I'm "+ this.name);
 this.say();
}

b.call(a,'test');
>>
Post params: test
I'm onepixel
I'm function a!

Nach dem Login kopieren

Wenn b.call ausgeführt wird, wird die Zeichenfolge „test“ als Parameter an Funktion b übergeben. Aufgrund der Funktion von call zeigt dies in Funktion b auf Objekt a, sodass es dem Aufruf von Funktion b für Objekt entspricht a. Tatsächlich ist b nicht in a definiert.

Anwenden(thisArgs[,args[]])

Der einzige Unterschied zwischen apply und call besteht in der Art und Weise, wie der zweite Parameter übergeben wird. Der zweite Parameter von apply muss ein Array sein, während call die Übergabe einer Parameterliste ermöglicht. Beachten Sie, dass apply zwar ein Parameterarray empfängt, dieses aber bei der Übergabe an die aufrufende Funktion in Form einer Parameterliste übergeben wird:

function b(x,y,z){
 console.log(x,y,z);
}

b.apply(null,[1,2,3]); // 1 2 3

Nach dem Login kopieren

Diese Funktion von Apply ist sehr wichtig, wir werden sie in den folgenden Anwendungsszenarien erwähnen.

bind(thisArgs [,args...])

bind ist eine neue Methode in ES5, ihre Parameter ähneln denen von call/apply, das heißt, beim Aufrufen von call oder apply wird die entsprechende Funktion automatisch ausgeführt, während bind die entsprechende Funktion nicht ausführt . Die Funktion gibt lediglich einen Verweis auf die Funktion zurück. Auf den ersten Blick scheint Bind hinter Call/Apply zurückzubleiben. Warum führt ES5 also Bind ein?

Tatsächlich besteht der eigentliche Zweck der Einführung von bind in ES5 darin, die Mängel von call/apply auszugleichen. Da call/apply die Zielfunktion automatisch ausführt, kann sie aufgrund der Ereignisbindung nicht in der Ereignisbindungsfunktion verwendet werden Funktion braucht nicht Wir machen es manuell, es wird automatisch von JS intern ausgeführt, wenn das Ereignis ausgelöst wird. Bind führt die Zielfunktion nicht automatisch aus, während es die Funktion ändert, sodass es die oben genannten Probleme perfekt lösen kann. Sie können es anhand eines Beispiels verstehen:

var obj = {name:'onepixel'};

/**
 * 给document添加click事件监听,并绑定onClick函数
 * 通过bind方法设置onClick的this为obj,并传递参数p1,p2
 */
document.addEventListener('click',onClick.bind(obj,'p1','p2'),false);

//当点击网页时触发并执行
function onClick(a,b){
 console.log(
   this.name, //onepixel
   a, //p1
   b //p2
 )
}

Nach dem Login kopieren

Wenn auf die Webseite geklickt wird, wird onClick ausgelöst und ausgeführt und ein Pixel p1 p2 ausgegeben, was darauf hinweist, dass dies in onClick durch bind in ein obj-Objekt geändert wurde. Um ein detailliertes Verständnis von bind zu erhalten, Werfen wir einen Blick auf die Polyfill-Implementierung von bind:

if (!Function.prototype.bind) {
 Function.prototype.bind = function (oThis) {
  var aArgs = Array.prototype.slice.call(arguments, 1),
   fToBind = this, //this在这里指向的是目标函数
   fBound = function () {
    return fToBind.apply(
     //如果外部执行var obj = new fBound(),则将obj作为最终的this,放弃使用oThis
     this instanceof fToBind
       ? this //此时的this就是new出的obj
       : oThis || this, //如果传递的oThis无效,就将fBound的调用者作为this

     //将通过bind传递的参数和调用时传递的参数进行合并,并作为最终的参数传递
     aArgs.concat(Array.prototype.slice.call(arguments)));
   };

  //将目标函数的原型对象拷贝到新函数中,因为目标函数有可能被当作构造函数使用
  fBound.prototype = this.prototype;

  //返回fBond的引用,由外部按需调用
  return fBound;
 };
}

Nach dem Login kopieren

Anwendungsszenario eins: Vererbung

Wie wir alle wissen, gibt es in Hochsprachen wie Java und C# kein Extend-Schlüsselwort, daher gibt es in JS kein Vererbungskonzept. Wenn Vererbung erforderlich ist, kann diese Funktion durch Aufrufen und Anwenden erreicht werden :

function Animal(name,weight){
 this.name = name;
 this.weight = weight;
}

function Cat(){
 Animal.call(this,'cat','50');
 //Animal.apply(this,['cat','50']);

 this.say = function(){
  console.log("I am " + this.name+",my weight is " + this.weight);
 }
}

var cat = new Cat();
cat.say();//I am cat,my weight is 50

Nach dem Login kopieren

当通过new运算符产生了cat时,Cat中的this就指向了cat对象,而继承的关键是在于Cat中执行了Animal.call(this,'cat','50') 这句话,在call中将this作为thisArgs参数传递,于是Animal方法中的this就指向了Cat中的this,而cat中的this指向的是cat对象,所以Animal中的this指向的就是cat对象,在Animal中定义了name和weight属性,就相当于在cat中定义了这些属性,因此cat对象便拥有了Animal中定义的属性,从而达到了继承的目的。

应用场景二:移花接木

在讲下面的内容之前,我们首先来认识一下JavaScript中的一个非标准专业术语:ArrayLike(类数组/伪数组)

ArrayLike 对象即拥有数组的一部分行为,在DOM中早已表现出来,而jQuery的崛起让ArrayLike在JavaScript中大放异彩。ArrayLike对象的精妙在于它和JS原生的Array类似,但是它是自由构建的,它来自开发者对JavaScript对象的扩展,也就是说:对于它的原型(prototype)我们可以自由定义,而不会污染到JS原生的Array。

ArrayLike对象在JS中被广泛使用,比如DOM中的NodeList, 函数中的arguments都是类数组对象,这些对象像数组一样存储着每一个元素,但它没有操作数组的方法,而我们可以通过call将数组的某些方法`移接`到ArrayLike对象,从而达到操作其元素的目的。比如我们可以这样遍历函数中的arguments:

function test(){
 //检测arguments是否为Array的实例
 console.log(
   arguments instanceof Array, //false
   Array.isArray(arguments) //false
 );
 //判断arguments是否有forEach方法
 console.log(arguments.forEach); //undefined

 // 将数组中的forEach应用到arguments上
 Array.prototype.forEach.call(arguments,function(item){
  console.log(item); // 1 2 3 4
 });

}
test(1,2,3,4);

Nach dem Login kopieren

除此之外,对于apply而言,我们上面提到了它独有的一个特性,即apply接收的是数组,在传递给调用函数的时候是以参数列表传递的。 这个特性让apply看起来比call 略胜一筹,比如有这样一个场景:给定一个数组[1,3,4,7],然后求数组中的最大元素,而你知道,数组中并没有获取最大值的方法,一般情况下,你需要通过编写代码来实现。而我们知道,Math对象中有一个获取最大值的方法,即Math.max(), max方法需要传递一个参数列表,然后返回这些参数中的最大值。而apply不仅可以将Math对象的max方法应用到其他对象上,还可以将一个数组转化为参数列表传递给max,看代码就能一目了然:

var arr = [2,3,1,5,4];

Math.max.apply(null,arr); // 5

Nach dem Login kopieren

以上便是call和apply比较经典的几个应用场景,熟练掌握这些技巧,并把这些特性应用到你的实际项目中,会使你的代码看起来更加耐人寻味!

Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage