8

言語デザインの観点からこれをお願いしています。だから私は見つけようとしています

  1. の振る舞いの理論的根拠は何thisですか?
  2. の振る舞いはどの程度this間違いでしたか、または改善することができましたか?

不安な理由を明確にするためにthis、次の例を検討してください。

var a = {};
a.f = function(){ return this; }
var f = a.f;
// f() != a.f()

所属するオブジェクトが簡単にf()失われることに注意してください。から分離すると、グローバルオブジェクトaになります(ブラウザの場合)。thiswindow

今考えてみましょう:

var newA = function(){
    var self = {};
    self.f = function(){ return self; }
    return self;
}

var a = newA();
var f = a.f;
// f() == a.f() !

まったく使用せthisずに、メソッドがどこでどのように使用されているかに関係なく、オブジェクトコンテキストを確立して維持することができます。クロージャーが提供する力で、this余計になり、おそらく少しでも危険になると思わずにはいられません...

私は、に反対thisしたり、議論を始めようとしているわけではありません。私は単にそれをよりよく理解しようとしているだけです。「これ」が役立つことはありがたいですが、それも混乱を招く可能性があることを認識してください...確かに初心者にとって、そしておそらく専門家にとっても、十分にあいまいな場合には混乱します。

それでも、言語の他のコアな側面が忌避のための公正なゲームであるように見える時代に、それは言語の頻繁に使用され、一見尊敬されている部分のままです(すなわち、Crockfordおよびwithまたはnew)。それでは何が欠けているのthisでしょうか。

4

7 に答える 7

11

これは、メソッドが属するオブジェクトを常に参照する特定のオブジェクト指向言語と同じように動作することを期待しているようです。

ただし、JavaScriptでは、関数を複数のオブジェクトにアタッチすることも、オブジェクトをまったくアタッチしないこともできます。あなたの例では、ある特定のオブジェクトのコンテキストで使用することを目的とした関数を作成しました...しかし、その関数を取得して他のオブジェクトにアタッチすることを妨げるものは何もありません。これは言語の性質です。関数はファーストクラスであり、オブジェクトのメンバーシップはオプションです。

したがって、これは関数が呼び出されるコンテキストを指します。現在、これは任意のオブジェクト(、、、またはで.指定)またはグローバルオブジェクトのいずれかです。言語の将来のバージョンでは、関数が定義されたコンテキストを参照します。グローバル関数の場合はグローバルオブジェクト、内部関数の場合は外部オブジェクト。実際には、これを使用してグローバルオブジェクトを参照できることは特に有用ではなかったため、これは設計上の欠陥の修正と見なすことができます。.apply.call()this

于 2009-02-12T16:11:55.960 に答える
8

「これ」をバインド解除したことは間違いではなかったと思います。最初は混乱することもありますが、それには十分な理由があります。最初に思い浮かぶのは、JavaScript はクラスベースの言語ではないため、関数は特定のクラスに関連付けられていないため、「これ」を正しいオブジェクト インスタンスに自動的にバインドする一貫した方法がないということです。例えば、

function Person(first, last, age) {
    this.firstName = first;
    this.lastName = last;
    this.age = age;
}

Person.prototype.getFullName = function() {
    return this.firstName + " " + this.lastName;
};

「this」は Person オブジェクトを参照する必要がありますが、Person.prototype.getName に割り当てられた関数には、それがどのように使用されるかを知る方法がないため、「this」は呼び出されたオブジェクトにバインドする必要があります。の上。

これが問題を引き起こすのは、ネストされた関数がある場合です。

// This is a really contrived example, but I can't think of anything better
Person.prototype.getInfo = function() {
    // get name as "Last, First"
    function getNameLastFirst() {
        // oops. "this" is the global object, *not* the Person
        return this.lastName + ", " + this.firstName;
    }

    // expect something like "Crumley, Matthew: Age 25",
    // but you get "undefined, undefined: Age 25"
    return getNameLastFirst() + ": Age " + this.age;
};

