このJavaScriptイディオムの根底にあるものは何ですか?var self = this?


357

WebKit HTML 5 SQL Storage Notes Demoのソースで以下を確認しました。

function Note() {
  var self = this;

  var note = document.createElement('div');
  note.className = 'note';
  note.addEventListener('mousedown', function(e) { return self.onMouseDown(e) }, false);
  note.addEventListener('click', function() { return self.onNoteClick() }, false);
  this.note = note;
  // ...
}

著者は自分自身をいくつかの場所(関数本体)で使用し、これを他の場所(メソッドの引数リストで定義された関数の本体)で使用します。どうしたの?一度気づいた今、どこでも見始めますか?


4
これは呼ばれるJS言語機能である「字句クロージャ。」
零下

2
重複の可能性:var self = this?
DavidRR 2015年

これの概念は、ここで明示的に説明されています scotch.io/@alZami/understanding-this-in-javascript
AL-

この回答の関連する例stackoverflow.com/a/20279485/5610569(「thisコールバック内で正しいものにアクセスする方法は?」という質問に対して)
FluxLemur

回答:


431

alistapart.comでこの記事を参照してください。(編集:記事は最初にリンクされてから更新されています)

selfthisコンテキストが変化しても、オリジナルへの参照を維持するために使用されています。これは、イベントハンドラー(特にクロージャー)でよく使用される手法です。

編集:self現在のところ使用は推奨されwindow.selfておらず、注意しないとエラーが発生する可能性があることに注意してください。

変数を何と呼ぶか​​は特に重要ではありません。var that = this;大丈夫ですが、名前に魔法はありません。

コンテキスト内で宣言された関数(コールバック、クロージャーなど)は、同じスコープまたはそれ以上で宣言された変数/関数にアクセスできます。

たとえば、単純なイベントコールバック:

function MyConstructor(options) {
  let that = this;

  this.someprop = options.someprop || 'defaultprop';

  document.addEventListener('click', (event) => {
    alert(that.someprop);
  });
}

new MyConstructor({
  someprop: "Hello World"
});


表示された記事があること使って変身var that = this;
ボブ・スタインを

@BobSteinありがとう。それに応じて答えを更新します。
ジョナサン・フィンランド

96

最近のブラウザーは、通常のウィンドウまたはWebWorkerのいずれかのグローバルオブジェクトを指すグローバル変数をself提供しているため、変数名 'self'はこの方法でもう使用しないでください。

混乱や潜在的な競合を回避するために、var thiz = thisまたはを書くことができますvar that = this


43
私が通常使用する_this
djheru

6
@djheru +1。" that"(私の脳は慣れません)よりもずっと良いです。
o_o_o-- 2014

9
私は "私"を使い始めました:)
Mopparthy Ravindranath

3
最近のブラウザがグローバル変数_this、that、またはmeを提供し始めるまで。
Beejor 2015

10
名前selfvariable として宣言する限り、名前を使用してもまったく問題はなく、グローバルをシャドウします。もちろん、忘れた場合は、var他の名前でも機能しません。
ベルギ

34

はい、どこでも見られます。それはしばしばthat = this;です。

selfイベントによって呼び出される関数内でどのように使用されるか確認してください。それらは独自のコンテキストを持っているのでselfthisに入ってきたを保持するために使用されNote()ます。

その理由は、self後に、彼らは唯一の実行可能にもかかわらず、まだ機能が利用可能であるNote()、関数が実行を終了した内部関数が原因に外側の関数のコンテキストを取得することで閉鎖


12
私にとっては、それselfは特別な意味を持たないというのが正しい点です。私は個人的selfには、自分自身を予約語にすると思っているので、混乱することが多いため、別の名前のvarを使用することを好みます。だから私はあなたの答えが好きです。そしてOPの例では、私はvar thisNote = this同じか似ています。
2014年

@steveは同意しましたが、保守性の点で非常に脆弱であるため、これ/自己参照を一般的に使用しないようにします。
mattLummus 2015年

28

またthisvar self = thisイディオムが嫌いな場合は、コールバックでオリジナルへの参照を維持するための代替のプロキシパターンがあることに注意してください。

またはを使用して特定のコンテキストで関数を呼び出すことができるため、特定のコンテキストで、function.applyまたは特定のコンテキストを使用しfunction.callて関数を呼び出す関数を返すラッパーを作成できます。このパターンの実装については、jQueryの関数を参照してください。使用例は次のとおりです。applycallproxy

