bind() メソッドは、呼び出された時に新しい関数を生成します。新しい関数が呼び出される時、this キーワードは与えられた値がセットされ、ます。2 個目以降の引数は、新しい関数より前に、ターゲット関数の引数として与えられます。

構文

fun.bind(thisArg[, arg1[, arg2[, ...]]])

引数

thisArg
束縛された関数が呼ばれる時、this 値としてターゲット関数に渡される値を指定します。束縛された関数が new 演算子によって構築された場合、この引数は無視されます。
arg1, arg2, ...
ターゲット関数を呼び出す時、束縛された関数に与えられる引数の前に付けてターゲット関数に渡す引数。

返り値

thisや初期引数が指定された、与えられた関数のコピーです。

説明

bind() 関数は、新たな関数(束縛された関数 = a bound function; BFとも)を生成して返します。 BF特殊関数オブジェクト (exotic function object; ECMAScript 2015からの用語) であり、元の関数オブジェクトをラップします。BF を呼び出すとラップされた関数が実行されます。
BF は下記の内部プロパティを持ちます:

  • [[BoundTargetFunction]] - ラップされた関数オブジェクト;
  • [[BoundThis]] - ラップされた関数を呼び出す時に常に this に渡される値。
  • [[BoundArguments]] - ラップされた関数を呼び出す時に、その要素が第1引数として使われる値のリスト。
  • [[Call]] - オブジェクトに関連する実行コード。関数呼び出し式を通じて実行される。内部メソッドへの引数は this 値と呼び出し式によって関数に渡される引数を含むリスト。

束縛関数が呼ばれるとき、[[BoundTargetFunction]]上の内部メソッド [[Call]] を、次の引数とともに呼び出します: Call(boundThis, args)。ここで boundThis [[BoundThis]]args [[BoundArguments]] で、後に関数呼び出しで渡された引数が続きます。

束縛関数は new 演算子でも生成されます: これを行うとターゲット関数が代わりに生成されたようになります。与えられた this の値は無視され、追加された引数はエミュレートされた関数に提供されます。

束縛された関数を生成する

最もシンプルな bind() の使い方は、どのように呼び出された場合でも特定の this 値を持つ関数を生成することです。初心者の JavaScript プログラマーがよくやる間違いは、あるオブジェクトからメソッドを取り出し、後でその関数を呼び出すとき、その内側の this 値が元のオブジェクトになると考えてしまうことです(例えば、そのメソッドをコールバック関数に使うケース)。特に配慮しなければ、元のオブジェクトは失われてしまいます 【訳注: 取り出した関数内の this としては使えなくなる】。その関数に元々のオブジェクトを bind() して束縛された関数を生成すれば、この問題をきちんと解決することができます:

this.x = 9;    // this はブラウザーのグローバルな "window" オブジェクトを参照する
var module = { 
  x: 81,
  getX: function() { return this.x; }
};

module.getX(); // 81

var retrieveX = module.getX;
retrieveX(); 
// この関数はグローバルスコープで呼び出されるため9を返します。

// 'this' を module に結びつけた新しい関数を生成
// 初心者のプログラマーはグローバル変数の x と
// モジュールプロパティの x とを混同するかもしれません。
var boundGetX = retrieveX.bind(module);
boundGetX(); // 81

部分的に適用された関数

次にシンプルな bind() の使い方は、あらかじめ引数が指定された関数を生成することです。これらの引数は、this 値の後に続けます(指定しないことも可能)。すると、束縛された関数がいつ呼ばれても、この指定された引数を先頭にして束縛された関数の引数がターゲット関数に渡されます。

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

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

// 先頭の引数がプリセットされた関数をつくる
var leadingThirtysevenList = list.bind(undefined, 37);

var list2 = leadingThirtysevenList(); // [37]
var list3 = leadingThirtysevenList(1, 2, 3); // [37, 1, 2, 3]

setTimeout とともに

デフォルトで、window.setTimeout() 内部の this キーワードは window(あるいは global オブジェクト)に設定されます。クラスインスタンスを参照する this が必要なクラスメソッドを使う場合、this をコールバック関数と明確に結びつけて(束縛して)、インスタンスを維持することができます。

function LateBloomer() {
  this.petalCount = Math.floor(Math.random() * 12) + 1;
}

// 1 秒遅延させてから bloom を宣言する
LateBloomer.prototype.bloom = function() {
  window.setTimeout( this.declare.bind( this ), 1000 );
};

