ホームページ  >  記事  >  ウェブフロントエンド  >  Javascript_javascriptスキルにおけるbind()メソッドの使用と実装の簡単な分析

Javascript_javascriptスキルにおけるbind()メソッドの使用と実装の簡単な分析

WBOY
WBOYオリジナル
2016-05-16 15:02:531286ブラウズ

bind() メソッドについて説明する前に、次の質問を見てみましょう:

var altwrite = document.write
altwrite("こんにちは"); //1. 上記のコードのどこが間違っています
//2. 正しい操作は何ですか
//3.bind()メソッドの実装方法

上記の質問に対する答えは、それほど難しくありません。 altwrite() 関数が this のポイントをグローバルまたはウィンドウ オブジェクトに変更することにより、不正な呼び出し例外が発生します。正しい解決策は、bind() メソッドを使用することです:

altwrite.bind(document)("hello")

もちろん、call() メソッドを使用することもできます:

altwrite.call(document, "hello")

この記事の焦点は、3 番目の問題である、bind() メソッドの実装について説明することです。bind() の実装について説明する前に、まず、bind() メソッドの使用方法を見てみましょう。
バインディング関数

bind() の最も簡単な使用法は、関数がどのように呼び出されたとしても同じ this 値を持つように関数を作成することです。よくある間違いは、上の例のように、オブジェクトからメソッドを取り出して呼び出し、これが元のオブジェクトを指すことを期待することです。特別な処理が行われない場合、通常、元のオブジェクトは失われます。 binding() メソッドを使用すると、この問題を見事に解決できます。



this.num = 9; 
var mymodule = { 
 num: 81,
 getNum: function() { return this.num; }
};

module.getNum(); // 81

var getNum = module.getNum; 
getNum(); // 9, 因为在这个例子中,"this"指向全局对象

// 创建一个'this'绑定到module的函数
var boundGetNum = getNum.bind(module); 
boundGetNum(); // 81 

部分関数 部分関数は部分アプリケーションとも呼ばれます。部分関数の定義は次のとおりです。

部分的なアプリケーションは、いくつかの引数を受け入れる関数を受け取り、それらの引数の 1 つ以上に値をバインドし、残りのバインドされていない引数のみを受け入れる新しい関数を返すものとして説明できます。

これは非常に優れた機能です。bind() を使用して、関数の事前定義されたパラメーターを設定し、呼び出し時に他のパラメーターを渡します。

function list() { 
 return Array.prototype.slice.call(arguments);
}

var list1 = list(1, 2, 3); // [1, 2, 3]

// 预定义参数37
var leadingThirtysevenList = list.bind(undefined, 37);

var list2 = leadingThirtysevenList(); // [37] 
var list3 = leadingThirtysevenList(1, 2, 3); // [37, 1, 2, 3] 
setTimeout と一緒に使用します

通常、setTimeout() の this はウィンドウまたはグローバル オブジェクトを指します。クラス メソッドを使用するときにこれをクラス インスタンスを指す必要がある場合は、bind() を使用してこれをコールバック関数にバインドし、インスタンスを管理できます。


注: 上記のメソッドはイベント処理関数や setInterval メソッドにも使用できます
function Bloomer() { 
 this.petalCount = Math.ceil(Math.random() * 12) + 1;
}

// 1秒后调用declare函数
Bloomer.prototype.bloom = function() { 
 window.setTimeout(this.declare.bind(this), 1000);
};

Bloomer.prototype.declare = function() { 
 console.log('我有 ' + this.petalCount + ' 朵花瓣!');
};

コンストラクターとして関数をバインド

バインド関数は、new 演算子を使用してターゲット関数のインスタンスを構築するのにも適しています。バインド関数を使用してインスタンスを構築する場合、これは無視されますが、渡されたパラメーターは引き続き使用できることに注意してください。


上記の例では、Point と YAxisPoint はプロトタイプを共有しているため、instanceof 演算子を使用する場合は true になります。
function Point(x, y) { 
 this.x = x;
 this.y = y;
}