var wrappedFunc = $.proxy(this.myFunc, this);

wrappedFunc次に呼び出すことができ、あなたのバージョンをthisコンテキストとして持ちます。


10

他の人が説明したvar self = this;ように、クロージャー内のコードが親スコープを参照できるようにします。

ただし、現在は2018年であり、ES6はすべての主要なWebブラウザーで広くサポートされています。このvar self = this;イディオムは、以前ほど重要ではありません。

アロー関数をvar self = this;使用することで回避できるようになりました。

私たちが使用したはずのインスタンスではvar self = this

function test() {
    var self = this;
    this.hello = "world";
    document.getElementById("test_btn").addEventListener("click", function() {
        console.log(self.hello); // logs "world"
    });
};

これで、次のことなくアロー関数を使用できますvar self = this

function test() {
    this.hello = "world";
    document.getElementById("test_btn").addEventListener("click", () => {
        console.log(this.hello); // logs "world"
    });
};

矢印関数には独自の関数はなくthis、単に囲みスコープを想定しています。


または–衝撃、恐怖!–実際の関連事項を関数(クロージャ)の引数として渡さないのはなぜですか?なぜ地獄は範囲外の状態を参照しているのですか、なぜ地獄はこのようなプログラミングをしているのですか?これを行う本当の理由は決してありません。代わりに.addEventListender("click", (x) => { console.log(x); });、方法と理由を非常に明確に説明しましたが、矢印関数を使用する方が理にかなっていることに同意しますが、それでも...これはひどく、面倒で、面倒で、プログラミングです。
ベンジャミンR

2
JavaScriptでは、親スコープに戻ることは非常に一般的であり、必要です。それは言語の基本的な部分です。イベントハンドラーの引数として親スコープを渡すという提案は、実際には不可能です。また、ES6では、矢印関数は字句スコープを使用します。「this」は、現在の周囲のスコープを指し、それ以上のことを指します。「スコープ外の状態の参照」などではありません。
エリオット

9

変数は、メソッドで定義されたインライン関数によってキャプチャされます。this関数内で別のオブジェクトを参照します。このようにして、関数thisに外部スコープのへの参照を保持させることができます。


9

それはJavaScriptの癖です。関数がオブジェクトのプロパティ、より適切にはメソッドと呼ばれる場合、これはオブジェクトを指します。イベントハンドラーの例では、含まれているオブジェクトはイベントをトリガーした要素です。標準関数が呼び出されると、これはグローバルオブジェクトを参照します。例のように関数をネストしている場合、これは外部関数のコンテキストとはまったく関係がありません。内部関数は包含関数とスコープを共有するので、開発者は内部関数で必要なthisvar that = thisを保持するためにのバリエーションを使用します。


5

実際には、自分自身がウィンドウ(window.selfvar self = 'something'への参照であるため、自分自身へのウィンドウ参照をオーバーライドすると、自分はウィンドウオブジェクトに存在します。

ほとんどの開発者が好むのはこのためですvar that = this以上var self = this;

とにかく; var that = this;あなたのコードが他の開発者によって後で修正/変更されると仮定すると、あなたは開発者コミュニティに関して最も一般的なプログラミング標準を使用するべきです

したがって、スコープ内で明確にするために、var oldThis/ var oThis/などのようなものを使用する必要があります。


2
@prior最後の段落まで意味があると思います。
miphe

0

上記で何度か言及したように、「自己」は、関数に入る前に「これ」への参照を保持するために単に使用されています。関数に入ると、「this」は別のものを指します。


@JohnPaul ...これ答えを提供します。正解ではないかもしれませんが、「なぜ慣れているのか」は「なぜ彼はこれをしたのか」という答えではありません。
GreenAsJade、2015年

-1
function Person(firstname, lastname) {
  this.firstname = firstname;

  this.lastname = lastname;
  this.getfullname = function () {
    return `${this.firstname}   ${this.lastname}`;
  };

  let that = this;
  this.sayHi = function() {
    console.log(`i am this , ${this.firstname}`);
    console.log(`i am that , ${that.firstname}`);
  };
}

let thisss = new Person('thatbetty', 'thatzhao');

let thatt = {firstname: 'thisbetty', lastname: 'thiszhao'};

thisss.sayHi.call(thatt);


1
あなたはあなたが特別にしたことをコードでいくつか説明を追加する必要があります。
Farhana
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.