5

thisJavaScriptのオブジェクトについてはある程度理解できたと思います。オブジェクト、コールバック、およびイベントとハンドラーの両方を扱う場合、太古の昔から問題はありませんでした。しかし、今ではすべてが変わりました。

私は JavaScript に夢中になりました。純粋な JS です。つまり、jQuery、prototype.js、dojo ではありません。当然のことながら、私はクロージャーを使用するようになりました。ただし、場合によっては、thisここで不意を突かれることがあります。このスニペットを 1 つ取ります。

function anyFunc(par)
{
    //console.log(par);
    console.log(this);
}

function makeClosure(func)
{
    return function(par)
    {
        return func(par);
    }
}
var close = makeClosure(anyFunc);
close('Foo');

var objWithClosure = {cls:makeClosure(anyFunc),prop:'foobar'};
objWithClosure.cls(objWithClosure.prop);

var scndObj = {prop:'Foobar2'};
scndObj.cls = makeClosure;
scndObj.cls = scndObj.cls(anyFunc);
scndObj.cls(scndObj.prop);

3 つのケースすべてthisで、window オブジェクトとしてログに記録します。もちろん、簡単に修正できます。

function makeClosure(func)
{
    return function(par)
    {
        return func.call(this,par);
    }
}

この修正は機能します。私が知る必要があることを説明せずに、人々がこれに答えるのを避けるためにここに置きます:なぜこれはここでのように振る舞うのですか?

呼び出し元が実質的にクロージャーが属するオブジェクトであることを保証します。私が理解できないのはこれです: 案の定this、最初のケースでは window オブジェクトを指しますが、他のケースではそうすべきではありません。this戻る直前に makeClosure 関数にログインしようとしましたが、オブジェクトではなく、オブジェクト自体がログに記録されましたwindow。しかし、実際のクロージャが使用されるthisと、window オブジェクトへのポイントに戻ります。なんで?

私が考えることができる唯一のことは、anyFunc関数を引数として渡すことによって、実際に を渡しているということですwindow.anyFunc。だから私はこの簡単な修正を試みました:

function makeClosure(func)
{
    var theFunc = func;
    return function(par)
    {
        theFunc(par);
    }
}

期待どおりの結果でthis、オブジェクトを指すようになりましたが、やはり: なぜでしょうか? いくつかのアイデアがあります (theFuncローカル スコープの関数への参照です [ this > private: theFunc]?) が、ここには JS に関してもっと多くのノウハウを持っている人がいると確信しているので、いくつか取得したいと考えていました。より多くの説明またはそれらから読む価値のある記事へのリンク...

ありがとう

アップデート

ここにフィドルがあります。何かを省略した可能性がありますが、ここではあらゆる種類のものをログに記録します;)

編集/更新 2

私を混乱させるケースはここにあります。

最終編集

わかりました、これはかなり厄介な投稿になっています。明確にするために:私が期待していたのは、これに似た動作でした:

function makeClosure()
{
    function fromThisFunc()
    {
        console.log(this);
    }
    return fromThisFunc;
}

var windowContext = makeClosure();
windowContext();
var objectContext = {cls:makeClosure()};
objectContext.cls();

私を捕まえたのは、関数anyFuncが正しいスコープ内で宣言されていなかったためthis、ウィンドウ オブジェクトを指していたことです。これは、ウェブ上のどこかで見つけた古代の巻物を読んでわかりました。

しかし、globalVar によって参照されるようになった関数オブジェクトは、それが作成された実行コンテキストに属する Activation/Variable オブジェクトを含むスコープ チェーンを参照する [[scope]] プロパティで作成されたため、もう少し複雑なことが起こりました (そしてグローバル オブジェクト)。globalVar によって参照される関数オブジェクトの実行では、その [[scope]] プロパティからのスコープ チェーン全体を、呼び出しごとに作成された実行コンテキストのスコープに追加する必要があるため、Activation/Variable オブジェクトをガベージ コレクションすることはできません。それ。

だから私がする必要があったのは、物事を複雑にするのではなく単純化することでした:

function fromThisFunc()
{
    console.log(this);
}

function makeClosure(funcRef)
{
    //some code here
    return funcRef;
}

それはうまくいくはずですよね?

PS: Alnitak の回答は除外しますが、Felix Kling の忍耐と情報に特に感謝します。

4

2 に答える 2

4

電話するとすぐに:

return func(par);

新しいスコープを (独自の でthis) 作成しています。この場合は、オブジェクトを指定していないため、this === window通常は厳密モードで未定義です。呼び出された関数は、呼び出しスコープにあったものを継承しません。this

この値を設定する方法は次のとおりです。

myobj.func(par);  // this === myobj

また

func.call(myobj, ...)  // this === myobj

もあります:

于 2012-05-09T08:07:02.740 に答える
1

の値はthis、関数をメソッドとして呼び出すか、関数として呼び出すかによってのみ異なります。

メソッドとして呼び出すとthis、メソッドが属するオブジェクトになります。

obj.myFunction();

関数として呼び出すと、次のオブジェクトthisになります。window

myFunction();

オブジェクトに属するメソッドにいる場合でも、メソッド構文を使用してオブジェクト内の他のメソッドを呼び出す必要があることに注意してください。そうしないと、関数として呼び出されます。

this.myOtherFunction();

メソッド参照を変数に入れると、オブジェクトから切り離され、関数として呼び出されます。

var f = obj.myFunction;
f();

およびメソッドは、関数がオブジェクト内のメソッドでなくても (または別のオブジェクト内のメソッドである場合でも)、関数をメソッドとして呼び出すために使用されますcallapply

myFunction.call(obj);
于 2012-05-09T08:19:59.120 に答える