LateBloomer.prototype.declare = function() {
  console.log('I am a beautiful flower with 
              ' + this.petalCount + ' petals!');
};

var flower = new LateBloomer();
flower.bloom();  
// after 1 second, triggers the 'declare' method

束縛された関数をコンストラクタとして使う

警告: このセクションでは、JavaScript の性能(capabilities)を実演して bind() メソッドの極端な例を説明していますが、以下の方法がベストなわけではなく、むしろプロダクション環境では推奨されない方法です。

束縛された関数は自動的に、 new 演算子を使ってターゲット関数の新しいインスタンスを構築できるようになっています。新たな値を構築するために束縛された関数を使った場合、this を与えても無視されます。しかし、同時に与える引数はコンストラクタ呼び出しの先頭部分に挿入されます:

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'

// not supported in the polyfill below,

// works fine with native bind:

var YAxisPoint = Point.bind(null, 0/*x*/);


var emptyObj = {};
var YAxisPoint = Point.bind(emptyObj, 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

束縛された関数を new で使えるように生成するのに特別なことをする必要は無いので注意してください。当然、普通に呼び出される束縛された関数を生成する際も特別なことは必要ありません。もしその関数を new 演算子とともに呼び出すことにしか使いたくないと思っても、普通に呼び出すことはできてしまいます。

// この例は JavaScript コンソールで直接実行できます
// ...上の例のつづき

// 普通の関数としても実行できます
//(あまり必要にはなりませんが)
YAxisPoint(13);

emptyObj.x + "," + emptyObj.y;
// >  "0,13"

束縛された関数を new でしか使えないように制限したい場合、または通常の呼び出しだけに制限したい場合には、ターゲット関数がその制限を強制するようにしなければなりません。

ショートカットを作成する

bind() は、特定の this を必須とするような関数のショートカットを作成するのにも便利です。

例として、Array.prototype.slice を取り上げます。この関数は、配列に似たオブジェクトを本物の配列へ変換するために使えます。まず、次のようにショートカットを作成するとします:

var slice = Array.prototype.slice;

// ...

slice.call(arguments);

bind() を使うと、さらにシンプルにできます。次のコードでは、sliceFunction.prototypeapply() 関数に結びつけられた関数になり、その内側の this  値は Array.prototypeslice() 関数にセットされます。こうすると、いちいち apply() を呼び出す必要がなくなります:

 // ひとつ前の例の "slice" と同じ
var unboundSlice = Array.prototype.slice;
var slice = Function.prototype.call.bind(unboundSlice);

// ...

slice(arguments);

Polyfill

以下のコードをあなたのスクリプトの先頭に挿入すれば、その状況をいくらか変えることができます。ネイティブでサポートされていない実装において、bind() の多くの機能を使えるようになります。

if (!Function.prototype.bind) {
  Function.prototype.bind = function (oThis) {
    if (typeof this !== "function") {
      // closest thing possible to the ECMAScript 5
      // internal IsCallable 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,
                 aArgs.concat(Array.prototype.slice.call(arguments)));
        };

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

    return fBound;
  };
}

このアルゴリズムと仕様上のアルゴリズムとの間には、いくつか大きな違いがあります(真剣に網羅することを目指したわけではないので、他にも差はあるかもしれません):

  • この部分的な実装は、 Array.prototype.slice(), Array.prototype.concat(), Function.prototype.call()  Function.prototype.apply() という、それぞれオリジナルの値を持つ組み込みメソッドに依存している。
  • この不完全な実装がつくり出す関数は、不変の(immutable) "poison pill" caller プロパティと arguments プロパティ(get, set, delete の際に TypeError を投げる【訳注: strict mode での話をしているようだ】)を持たない( Object.defineProperty をサポートする実装の上ではこれを追加することができる。あるいは __defineGetter____defineSetter__ をサポートする実装上でも部分的に実装可能だが、delete の際に例外を投げるようにはできない)。
  • この不完全な実装は prototype プロパティを持つ関数をつくり出す(正規の束縛された関数には存在しない)。
  • この不完全な実装でつくられた束縛された関数の length プロパティは、ECMA-262 で示されているものと一致しない。この実装がつくる関数の length は常に 0 だが、完全な実装においては、ターゲット関数と先行定義引数の長さ次第で、0 ではない長さになりうる。

この不完全な実装を使うことを選ぶ場合は、ECMA-262 第5版の定義から外れる挙動に依存しないように! ただし、いくらか気をつければ(特定の要望に適するような追加修正も必要かもしれません)、この不完全な実装は、bind() が広く仕様通りに実装されるまでの悪くないつなぎとして使えるでしょう 【訳注: Prototype.js の Function#bind、jQuery の jQeury.proxy()、Underscore.js の _.bind() など多数のライブラリでも提供されています】

もっと完全な解決法は https://github.com/Raynos/function-bind を確認してください

仕様

仕様 状態 コメント
ECMAScript 5.1 (ECMA-262)
Function.prototype.bind の定義
標準 Initial definition. Implemented in JavaScript 1.8.5.
ECMAScript 2015 (6th Edition, ECMA-262)
Function.prototype.bind の定義
標準  
ECMAScript Latest Draft (ECMA-262)
Function.prototype.bind の定義
ドラフト  

ブラウザ互換性

機能ChromeEdgeFirefoxInternet ExplorerOperaSafari
基本対応7 あり4911.65.1
機能Android webviewChrome for AndroidEdge mobileFirefox for AndroidOpera AndroidiOS SafariSamsung Internet
基本対応41 あり411.56 あり

参照

ドキュメントのタグと貢献者

このページの貢献者: acro5piano, k08045kk, Uemmra3, lv7777, Marsf, cu39, S_F__
最終更新者: acro5piano,