花を移して木を接ぎます——更にjavascriptの中のcallとappyを話します.

5910 ワード

JavaScriptでは、callとapplyはFunctionオブジェクトが持つ2つの方法であり、この2つの方法の主な役割は関数のthisの指向を変えることであり、したがって`花移木`の効果を達成することができる.本論文ではこの二つの方法を詳しく説明し、callとapplyに関する古典的な応用シーンをいくつか並べます.
 
call(thisArgs[,args...])
この方法は、運転中の関数の使用者、すなわち関数内のthisオブジェクトを指定したthisArgsパラメータとパラメータリストを渡すことができ、パラメータリストは呼び出し関数に入力されます.thisArgsの評価は以下の4つの場合があります.
(1)伝えない、またはnull、undefinedを伝え、関数の中のthisはwindowオブジェクトを指します.
(2)他の関数の関数名を伝え、関数のthisはこの関数の参照を指します.
(3)伝達文字列、数値またはブールタイプなどの基礎タイプで、関数の中のthisはString、Number、Booleanなどの対応する包装対象を指します.
(4)オブジェクトを伝達し、関数の中のthisはこのオブジェクトを指します.
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
これはコールの核心機能です.オブジェクトに定義されていない方法を呼び出すことができます.そしてこの方法はオブジェクトの属性にアクセスできます.このようにすると何かメリットがありますか?後でまた話します.簡単な例を見ます.
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!
b.callを実行すると、文字列`test`がパラメータとして関数bに伝達され、callの役割により、関数bのthisはオブジェクトaを指すので、オブジェクトaの関数bを呼び出すのに相当し、実際にはaにbは定義されていない.
 
apply(thisArgs[,args[])
applyとcallの唯一の違いは第二のパラメータの伝達方式が違っています.applyの第二のパラメータは配列でなければなりません.callはパラメータリストの伝達を許可します.注意すべきなのは、applyが受信したのはパラメータ配列ですが、関数を呼び出した時にはパラメータリストとして伝達されています.簡単な例を見ます.
function b(x,y,z){
    console.log(x,y,z);
}

b.apply(null,[1,2,3]); // 1 2 3
applyのこの特性はとても重要で、以下の応用シーンでこの特性を言及します.
 
応用シーン一:継承
JavaScriptにはJava、C((zhi)などの高級言語の中のextedキーワードがないので、JSには継承の概念がありません.もし継承したいなら、callとappyはこの機能を実現できます.
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
new演算子によってcatが生まれた場合、Catのthisはcatオブジェクトを指します.http://www.cnblogs.com/onepixel/p/5043523.html)の継承の鍵は、CatでAnimal.call(this,'cat','50')という言葉が実行され、callではthisをthis Argsパラメータとして伝達し、アニマル法のthisはCatの中のthisを指しています.catの中のthisはcatの対象を指すので、アニマルの中のthisはcatの対象を指し、アニマルの中でnameとweightの属性を定義したのはcatの中でこれらの属性を定義したのに相当し、アニマルの中で定義された属性を持つことで継承の目的を達成しました.
 
応用シーンその2:シフォンウッド
以下の内容を話す前に、まずJavaScriptの中の非標準専門用語を紹介します.ARrayLike(クラス配列/擬似配列)
ArayLikeオブジェクトは配列の一部を持っている行為で、DOMではすでに表現されていますが、jQueryの上昇によって、ArayLikeはJavaScriptで大いに異彩を放っています.ArayLikeオブジェクトの精妙はJS原生のArayと似ていますが、自由に構築されています.開発者からJavaScriptオブジェクトに対する拡張から来ています.つまり、プロトタイプはJS原生のArayを汚染することなく自由に定義できます. 
ArayLikeオブジェクトは、JSで広く使用されています.例えば、DOMのNodeList、関数のアーグメンツは、配列のように各要素が格納されていますが、配列を操作する方法はありません.配列のいくつかの方法をcallでArayLikeオブジェクトに移動し、その要素を操作する目的を達成することができます.例えば、関数の中のargmentsをこのように遍歴することができます.
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);
これ以外にも、applyにとっては、その独自の特性、すなわちapply受信は配列であり、呼び出し関数に伝達するときはパラメータリストで伝達される.この特性は、たとえばcallよりもapplyの方がはるかに優れているように見える.配列の中の最大要素を求めて、行列の中で最大値を得る方法がないことを知っています.一般的には、コードを書くことによって実現する必要があります.一方、Mathオブジェクトには最大値を取得する方法があり、Math.max()という方法があり、max方法はパラメータリストを転送して、これらのパラメータの最大値を返す必要があることを知っています.アプリは、Mathオブジェクトのmax方法を他のオブジェクトに適用するだけでなく、一つの配列をパラメータリストに変換してmaxに渡すこともでき、コードを見れば一目瞭然です.
var arr = [2,3,1,5,4];

Math.max.apply(null,arr); // 5
以上はcallとappyの古典的ないくつかの応用シーンです.これらの技術を熟練に把握して、これらの特性を実際のプロジェクトに応用すると、コードがより味わい深いように見えます.
 
by@一画素ブログ園2016.01
 
転載と共有を歓迎しますが、出典と接続を明記してください.