web-dev-qa-db-ja.com

'var that = this;'とは何ですか。 JavaScriptで意味ですか?

私が見たJavaScriptファイルでは:

function Somefunction(){
   var that = this; 
   ... 
}

thatを宣言し、それをthisに割り当てる目的は何ですか?

338
Chris

私はこの答えをイラストで始めます。

var colours = ['red', 'green', 'blue'];
document.getElementById('element').addEventListener('click', function() {
    // this is a reference to the element clicked on

    var that = this;

    colours.forEach(function() {
        // this is undefined
        // that is a reference to the element clicked on
    });
});

私の答えはもともとjQueryを使ってこれを実証しました。

$('#element').click(function(){
    // this is a reference to the element clicked on

    var that = this;

    $('.elements').each(function(){
        // this is a reference to the current element in the loop
        // that is still a reference to the element clicked on
    });
});

新しい関数を呼び出してスコープを変更すると、thisが頻繁に変更されるため、それを使用して元の値にアクセスすることはできません。 thatにエイリアスしても、元のthisの値にアクセスできます。

個人的には、エイリアスとしてthatを使用するのは嫌いです。それが何を参照しているのかはめったに明らかではありません、特に関数が数行より長い場合は。 I 常により説明的なエイリアスを使用します。上記の例では、おそらくclickedElを使用します。

471
lonesomeday

から Crockford

慣例により、プライベートthat変数を作成します。これは、オブジェクトをプライベートメソッドが利用できるようにするために使用されます。これはECMAScript言語仕様のエラーに対する回避策であり、これはthisが内部関数に対して正しく設定されないようにします。

JSフィドル

function usesThis(name) {
    this.myName = name;

    function returnMe() {
        return this;        //scope is lost because of the inner function
    }

    return {
        returnMe : returnMe
    }
}

function usesThat(name) {
    var that = this;
    this.myName = name;

    function returnMe() {
        return that;            //scope is baked in with 'that' to the "class"
    }

    return {
        returnMe : returnMe
    }
}

var usesthat = new usesThat('Dave');
var usesthis = new usesThis('John');
alert("UsesThat thinks it's called " + usesthat.returnMe().myName + '\r\n' +
      "UsesThis thinks it's called " + usesthis.returnMe().myName);

このアラート...

用途Daveと呼ばれるもの

用途これは未定義と呼ばれます

103
El Ronnoco

これは、内部関数(他の関数の内部で定義された関数)が本来の動作をより良くするためのハックです。 JavaScriptでは、ある関数を別の関数内で定義すると、thisは自動的にグローバルスコープに設定されます。あなたはthisが外側の関数と同じ値を持つことを期待しているので、これは混乱するかもしれません。

var car = {};
car.starter = {};

car.start = function(){
    var that = this;

    // you can access car.starter inside this method with 'this'
    this.starter.active = false;

    var activateStarter = function(){
        // 'this' now points to the global scope
        // 'this.starter' is undefined, so we use 'that' instead.
        that.starter.active = true;

        // you could also use car.starter, but using 'that' gives
        // us more consistency and flexibility
    };

    activateStarter();

};

これは特に、オブジェクトのメソッドとして関数を作成し(例のcar.startのように)、そのメソッド内に(activateStarterのように)関数を作成する場合に特に問題になります。トップレベルのメソッドではthisはオブジェクトを指していますが(この場合はcar)、内部関数ではthisがグローバルスコープを指しています。これは痛みです。

両方のスコープで慣例として使用する変数を作成することは、javascriptに関するこの非常に一般的な問題に対する解決策です(ただし、jquery関数でも役立ちます)。これが、非常に一般的な発音名thatが使用される理由です。それは言語の欠点を克服するための簡単に認識できる慣例です。

El Ronnocoが Douglas Crockford に示唆するように、これは良い考えであると考えています。

82
Waylon Flinn

call()またはapply()を使用して回避策を作成する場合は、thatを使用する必要はありません。

var car = {};
car.starter = {};

car.start = function(){
    this.starter.active = false;

    var activateStarter = function(){
        // 'this' now points to our main object
        this.starter.active = true;
    };

    activateStarter.apply(this);
};
8
Adela

thisが別のスコープを参照して別のスコープを参照することがある場合があります。たとえば、DOMイベント内でコンストラクタメソッドを呼び出す場合、thisは作成されたオブジェクトではなくDOM要素を参照します。

HTML

<button id="button">Alert Name</button>

JS

var Person = function(name) {
  this.name = name;
  var that = this;
  this.sayHi = function() {
    alert(that.name);
  };
};

var ahmad = new Person('Ahmad');
var element = document.getElementById('button');
element.addEventListener('click', ahmad.sayHi); // => Ahmad

デモ

上記の解決法はthisthatに代入し、sayHiからthatメソッド内のnameプロパティにアクセスできるので、DOM呼び出し内で問題なく呼び出すことができます。

別の解決策は、空のthatオブジェクトを割り当て、それにプロパティとメソッドを追加してそれを返すことです。しかし、この解決策ではコンストラクタのprototypeを失いました。

var Person = function(name) {
  var that = {};
  that.name = name;
  that.sayHi = function() {
    alert(that.name);
  };
  return that;
};
3
Ahmad Ajmi

これが例です `

$(document).ready(function() {
        var lastItem = null;
        $(".our-work-group > p > a").click(function(e) {
            e.preventDefault();

            var item = $(this).html(); //Here value of "this" is ".our-work-group > p > a"
            if (item == lastItem) {
                lastItem = null;
                $('.our-work-single-page').show();
            } else {
                lastItem = item;
                $('.our-work-single-page').each(function() {
                    var imgAlt = $(this).find('img').attr('alt'); //Here value of "this" is '.our-work-single-page'. 
                    if (imgAlt != item) {
                        $(this).hide();
                    } else {
                        $(this).show();
                    }
                });
            }

        });
    });`

そのため、この値は、ターゲットとするDOM要素に応じて2つの異なる値になりますが、上記のコードに "that"を追加すると、ターゲットとなる "this"の値が変更されます。

`$(document).ready(function() {
        var lastItem = null;
        $(".our-work-group > p > a").click(function(e) {
            e.preventDefault();
            var item = $(this).html(); //Here value of "this" is ".our-work-group > p > a"
            if (item == lastItem) {
                lastItem = null;
                var that = this;
                $('.our-work-single-page').show();
            } else {
                lastItem = item;
                $('.our-work-single-page').each(function() {
                   ***$(that).css("background-color", "#ffe700");*** //Here value of "that" is ".our-work-group > p > a"....
                    var imgAlt = $(this).find('img').attr('alt'); 
                    if (imgAlt != item) {
                        $(this).hide();
                    } else {
                        $(this).show();
                    }
                });
            }

        });
    });`

.....$(that).css( "background-color"、 "#ffe700"); /ここで "that"の値は ".our-work-group> p> a"です。varの値がthat = thisであるためです。そのため、「this」= '.our-work-single-page'になっていても、以前のDOM要素を操作するために「that」を使用できます。

2
rshah