3

私の質問は簡単です: 私は関数を他の関数に渡して後で呼び出すようにしています (コールバック関数のサンプル)。

サンプル: xxx()関数があり、window.onload イベントで以下に示すように、これを渡す必要があります。

ベストプラクティスとその理由は何ですか? パフォーマンスの側面があります。または、この関数を呼び出すために call または bind を使用する必要があるのはなぜですか

function xxx(text)
{
    var div = document.createElement("div");
    div.innerHTML = text + " - this: " + this.toString();

    document.body.appendChild(div)
}

function callFunction(func)
{
    func("callFunction");
}

function callUsingCall(func)
{
    func.call(this, ["callUsingCall"]);
}

function callUsingBind(func)
{
    func.call(this, ["callUsingCall"]);
}


window.onload = function(){
    callFunction(xxx);

    callUsingCall(xxx);

    callUsingBind(xxx.bind(document));
}

ありがとうございました、

セバスチャン P.

4

2 に答える 2

4

thisオブジェクトは関数のコンテキストです。それはあなたがあなたのために何かを作る機械を作るようなものであり、thisオブジェクトはあなたの家のように機械が働く場所になるでしょう。好きなように動かすことができます。

オブジェクトを設定する方法は4つありthisます。

メソッドではない関数の呼び出し:

fn(someArguments)

このようにして、thisオブジェクトはnullまたはおそらくウィンドウオブジェクトに設定されます。

関数をメソッドとして呼び出す:

someObject.fn(someArguments)

この場合、thisオブジェクトはポイントしsomeObject、変更可能です。

call関数のまたはapplyメソッドを呼び出します。

fn.call(anotherObject, someArguments)
someObject.call(anotherObject, someArguments)
someObject.apply(anotherObject, [someArguments])

この場合、thisオブジェクトはここを指しsomeObjectます。それを呼び出すとき、あなたはそれを別のコンテキストを持つように強制しています。

関数のバインド

var fn2 = fn.bind(anotherObject, someArguments)

thisこれにより、指定したオブジェクトにバインドされる別の関数が作成されます( anotherObject)。どのように呼んでも、thisオブジェクトは同じになります。

ユースケース

今、あなたはこれを知っているいくつかのトリッキーなことをすることができます。ここにある理由(最初はC ++から来たと思います)は、オブジェクトのメソッドがその親にアクセスする必要があるためです。thisオブジェクトがアクセスを提供します。

var coolObject = {
  points : ['People are amazing'],
  addPoint : function (p) { this.points.push(p) }
}

したがって、次のことを行うと機能しません。

var addPoint = coolObject.addPoint;
addPoint('This will result in an error');

このオブジェクトはcoolObjectもう私たちのものではなく、pointsプロパティを持っていないため、エラーがスローされます。したがって、このような場合は、次のようにすることができます。

var addPoint = coolObject.addPoint;
addPoint.call({points : []}, 'This is pointless');

これは無意味ですが、関数は機能thisします。オブジェクトでさえ、本来あるべきものではありません。

var anotherCoolObject = {
  points : ['Im a thief!'],
  addPoint : coolObject.addPoint
}
anotherCoolObject.addPoint('THIS IS CALL STEALING');

それでも、このように呼び出すと、関数は機能します。これは、thisオブジェクトがプロパティを持つanotherCoolObjectを指すためですpoints

私が見た中で最も一般的なユースケースは、argumentsオブジェクトをスライスすることです。

function returnHalf() {
  return [].slice.call(arguments, 0, arguments.length / 2);
}

returnHalf('Half', 'is', 'not', 'awesome');
// >> [Half', 'is']

ご覧のとおり、argumentsオブジェクトはinstanceof配列ではありません。そうするとarguments.slice(...)、コンパイラに殺されてしまいます。ただし、ここでは、配列のようなものであるため、argumentsオブジェクトで配列のメソッドを使用します。

関数コンテキストを変更したくない場合や、独自の引数を追加したい場合は、bindを使用します。

たとえば、jqueryを使用してイベントのリスナーを追加する場合、jqueryが関数を呼び出すと、thisオブジェクトが要素になります。しかし、時々あなたはトリッキーなことをしてそれを変更したいです:

var myElement = {
  init : function () {
    $(this.element).click(this.listener.bind(this));
  },
  view : "<li>${Name}</li>",
  name : 'ed',
  element : $('#myelement'),
  listener : function () {
    this.element.append($.tmpl( this.view, this ));
  }
}

myElement.init();

したがって、ここでは、それをmyElementにバインドして、オブジェクトのプロパティにアクセスしてビューをレンダリングできるようにします。別の例は次のとおりです。

for (var i = 0; i < 10; i++) {
  setTimeout(function () {console.log(i)}, 10)
}

// All of them will be 10.

for (var i = 0; i < 10; i++) {
  setTimeout((function () {console.log(this.i)}).bind({ i : i }, 10)
}

非同期関数呼び出しをループに入れた場合、コールバックが呼び出され、ループが終了し、カウンターが終了するまでに、bindを使用して、現在のカウンターをコールバックにクリーンにバインドできます。

async私がよく使用するもう1つの良いユースケースは、クロージャを作成せずに、引数を使用して関数をモジュールに渡す場合です。

async.parallel({
  writeFile : function (cb) {
    fs.writeFile('lolz.txt', someData, cb);
  }, 
  writeFile2 : function (cb) {
    fs.writeFile('lolz2.txt', someData, cb);
  }
}, function (err){ 
    console.log('finished')
});

async.parallel({
  writeFile : fs.writeFile.bind(fs, 'lolz.txt', someData),
  writeFile2 : fs.writeFile.bind(fs, 'lol2z.txt', someData),
}, function (err){ 
    console.log('finished')
});

これらの2つの実装は同じです。

パフォーマンス

これらをチェックしてください:

http://jsperf.com/bind-vs-call2

http://jsperf.com/js-bind-vs-closure/2

http://jsperf.com/call-vs-closure-to-pass-scope/10

bind他のタイプの呼び出しと比較してパフォーマンスのオーバーヘッドが大きくなりますが、時期尚早の最適化による保守性でパフォーマンスを犠牲にしないようにしてください。

また、この記事を見ることができます。

于 2012-07-17T13:18:44.757 に答える
4

「ベスト」プラクティスはないと思います。

call呼び出している関数が何であるかを気にする場合に使用しますthis

の指定された値でのみbind関数を呼び出すことができるようにする場合に使用します。this

[両方に多少のオーバーヘッドがあります。つまり、関数呼び出し/スコープの少なくとも 1 つの深さ]

それ以外の場合は、関数を呼び出すだけです。

シンプル:)

于 2012-07-17T13:02:00.073 に答える