人工知能が提案した構文は便利ですが、適用を使用して「これ」を特定のオブジェクトにバインドするのは非常に簡単です。

function bind(func, obj) {
    return function() {
        return func.apply(obj, arguments);
    };
}

Person.prototype.getInfo = function() {
    // get name as "Last, First"
    var getNameLastFirst = bind(function () {
        return this.lastName + ", " + this.firstName;
    }, this);

    return getNameLastFirst() + ": Age " + this.age;
};

または、クロージャーを使用したより「伝統的な」方法:

Person.prototype.getInfo = function() {
    var self = this;

    // get name as "Last, First"
    function getNameLastFirst() {
        return self.lastName + ", " + self.firstName;
    }

    return getNameLastFirst() + ": Age " + this.age;
};
于 2009-02-12T15:50:47.600 に答える
3
  • そうではなかった
  • OOのものがたくさん
  • それはそれがそうであるように良いです
于 2009-02-12T13:21:26.430 に答える
3

バインドされていない「これ」は間違いだと思います。そうでなければ、それは非常に便利です。バインドされていない「this」は、ブラウザーのイベント処理で最も顕著に現れるコンテキストを誤解する可能性を開きます。また、JavaScript ライブラリには、イベント処理や多くのコールバック コンストラクト (マップ、フィルターなど) で "this" が何を参照するかについて、さまざまな意見があります。

バインドされていない「this」を削除しても、おそらくこれ以上困難になることはありません。

編集:別の構文例を使用すると、私のスタンスがより明確になると思います。

function Foo()
{
    //both this refer to the Foo instance
    this.blah=this.function(){this.bar;};

    //second this refers to baz
    this.blah=baz.function(){this.bar;};

    //second this refers to anonymous function itself
    this.blah=function(){this.bar;};
}
于 2009-02-12T13:47:58.630 に答える
1

JavaScript はプロトタイプベースの言語なので、バインドされていない 'this' キーワードが必要だと思います。詳しい人は、おそらくここに詳細を記入できます。

しかし、そうであるという事実は、非常に役に立たない. 特に、オブジェクトのメソッドを高階関数に渡したい場合は、面倒なことになります (MooTools の助けを借りて以下の例を参照してください):

myArray.each(myObject.foo);

myObject.foo の「this」が myObject ではなく myArray を参照するため、機能しません。その代わり:

myArray.each(myObject.foo.bind(myObject))

これは私には非常に醜いようです。そのため、私は通常、JavaScript でオブジェクト指向の方法でプログラミングすることはせず、代わりにクロージャーに大きく依存しています。

于 2009-02-12T16:07:15.643 に答える
1
  • 代わりに「self」と呼ぶ必要があります
  • 現在のオブジェクトの状態を参照するもの。
  • 「this」の名前として「self」を選択し、それを明示的に (最初の引数として) すべてのメソッドに渡します。このようにして、インスタンスメソッドを静的メソッドまたは関数から簡単に区別できます。

申し訳ありませんが、私はPythonが本当に好きです;-)

于 2009-02-12T13:35:21.763 に答える
1

イディオムa.f()を次の略記と考えてください。

a.f.call(a);

fこれは定義上、スコープを使用した関数の呼び出しaです。

var f = a.f;
f(); // f.call(this);
a.f(); // f.call(a);

thisaが同じオブジェクトではない場合、f()a.f()は異なるスコープを使用するため、動作が異なる場合があります。他の言語での静的メソッドとクラス メソッドの違いを考慮してください。

class Foo {
public:
    static void a(Foo *scope) {
        // do something with given scope
    };

    void b() {
        a(this); // do something with the scope of this object
    };
};

Foo foo;
Foo bar;

foo.a(&bar) != foo.b(); // just like f() != a.f()
foo.a(&foo) == foo.b(); // just like f.call(a) == a.f()
于 2009-02-12T16:08:24.550 に答える