Point.prototype.toString = function() { 
 return this.x + ',' + this.y; 
};

var p = new Point(1, 2); 
p.toString(); // '1,2'


var emptyObj = {}; 
var YAxisPoint = Point.bind(emptyObj, 0/*x*/); 
// 实现中的例子不支持,
// 原生bind支持:
var YAxisPoint = Point.bind(null, 0/*x*/);

var axisPoint = new YAxisPoint(5); 
axisPoint.toString(); // '0,5'

axisPoint instanceof Point; // true 
axisPoint instanceof YAxisPoint; // true 
new Point(17, 42) instanceof YAxisPoint; // true 

ショートカット

bind() は、特定の this 値を必要とする関数のショートカットを作成することもできます。

たとえば、配列のようなオブジェクトを実際の配列に変換する場合、考えられる例は次のとおりです:

bind() を使用すると、状況はより簡単になります。
var slice = Array.prototype.slice;

// ...

slice.call(arguments); 


var unboundSlice = Array.prototype.slice; 
var slice = Function.prototype.call.bind(unboundSlice);

// ...

slice(arguments); 
実績

上記のセクションから、bind() には多くの使用シナリオがあることがわかりますが、bind() 関数は ECMA-262 の第 5 版で追加されただけであり、すべてのブラウザで実行できるわけではありません。そのためには、bind() 関数を自分で実装する必要があります。

まず、ターゲット関数のスコープを指定することで、単純に binding() メソッドを実装できます。

関数のカリー化を考慮すると、より堅牢なbind()を構築できます。
Function.prototype.bind = function(context){ 
 self = this; //保存this,即调用bind方法的目标函数
 return function(){
   return self.apply(context,arguments);
 };
};


今回、bind() メソッドはオブジェクトをバインドでき、バインド中のパラメータの受け渡しもサポートします。
Function.prototype.bind = function(context){ 
 var args = Array.prototype.slice.call(arguments, 1),
 self = this;
 return function(){
   var innerArgs = Array.prototype.slice.call(arguments);
   var finalArgs = args.concat(innerArgs);
   return self.apply(context,finalArgs);
 };
};
続けて、JavaScript 関数はコンストラクターとしても使用できるため、バインドされた関数がこの方法で呼び出される場合、状況はより微妙になり、プロトタイプ チェーンの転送が関与する必要があります。


これは、書籍『JavaScript Web アプリケーション』に記載されている binding() の実装です。トランジット コンストラクター F を設定することで、バインドされた関数と、bind() を呼び出す関数が同じプロトタイプ チェーン上にあり、新しい操作が実行されます。 is used 演算子はバインドされた関数を呼び出し、返されたオブジェクトも通常どおりインスタンスオブを使用できるため、これは binding() の最も厳密な実装です。
Function.prototype.bind = function(context){ 
 var args = Array.prototype.slice(arguments, 1),
 F = function(){},
 self = this,
 bound = function(){
   var innerArgs = Array.prototype.slice.call(arguments);
   var finalArgs = args.concat(innerArgs);
   return self.apply((this instanceof F ? this : context), finalArgs);
 };

 F.prototype = self.prototype;
 bound.prototype = new F();
 return bound;
};
ブラウザでbind()関数をサポートするには、上記の関数を少し変更するだけで済みます。


JavaScript での binding() メソッドの使用と実装に関する上記の簡単な分析は、エディターによって共有されたすべての内容です。参考にしていただければ幸いです。また、Script Home をサポートしていただければ幸いです。
Function.prototype.bind = function (oThis) { 
  if (typeof this !== "function") {
   throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
  }

  var aArgs = Array.prototype.slice.call(arguments, 1), 
    fToBind = this, 
    fNOP = function () {},
    fBound = function () {
     return fToBind.apply(
       this instanceof fNOP && oThis ? this : oThis || window,
       aArgs.concat(Array.prototype.slice.call(arguments))
     );
    };

  fNOP.prototype = this.prototype;
  fBound.prototype = new fNOP();

  return fBound;
 };
声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。