Aray.prototype.slice.appleyと[].shift.callの使い方

5959 ワード

一、実例
例1、argmentsは、JavaScript文法において、関数特有のオブジェクト属性(Agmentsオブジェクト)であり、この関数を呼び出したときに伝達される実際のパラメータを参照するために使用される.
function test(){  
 //           
 var args = Array.prototype.slice.apply(arguments);  
 alert(args);  
} 
   argmentsは、クラスの配列オブジェクトであり、着信関数のすべてのパラメータを含んでおり、length属性を使用して、どれぐらいのパラメータが伝達されたかを決定することができます.直接的にアラgments.sliceを呼び出すと、「Object doesn't support this property or method」というエラーが返されます.argmentsは本物の配列ではないからです.上記のコードがAray.prototype.slice.appleyを呼び出すという意味は、関数のパラメータオブジェクトを本物の配列に変換することができるということです.一方,AgmentsオブジェクトとArayオブジェクトの親縁関係も推論できる.JavaScriptを編纂する時、argmentsの対象をArayに変えて処理する必要がある場合がよくあります.この技術は役に立ちます.Arayの他のプロトタイプ法は、アーグメンントにも適用されます. 
  var arg0 = Array.prototype.shift.apply(arguments); 
shiftは、配列の最初の要素を取得し、戻すためのArayの例示的な方法でもある.もちろん上記のような呼び出しは実行できますが、まったく余分です.直接にアーグメンツ[0]を呼び出してきた方がいいです.更に広く推してもいいです.私達はたくさんのアーチェリーのような形をしたCollectionの対象にこの技術を適用できます.
  Array.prototype.slice.apply(document.getElementsByTagName('div')); 
残念ながら、IEはこのような呼び出しをサポートしていません.FirefoxとOperaは正しい結果を得ることができます.
例2、
 function a(){ 
    var arr = Array.prototype.slice.apply(arguments) 
    console.log(arr);//[1,2,3,4,5] 
  } 
  a(1,2,3,4,5); 
 
  

  解释:apply是用来改变函数执行是this指向的,这里以argumens对象为this来执行Array.prototype.slice函数,而Array.prototype.slice函数不带参数时默认返回的是数组对象本身。

var ar = Array.prototype.slice.apply({0:1,length:1}) 
console.log(ar)//[1] 
  ここでは{0:1、length:1}を新しい配列にします.(ここでは属性名は0,1,2でなければなりません.また、length属性は少なくてはいけません.前の属性の個数に対応するべきです.このように、1つの配列をシミュレートしました.)
二、原理
1、まずはcall()、appy()とbind()の方法を理解する
各関数には、引き継ぎではない2つの方法が含まれています.この2つの方法の用途は特定の作用領域において関数を呼び出すことであり、実際には関数の内部のthisオブジェクトを設定する値に等しい.まず、apply()方法は、2つのパラメータを受け入れる.一つは、機能を実行するスコープ、もう一つはパラメータ配列である.ここで、第二のパラメータは、Arayの例であっても良いし、argmentsオブジェクトであっても良い.たとえば:   
    function sum(num1,num2) {
      return num1 + num2;
    }
    function callSum1(num1,num2) {
      return sum.apply(this,arguments);
    }
    function callSum2(num1,num2) {
      return sum.apply(this,[num1,num2]);
    }
    alert(callSum1(10,10));                    //20
    alert(callSum2(10,10));                    //20
上記の例では、コールSum 1()は、sum()関数を実行する際に、this値(グローバルスコープで呼び出されたので、伝わってきたのがwindowオブジェクト)とargmentsオブジェクトとして伝えられました.call Sum 2もsum()関数を呼び出しましたが、それが入ってきたのはthisとパラメータ配列です.
call()方法とappy()方法の役割は同じで、それらの違いは、受信パラメータの方式が異なるだけである.call()法に対して,最初のパラメータは作用領域に変化がなく,変化があるのは残りのパラメータだけが直接関数に伝達される. 
function callSum2(num1,num2) {
  return sum.call(this,num1,num2);
}
alert(callSum2(10,10));                    //20
実際には、伝達パラメータはapply()とcall()が本当に使う場所ではない.それらが本当に強いところは、関数を拡張して実行できるスコープです.次の例を見てください.
    window.color = 'red';
    var o = {color:'blue'};
    function sayColor() {
      alert(this.color);
    }
    sayColor();                //red
    sayColor.call(this);    //red
    sayColor.call(window);    //red
    sayColor.call(o);        //blue
上記の例では、sayColor.call(o)を実行すると、関数の実行環境が異なります.このとき、関数の体内のthisオブジェクトがoを指しているので、結果として「blue」が表示されます.call()またはapply()を使って作用領域を拡張する最大の利点は、オブジェクトが方法との結合関係を必要としないことである.
   bind()は、この方法は、bind()関数に伝える値に結合される関数の例を作成します.たとえば:
    window.color = 'red';
    var o = {color:'blue'};
    function sayColor() {
      alert(this.color);
    }
    var objectSayColor=sayColor.bind(o);
    objectSayColor();//blue
 
  

  在这里,SayColor()调用bind()并传入对象o,创建了objectSayColor()函数。objectSayColor()函数的this等于o,因此即使是在全局作用域中调用这个函数,与会看到“blue”。

注意点:(1)、 使用apply 时要注意:apply或call 只是切换了函数内部 this 的调用,但是执行的方法依然是原始对象上的方法, 即使你在 Array.prototype.slice.call(obj)的 obj 上 覆盖了slice 方法 ,依然会执行 Array 上的 slice 方法;(2)、 由于apply方法(或者call方法)也可以绑定函数执行时所在的对象,但是会立即执行函数,因此不得不把绑定语句写在一个函数体内。建议使用函数改变this指向时使用 bind 方法。(3)、bind方法每运行一次,就返回一个新函数,这会产生一些问题。比如,监听事件的时候,不能写成下面这样。

 element.addEventListener('click', o.m.bind(o));
上のコードは、clickイベントバインディングbind方法によって生成される匿名関数を表している.バインディングをキャンセルできなくなります.以下のコードは無効です.
 element.removeEventListener('click', o.m.bind(o));
の正しい方法は次のように書くことです.
var listener = o.m.bind(o);
element.addEventListener('click', listener);
//  ...
element.removeEventListener('click', listener);
2、配列は特殊なobjectオブジェクトです.
  jsには{0:1、length:1}またはDOMオブジェクト、あるいはargmentsオブジェクトのような種類の配列オブジェクトがあることを知っています.配列は特殊なオブジェクトであり、配列の特殊性は、そのキーはデフォルトでは順序で配列された整数(0,1,2...)ですので、配列は要素ごとにキー名を指定する必要はなく、オブジェクトの各メンバーはキー名を指定しなければなりません.  したがって、JavaScriptの配列もこのような対象と見なされます.
   var array = [1, 2, 3];
   var obj = {
      0: 1,
      1: 2,
      2: 3,
      length:3
   }
なお、このlength属性は重要であり、lengthがあれば配列のようにオブジェクトを巡ることができる.
3、簡単なslice方法を実現し、
function slice(start, end) {
  var array = [];
  start = start ? start : 0;
  end = end ? end : this.length;
  for (var i = start, j = 0; i < end; i++, j++) {
     array[j] = this[i];
  }
  return array;
}
  例として、Aray.prototype.slice.apply({0:1,length:1}applyにより、slice方式のthisをオブジェクトに向けて、新しい配列オブジェクトを遍歴して生成する.Aray.prototype.slice.apply({0:1,length:1}この場合は
var array=[1];
array.slice();
はっきり言ってこのオブジェクト{0:1,length:1}はこの場合は[1]と見なされます.つまり、sliceメソッドはパラメータを伝えていないので、startはundefinedです.sliceメソッドにstartが設定されていない場合、startは0となり、以下のように証明されます.
[1,2].slice(); // [1,2]
endが指定されていないなら、現在のオブジェクトのlength属性の値、つまり1です.結果は
{0:1}.slice(0, 1); //      
は新しい配列を返し、オブジェクトの中から0から1まで、つまりオブジェクトを0としてマークした値をとります.{0:1}[0]=>1だから[1]を返します.このようにAray.prototype.slice.applyを書くと({0:1,length:3}).結果は[1,undefined,undefined]です.