web-dev-qa-db-ja.com

"this"キーワードはどのように機能しますか?

私は、thisキーワードが何であるか、そしてStack OverflowサイトのJavaScriptでそれがどのように正しく(そして間違って)使用されているかの明確な説明がないように思われることに気づきました。

私はそれでいくつかの非常に奇妙なふるまいを目撃しました、そして、なぜそれが起こったのか理解できませんでした。

thisはどのように機能し、いつ使うべきですか?

1189

最初に Mike West の記事 JavaScriptのスコープmirror )を読むことをお勧めします。これは、JavaScriptのthisおよびスコープチェーンの概念の優れたわかりやすい紹介です。

thisに慣れ始めたら、ルールは実際には非常に簡単です。 ECMAScript 5.1 Standardthisを定義します:

§11.1.1thisキーワード

thisキーワードは、現在の実行コンテキストのThisBindingの値に評価されます

ThisBindingは、オブジェクトへの参照を保持する特別なCPUレジスタのように、JavaScriptインタープリターがJavaScriptコードを評価するときに保持するものです。インタプリタは、次の3つの異なるケースのいずれかで実行コンテキストを確立するたびにThisBindingを更新します。

1.初期グローバル実行コンテキスト

これは、トップレベルで評価されるJavaScriptコードの場合です。 <script>内に直接ある場合:

<script>
  alert("I'm evaluated in the initial global execution context!");

  setTimeout(function () {
      alert("I'm NOT evaluated in the initial global execution context.");
  }, 1);
</script>

初期グローバル実行コンテキストでコードを評価する場合、ThisBindingはグローバルオブジェクトwindow§10.4.1.1 )に設定されます。

評価コードの入力

  • eval()への直接呼び出しによるThisBindingは変更されません。呼び出し実行コンテキストのThisBindingと同じ値です( §10.4.2 (2)(a))。

  • eval()を直接呼び出していない場合
    ThisBindingはグローバルオブジェクトに設定されますas if初期のグローバル実行コンテキストで実行中( §10.4.2 (1))。

§15.1.2.1.1は、eval()の直接呼び出しが何であるかを定義します。基本的に、eval(...)は直接呼び出しですが、(0, eval)(...)var indirectEval = eval; indirectEval(...);などはeval()の間接呼び出しです。 JavaScriptで chuckjの答え to (1、eval)( 'this')vs eval( 'this')を参照してください。 および Dmitry SoshnikovのECMA-262-5の詳細。第2章厳密モード。 間接的なeval()呼び出しを使用する場合。

機能コードの入力

これは、関数を呼び出すときに発生します。 obj.myMethod()または同等のobj["myMethod"]()などのオブジェクトで関数が呼び出された場合、ThisBindingはオブジェクトに設定されます(例ではobj; §13.2.1 )。他のほとんどの場合、ThisBindingはグローバルオブジェクトに設定されます( §10.4.3 )。

「他のほとんどの場合」と書く理由は、引数リストでThisBindingを指定できるECMAScript 5組み込み関数が8つあるためです。これらの特殊関数は、いわゆるthisArgを取ります。これは、関数を呼び出すときにThisBindingになります( §10.4.3 )。

これらの特別な組み込み関数は次のとおりです。

  • Function.prototype.apply( thisArg, argArray )
  • Function.prototype.call( thisArg [ , arg1 [ , arg2, ... ] ] )
  • Function.prototype.bind( thisArg [ , arg1 [ , arg2, ... ] ] )
  • Array.prototype.every( callbackfn [ , thisArg ] )
  • Array.prototype.some( callbackfn [ , thisArg ] )
  • Array.prototype.forEach( callbackfn [ , thisArg ] )
  • Array.prototype.map( callbackfn [ , thisArg ] )
  • Array.prototype.filter( callbackfn [ , thisArg ] )

Function.prototype関数の場合、関数オブジェクトで呼び出されますが、ThisBindingを関数オブジェクトに設定するのではなく、ThisBindingをthisArgに設定します。

Array.prototype関数の場合、指定されたcallbackfnは、ThisBindingがthisArgに設定されている場合に設定される実行コンテキストで呼び出されます。それ以外の場合は、グローバルオブジェクトに。

これらはプレーンJavaScriptのルールです。 JavaScriptライブラリ(jQueryなど)の使用を開始すると、特定のライブラリ関数がthisの値を操作することがあります。 JavaScriptライブラリの開発者は、最も一般的なユースケースをサポートする傾向があるため、これを行います。通常、ライブラリのユーザーは、この動作がより便利であると感じています。 thisを参照するコールバック関数をライブラリ関数に渡す場合、関数が呼び出されたときにthisの値が何であるかについての保証については、ドキュメントを参照する必要があります。

JavaScriptライブラリがthisの値をどのように操作するのか疑問に思っている場合、ライブラリはthisArgを受け入れる組み込みJavaScript関数の1つを単に使用しています。あなたも、コールバック関数とthisArgを使用して独自の関数を作成できます。

function doWork(callbackfn, thisArg) {
    //...
    if (callbackfn != null) callbackfn.call(thisArg);
}

まだ言及していない特別なケースがあります。 new演算子を使用して新しいオブジェクトを作成する場合、JavaScriptインタープリターは新しい空のオブジェクトを作成し、いくつかの内部プロパティを設定してから、新しいオブジェクトでコンストラクター関数を呼び出します。したがって、コンストラクターコンテキストで関数が呼び出されると、thisの値はインタープリターが作成した新しいオブジェクトになります。

function MyType() {
    this.someData = "a string";
}

var instance = new MyType();
// Kind of like the following, but there are more steps involved:
// var instance = {};
// MyType.call(instance);

矢印関数

矢印関数 (ECMA6で導入)thisのスコープを変更します。既存の標準的な質問、 矢印関数と関数宣言/式を参照してください:それらは同等/交換可能ですか? 詳細については。しかし、要するに:

矢印関数には、独自のthis....バインディングがありません。代わりに、これらの識別子は他の変数と同様に字句スコープで解決されます。つまり、矢印関数内では、this......矢印関数が定義されている環境のthisの値を参照します。

楽しみのために、いくつかの例を使って理解度をテストしてください

回答を表示するには、明るい黄色のボックスの上にマウスを置きます。

  1. マークされた行のthisの値は何ですか?どうして?

    window —マークされた行は、初期グローバル実行コンテキストで評価されます。

    if (true) {
        // What is `this` here?
    }
    
  2. obj.staticFunction()が実行されるとき、マークされた行のthisの値は何ですか?どうして?

    obj —オブジェクトの関数を呼び出すと、ThisBindingがオブジェクトに設定されます。

    var obj = {
        someData: "a string"
    };
    
    function myFun() {
        return this // What is `this` here?
    }
    
    obj.staticFunction = myFun;
    
    console.log("this is window:", obj.staticFunction() == window);
    console.log("this is obj:", obj.staticFunction() == obj);
      
  3. マークされた行のthisの値は何ですか?どうして?

    window

    この例では、JavaScriptインタープリターが関数コードを入力しますが、myFun/obj.myMethodがオブジェクトで呼び出されないため、ThisBindingはwindowに設定されます。

    これは、メソッド(obj.myMethod)にアクセスすると バインドメソッドオブジェクト が作成されるPythonとは異なります。

    var obj = {
        myMethod: function () {
            return this; // What is `this` here?
        }
    };
    var myFun = obj.myMethod;
    console.log("this is window:", myFun() == window);
    console.log("this is obj:", myFun() == obj);
      
  4. マークされた行のthisの値は何ですか?どうして?

    window

    これはトリッキーでした。評価コードを評価するとき、thisobjです。ただし、評価コードでは、オブジェクトでmyFunが呼び出されないため、呼び出しに対してThisBindingがwindowに設定されます。

    function myFun() {
        return this; // What is `this` here?
    }
    var obj = {
        myMethod: function () {
            eval("myFun()");
        }
    };
    
  5. マークされた行のthisの値は何ですか?どうして?

    obj

    myFun.call(obj);は、thisArgを最初の引数として受け入れる特別な組み込み関数Function.prototype.call()を呼び出しています。

    function myFun() {
        return this; // What is `this` here?
    }
    var obj = {
        someData: "a string"
    };
    console.log("this is window:", myFun.call(obj) == window);
    console.log("this is obj:", myFun.call(obj) == obj);
      
1287
Daniel Trebbien

thisキーワードは、JavaScriptでは他の言語とは動作が異なります。オブジェクト指向言語では、thisキーワードはクラスの現在のインスタンスを参照します。 JavaScriptでは、thisの値は主にfunction(context.function())の呼び出しコンテキストとそれが呼び出される場所によって決定されます。

1.グローバルな場合

thisをグローバルコンテキストで使用すると、グローバルオブジェクトにバインドされます(ブラウザのwindow

document.write(this);  //[object Window]

グローバルコンテキストで定義された関数内でthisを使用すると、その関数は実際にはグローバルコンテキストのメソッドになるため、thisは依然としてグローバルオブジェクトにバインドされます。

function f1()
{
   return this;
}
document.write(f1());  //[object Window]

上記のf1はグローバルオブジェクトのメソッドになります。したがって、windowオブジェクトで次のように呼び出すこともできます。

function f()
{
    return this;
}

document.write(window.f()); //[object Window]

2.オブジェクトメソッド内で使用した場合

オブジェクトメソッド内でthisキーワードを使用すると、thisは「直接」を囲むオブジェクトにバインドされます。

var obj = {
    name: "obj",
    f: function () {
        return this + ":" + this.name;
    }
};
document.write(obj.f());  //[object Object]:obj

上記の言葉を二重引用符で囲みます。オブジェクトを別のオブジェクトの内側にネストすると、thisは直接の親にバインドされるということになります。

var obj = {
    name: "obj1",
    nestedobj: {
        name:"nestedobj",
        f: function () {
            return this + ":" + this.name;
        }
    }            
}

document.write(obj.nestedobj.f()); //[object Object]:nestedobj

メソッドとしてオブジェクトに関数を明示的に追加しても、それはまだ上記の規則に従います。つまり、thisはまだ直接の親オブジェクトを指しています。

var obj1 = {
    name: "obj1",
}

function returnName() {
    return this + ":" + this.name;
}

obj1.f = returnName; //add method to object
document.write(obj1.f()); //[object Object]:obj1

3.コンテキストレス機能を呼び出す場合

コンテキストなしで(つまり、どのオブジェクトに対しても)呼び出されない関数内でthisを使用すると、グローバル関数(ブラウザ内ではwindow)にバインドされます(関数がオブジェクト内で定義されている場合でも)。

var context = "global";

var obj = {  
    context: "object",
    method: function () {                  
        function f() {
            var context = "function";
            return this + ":" +this.context; 
        };
        return f(); //invoked without context
    }
};

document.write(obj.method()); //[object Window]:global 

機能で全部試して

上記の点も関数で試すことができます。ただし、いくつか違いがあります。

  • 上記では、オブジェクトリテラル表記を使用してオブジェクトにメンバーを追加しました。 thisを使って関数にメンバーを追加することができます。それらを指定します。
  • オブジェクトリテラル表記はすぐに使用できるオブジェクトのインスタンスを作成します。 functionでは、最初にnew演算子を使ってインスタンスを作成する必要があります。
  • また、オブジェクトリテラルアプローチでは、ドット演算子を使用して、既に定義されているオブジェクトにメンバーを明示的に追加できます。これは特定のインスタンスにのみ追加されます。しかし、関数のすべてのインスタンスに反映されるように、関数プロトタイプに変数を追加しました。

以下では、Objectとthisを使って行ったことをすべて試しましたが、直接オブジェクトを書くのではなく、まず関数を作成しました。

/********************************************************************* 
  1. When you add variable to the function using this keyword, it 
     gets added to the function prototype, thus allowing all function 
     instances to have their own copy of the variables added.
*********************************************************************/
function functionDef()
{
    this.name = "ObjDefinition";
    this.getName = function(){                
        return this+":"+this.name;
    }
}        

obj1 = new functionDef();
document.write(obj1.getName() + "<br />"); //[object Object]:ObjDefinition   

/********************************************************************* 
   2. Members explicitly added to the function protorype also behave 
      as above: all function instances have their own copy of the 
      variable added.
*********************************************************************/
functionDef.prototype.version = 1;
functionDef.prototype.getVersion = function(){
    return "v"+this.version; //see how this.version refers to the
                             //version variable added through 
                             //prototype
}
document.write(obj1.getVersion() + "<br />"); //v1

/********************************************************************* 
   3. Illustrating that the function variables added by both above 
      ways have their own copies across function instances
*********************************************************************/
functionDef.prototype.incrementVersion = function(){
    this.version = this.version + 1;
}
var obj2 = new functionDef();
document.write(obj2.getVersion() + "<br />"); //v1

obj2.incrementVersion();      //incrementing version in obj2
                              //does not affect obj1 version

document.write(obj2.getVersion() + "<br />"); //v2
document.write(obj1.getVersion() + "<br />"); //v1

/********************************************************************* 
   4. `this` keyword refers to the immediate parent object. If you 
       nest the object through function prototype, then `this` inside 
       object refers to the nested object not the function instance
*********************************************************************/
functionDef.prototype.nestedObj = { name: 'nestedObj', 
                                    getName1 : function(){
                                        return this+":"+this.name;
                                    }                            
                                  };

document.write(obj2.nestedObj.getName1() + "<br />"); //[object Object]:nestedObj

/********************************************************************* 
   5. If the method is on an object's prototype chain, `this` refers 
      to the object the method was called on, as if the method was on 
      the object.
*********************************************************************/
var ProtoObj = { fun: function () { return this.a } };
var obj3 = Object.create(ProtoObj); //creating an object setting ProtoObj
                                    //as its prototype
obj3.a = 999;                       //adding instance member to obj3
document.write(obj3.fun()+"<br />");//999
                                    //calling obj3.fun() makes 
                                    //ProtoObj.fun() to access obj3.a as 
                                    //if fun() is defined on obj3

4.コンストラクタ関数内で使用する場合 .

関数がコンストラクターとして使用されている場合(つまり、newキーワードを指定して呼び出されている場合)、関数本体内のthisは、作成中の新しいオブジェクトを指します。

var myname = "global context";
function SimpleFun()
{
    this.myname = "simple function";
}

var obj1 = new SimpleFun(); //adds myname to obj1
//1. `new` causes `this` inside the SimpleFun() to point to the
//   object being constructed thus adding any member
//   created inside SimipleFun() using this.membername to the
//   object being constructed
//2. And by default `new` makes function to return newly 
//   constructed object if no explicit return value is specified

document.write(obj1.myname); //simple function

5.プロトタイプチェーンで定義した関数内で使用した場合

メソッドがオブジェクトのプロトタイプチェーン上にある場合、そのメソッド内のthisは、そのメソッドがオブジェクト上で定義されているかのように、そのメソッドが呼び出されたオブジェクトを参照します。

var ProtoObj = {
    fun: function () {
        return this.a;
    }
};
//Object.create() creates object with ProtoObj as its
//prototype and assigns it to obj3, thus making fun() 
//to be the method on its prototype chain

var obj3 = Object.create(ProtoObj);
obj3.a = 999;
document.write(obj3.fun()); //999

//Notice that fun() is defined on obj3's prototype but 
//`this.a` inside fun() retrieves obj3.a   

6.内部のcall()、apply()、bind()関数

  • これらのメソッドはすべてFunction.prototypeで定義されています。
  • これらのメソッドは一度関数を書いてそれを異なるコンテキストで呼び出すことを可能にします。言い換えれば、関数の実行中に使用されるthisの値を指定することができます。それらはまた、呼び出されたときに元の関数に渡されるパラメータも取ります。
  • fun.apply(obj1 [, argsArray])fun()内のthisの値としてobj1を設定し、その引数としてargsArrayの要素を渡してfun()を呼び出します。
  • fun.call(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]]) - fun()内のthisの値としてobj1を設定し、その引数としてarg1, arg2, arg3, ...を渡してfun()を呼び出します。
  • fun.bind(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]]) - fun内のfunobj1にバインドし、thisのパラメーターをarg1, arg2, arg3,...で指定したパラメーターにバインドした関数funへの参照を返します。
  • これまでに、applycall、およびbindの違いが明らかになっているはずです。 applyは、配列のようなオブジェクト、すなわち数値のlengthプロパティおよび対応する負でない整数プロパティを持つオブジェクトとして機能するための引数を指定することを可能にします。 callでは、関数への引数を直接指定できます。 applycallは両方とも、指定されたコンテキストで指定された引数を使用して関数を直ちに呼び出します。一方、bindは、指定されたthis値と引数にバインドされた関数を単に返します。この返された関数への参照を変数に代入することで取得でき、後でいつでも呼び出すことができます。
function add(inc1, inc2)
{
    return this.a + inc1 + inc2;
}

var o = { a : 4 };
document.write(add.call(o, 5, 6)+"<br />"); //15
      //above add.call(o,5,6) sets `this` inside
      //add() to `o` and calls add() resulting:
      // this.a + inc1 + inc2 = 
      // `o.a` i.e. 4 + 5 + 6 = 15
document.write(add.apply(o, [5, 6]) + "<br />"); //15
      // `o.a` i.e. 4 + 5 + 6 = 15

var g = add.bind(o, 5, 6);       //g: `o.a` i.e. 4 + 5 + 6
document.write(g()+"<br />");    //15

var h = add.bind(o, 5);          //h: `o.a` i.e. 4 + 5 + ?
document.write(h(6) + "<br />"); //15
      // 4 + 5 + 6 = 15
document.write(h() + "<br />");  //NaN
      //no parameter is passed to h()
      //thus inc2 inside add() is `undefined`
      //4 + 5 + undefined = NaN</code>

7.イベントハンドラ内のthis

  • 関数を要素のイベントハンドラに直接割り当てる場合、イベント処理関数内で直接thisを使用すると、対応する要素が参照されます。そのような直接の関数割り当てはaddeventListenerメソッドを使うか、onclickのような伝統的なイベント登録メソッドを通して行うことができます。
  • 同様に、要素のeventプロパティ(<button onclick="...this..." >など)のすぐ内側でthisを使用すると、それは要素を参照します。
  • ただし、イベント処理関数またはイベントプロパティ内で呼び出される他の関数を介して間接的にthisを使用すると、グローバルオブジェクトwindowに解決されます。
  • MicrosoftのEvent RegistrationモデルメソッドattachEventを使用して、関数をイベントハンドラにアタッチすると、上記と同じ動作が実現されます。関数をイベントハンドラに割り当てる(そして要素の関数メソッドを作成する)代わりに、イベントで関数を呼び出します(実質的にグローバルコンテキストで呼び出します)。

私は JSFiddle でこれを試してみることをお勧めします

<script> 
    function clickedMe() {
       alert(this + " : " + this.tagName + " : " + this.id);
    } 
    document.getElementById("button1").addEventListener("click", clickedMe, false);
    document.getElementById("button2").onclick = clickedMe;
    document.getElementById("button5").attachEvent('onclick', clickedMe);   
</script>

<h3>Using `this` "directly" inside event handler or event property</h3>
<button id="button1">click() "assigned" using addEventListner() </button><br />
<button id="button2">click() "assigned" using click() </button><br />
<button id="button3" onclick="alert(this+ ' : ' + this.tagName + ' : ' + this.id);">used `this` directly in click event property</button>

<h3>Using `this` "indirectly" inside event handler or event property</h3>
<button onclick="alert((function(){return this + ' : ' + this.tagName + ' : ' + this.id;})());">`this` used indirectly, inside function <br /> defined & called inside event property</button><br />

<button id="button4" onclick="clickedMe()">`this` used indirectly, inside function <br /> called inside event property</button> <br />

IE only: <button id="button5">click() "attached" using attachEvent() </button>
137
Mahesha999

Javascriptのthis

単純な関数呼び出し

次の関数を考えてください。

function foo() {
    console.log("bar");
    console.log(this);
}
foo(); // calling the function

これは通常モードで実行していることに注意してください。つまり、厳密モードは使用されていません。

ブラウザで実行している場合、thisの値はwindowとして記録されます。これは、windowがWebブラウザのスコープ内のグローバル変数であるためです。

Node.jsのような環境でこれと同じコードを実行すると、thisはアプリケーションのグローバル変数を参照します。

厳密なモードでステートメント"use strict";を関数宣言の先頭に追加してこれを実行すると、thisはどちらの環境でもグローバル変数を参照しなくなります。これは、厳密モードでの混乱を避けるために行われています。 thisは、この場合は単にundefinedをログに記録するだけです。これは定義ではないためです。

次のような場合、thisの値を操作する方法がわかります。

オブジェクトの関数を呼び出す

これを行うにはさまざまな方法があります。 forEachsliceのようにJavascriptでネイティブメソッドを呼び出した場合は、その場合のthis変数がその関数を呼び出したObjectを参照していることをすでに知っているはずです(javascriptでは、Objectを含め、ほぼすべてArrayです) Functions)例えば以下のコードを取ります。

var myObj = {key: "Obj"};
myObj.logThis = function () {
    // I am a method
    console.log(this);
}
myObj.logThis(); // myObj is logged

ObjectFunctionを保持するプロパティを含む場合、そのプロパティはメソッドと呼ばれます。このメソッドは、呼び出されると、常にthis変数が関連付けられているObject変数に設定されます。これは、厳密モードと非厳密モードの両方に当てはまります。

メソッドが別の変数に格納されている(またはコピーされている)場合、thisへの参照は新しい変数には保存されなくなります。例えば:

// continuing with the previous code snippet

var myVar = myObj.thisMethod;
myVar();
// logs either of window/global/undefined based on mode of operation

より一般的な実用的なシナリオを考えます。

var el = document.getElementById('idOfEl');
el.addEventListener('click', function() { console.log(this) });
// the function called by addEventListener contains this as the reference to the element
// so clicking on our element would log that element itself

newキーワード

Javascriptのコンストラクタ関数を考えます。

function Person (name) {
    this.name = name;
    this.sayHello = function () {
        console.log ("Hello", this);
    }
}

var awal = new Person("Awal");
awal.sayHello();
// In `awal.sayHello`, `this` contains the reference to the variable `awal`

これはどのように作動しますか?それでは、newキーワードを使用したときに何が起こるかを見てみましょう。

  1. newキーワードを使用して関数を呼び出すと、すぐにObject型のPersonが初期化されます。
  2. このObjectのコンストラクタは、そのコンストラクタがPersonに設定されています。また、typeof awalObjectのみを返すことにも注意してください。
  3. この新しいObjectにはPerson.prototypeのプロトタイプが割り当てられます。これは、Personプロトタイプ内のすべてのメソッドまたはプロパティが、Personを含むawalのすべてのインスタンスで使用できることを意味します。
  4. 関数Person自体が呼び出されました。 thisは、新しく構築されたオブジェクトawalへの参照です。

かなり簡単ですね。

公式のECMAScript仕様では、この種の関数は実際のconstructor関数であるとは何も述べていないことに注意してください。それらは通常の関数であり、newはどの関数にも使用できます。それは私達がそれらをそのように使用するということだけです、そしてそれ故私達はそれらをそのようなものとしてのみ呼びます。

関数で関数を呼び出す:callapply

そうです、functionObjects(そしてJavascriptの実際にはファーストクラスの変数)でもあるので、関数でさえも...それ自体が関数であるメソッドを持っています。

すべての関数はグローバルFunctionを継承しており、その多くのメソッドのうちの2つはcallapplyであり、両方ともそれらが呼び出される関数でthisの値を操作するために使用できます。

function foo () { console.log (this, arguments); }
var thisArg = {myObj: "is cool"};
foo.call(thisArg, 1, 2, 3);

これはcallの典型的な使用例です。基本的に最初のパラメータを取り、関数thisfoothisArgへの参照として設定します。 callに渡される他のすべてのパラメータは、引数として関数fooに渡されます。
そのため、上記のコードはコンソールに{myObj: "is cool"}, [1, 2, 3]を記録します。どの関数でもthisの値を変更するための非常に良い方法です。

applycallとほとんど同じですが、thisArgと、関数に渡される引数を含む配列の2つのパラメータのみを取ります。したがって、上記のcall呼び出しは、次のようにapplyに変換できます。

foo.apply(thisArg, [1,2,3])

callapplyは、2番目の箇条書きで説明したドットメソッド呼び出しによって設定されたthisの値をオーバーライドすることができます。とても簡単:)

……bind

bindcallapplyの兄弟です。 JavascriptのグローバルFunctionコンストラクタからすべての関数に継承されるメソッドでもあります。 bindcall/applyの違いは、callapplyの両方が実際に関数を呼び出すということです。一方、bindは、thisArgargumentsが事前設定された新しい関数を返します。これをよりよく理解するために例を見てみましょう。

function foo (a, b) {
    console.log (this, arguments);
}
var thisArg = {myObj: "even more cool now"};
var bound = foo.bind(thisArg, 1, 2);
console.log (typeof bound); // logs `function`
console.log (bound);
/* logs `function () { native code }` */

bound(); // calling the function returned by `.bind`
// logs `{myObj: "even more cool now"}, [1, 2]`

3つの違いは?微妙ですが、使い方は異なります。 callapplyと同様に、bindもドットメソッド呼び出しによって設定されたthisの値を上書きします。

また、これら3つの関数はどちらも元の関数に変更を加えることはありません。 callapplyは、新たに構築された関数から値を返しますが、bindは、新たに構築された関数自体を返します。

追加のもの、これをコピーする

時々、あなたはthisがスコープ、特にネストされたスコープによって変わるという事実を好まない。次の例を見てください。

var myObj = {
    hello: function () {
        return "world"
        },
    myMethod: function () {
        // copy this, variable names are case-sensitive
        var that = this;
        // callbacks ftw \o/
        foo.bar("args", function () {
            // I want to call `hello` here
            this.hello(); // error
            // but `this` references to `foo` damn!
            // oh wait we have a backup \o/
            that.hello(); // "world"
        });
    }
  };

上記のコードでは、thisの値はネストされたスコープによって変化していますが、元のスコープからthisの値が必要でした。そのため、thisthatに「コピー」し、thisの代わりにそのコピーを使用しました。賢いでしょ?

索引:

  1. デフォルトでthisには何が保持されていますか?
  2. この関数をオブジェクトドット表記のメソッドとして呼び出すとどうなりますか?
  3. newキーワードを使用するとどうなりますか?
  4. thiscallを使ってapplyをどのように操作するのでしょうか。
  5. bindを使う.
  6. ネストスコープの問題を解決するためのthisのコピー.
53
user3459110

「これ」はすべて範囲に関するものです。すべての関数はそれ自身のスコープを持っています、そして、JSの中のすべてはオブジェクトなので、関数でさえも "this"を使ってそれ自身にいくつかの値を格納することができます。 OOP 101は "this"はオブジェクトの インスタンス にのみ適用可能であることを教えています。したがって、関数が実行されるたびに、その関数の新しい「インスタンス」は「this」という新しい意味を持ちます。

ほとんどの人は、次のような無名クロージャ関数の中で "this"を使おうとすると混乱します。

(関数(値){
 this.value = value; 
 $( '。some-elements')。each(関数(elt){
 elt .innerHTML = this.value; //あー!!おそらく未定義
}); 
})(2); 

だからここで、each()の中で、 "this"はあなたが期待する "value"を保持していません。

this.value = value;
(関数(値){
 var self = this; //小さな変更
 self.value = value; 
 $( '。some-elements') .each(function(elt){
 elt.innerHTML = self.value; // phew !! == 2 
}); 
})(2); 

やってみよう;あなたはプログラミングのこのパターンを好きになり始めるでしょう

46
arunjitsingh

このスレッドが盛り上がったので、私はthisname__トピックに不慣れな読者のためにいくつかのポイントをまとめました。

thisname__の値はどのように決定されますか?

私たちはこれを英語のような自然言語で代名詞を使うのと同じように使います。「ジョンはheが電車に乗ろうとしているので速く走っています。」Johnは電車に乗ろうとしています。

var person = {    
    firstName: "Penelope",
    lastName: "Barrymore",
    fullName: function () {

    // We use "this" just as in the sentence above:
       console.log(this.firstName + " " + this.lastName);

    // We could have also written:
       console.log(person.firstName + " " + person.lastName);
    }
}

thisname__ は、オブジェクトが定義されている場所で関数が呼び出されるまで、値 が割り当てられません。グローバルスコープでは、すべてのグローバル変数と関数はwindowname__オブジェクトで定義されています。したがって、グローバル関数内のthisname__は、グローバルwindowname__オブジェクトを参照します(そしてその値を持ちます)。

グローバル、およびどのオブジェクトにもバインドされていない無名関数内のuse strictthisname__が、値undefinedname__を保持している場合。

thisname__キーワードは 最も誤解される when:1)thisname__を使用するメソッドを借用します。2)thisname__を使用するメソッドを変数に割り当てます。3)thisname__を使用する関数はコールバック関数として渡されます。 4)thisname__はクロージャー(内部関数)の中で使われています。 (2)

table

未来を支えるもの

ECMA Script 6 で定義されている場合、arrow-functionsは囲んでいる(関数またはグローバル)スコープからthisname__バインディングを採用します。

function foo() {
     // return an arrow function
     return (a) => {
     // `this` here is lexically inherited from `foo()`
     console.log(this.a);
  };
}
var obj1 = { a: 2 };
var obj2 = { a: 3 };

var bar = foo.call(obj1);
bar.call( obj2 ); // 2, not 3!

Arrow-functionsはbind()を使用する代わりになりますが、それらが本質的に伝統的なthisname__メカニズムを無効にしているということは重要です。 (1)


参考文献

  1. this&Object Prototypes 、Kyle Simpson著。 ©2014 Getify Solutions。
  2. javascriptissexy.com - http://goo.gl/pvl0GX
  3. アンガスクロル - http://goo.gl/Z2RacU
16
carlodurso

Javascriptのthisは常に 実行されている関数の '所有者' を参照します。

明示的な所有者が定義されていない場合は、最上位の所有者であるウィンドウオブジェクトが参照されます。

だから私がした場合

function someKindOfFunction() {
   this.style = 'foo';
}

element.onclick = someKindOfFunction;

thisは要素オブジェクトを参照します。しかし、注意してください、多くの人がこの間違いを犯します

<element onclick="someKindOfFunction()">

後者の場合、あなたは単に関数を参照するだけで、それを要素に渡すことはしません。そのため、thisはウィンドウオブジェクトを参照します。

16
Seph

すべての 関数 実行コンテキスト javascriptでは/が 範囲コンテキスト this :によって設定されるパラメータ

  1. 関数の呼び出し方法(オブジェクトメソッドとして、 call apply の使用、 new の使用を含む)
  2. bind の使用
  3. 語彙的には矢印関数のために使われます(それらは this の外側の実行コンテキストを採用します)

そのスコープコンテキストが何であれ、 "this"によって参照されます。

あなたはできる それを変える this の値を設定 範囲コンテキスト func.callfunc.applyまたはfunc.bindを使用します。

デフォルトでは、ほとんどの初心者を混乱させます。 callback DOM要素でイベントが発生した後にリスナーが呼び出されます。 スコープコンテキスト これ 関数の値はDOM要素です。

jQueryはjQuery.proxyでこれを簡単に変更します。

12
blockhead

ここでthisの中のJavaScriptの良い情報源です。

概要は次のとおりです。

  • global this

    ブラウザでは、グローバルスコープでthiswindowオブジェクトです。

    <script type="text/javascript">
      console.log(this === window); // true
      var foo = "bar";
      console.log(this.foo); // "bar"
      console.log(window.foo); // "bar"
    

    Replを使用しているnodeでは、thisが最上位のネームスペースです。あなたはそれをglobalと呼ぶことができます。

    >this
      { ArrayBuffer: [Function: ArrayBuffer],
        Int8Array: { [Function: Int8Array] BYTES_PER_ELEMENT: 1 },
        Uint8Array: { [Function: Uint8Array] BYTES_PER_ELEMENT: 1 },
        ...
    >global === this
     true
    

    スクリプトから実行しているnodeでは、グローバルスコープのthisは空のオブジェクトとして始まります。 globalと同じではありません

    \\test.js
    console.log(this);  \\ {}
    console.log(this === global); \\ fasle
    
  • function this

DOMイベントハンドラの場合、またはthisArgが呼び出されていない関数内でthisを使用しているノード内およびブラウザ内の両方でnewが提供されている場合を除いて、グローバルスコープを参照します。

<script type="text/javascript">
    foo = "bar";

    function testThis() {
      this.foo = "foo";
    }

    console.log(this.foo); //logs "bar"
    testThis();
    console.log(this.foo); //logs "foo"
</script>

use strict;を使用する場合、その場合thisundefinedになります。

<script type="text/javascript">
    foo = "bar";

    function testThis() {
      "use strict";
      this.foo = "foo";
    }

    console.log(this.foo); //logs "bar"
    testThis();  //Uncaught TypeError: Cannot set property 'foo' of undefined 
</script>

newを使用して関数を呼び出すと、thisは新しいコンテキストになり、グローバルなthisを参照しなくなります。

<script type="text/javascript">
    foo = "bar";

    function testThis() {
      this.foo = "foo";
    }

    console.log(this.foo); //logs "bar"
    new testThis();
    console.log(this.foo); //logs "bar"

    console.log(new testThis().foo); //logs "foo"
</script>
  • プロトタイプこれ

作成した関数は関数オブジェクトになります。それらは自動的に特別なprototypeプロパティを取得します。これはあなたが値を割り当てることができるものです。 newを使用して関数を呼び出してインスタンスを作成すると、prototypeプロパティに割り当てた値にアクセスできます。これらの値にアクセスするにはthisを使用します。

function Thing() {
  console.log(this.foo);
}

Thing.prototype.foo = "bar";

var thing = new Thing(); //logs "bar"
console.log(thing.foo);  //logs "bar"

通常、prototype配列またはオブジェクトを代入するのは誤りです。インスタンスごとに独自の配列が必要な場合は、プロトタイプではなく関数内にそれらを作成します。

function Thing() {
    this.things = [];
}

var thing1 = new Thing();
var thing2 = new Thing();
thing1.things.Push("foo");
console.log(thing1.things); //logs ["foo"]
console.log(thing2.things); //logs []
  • object this

オブジェクトの他のプロパティを参照するために、オブジェクトの任意の関数でthisを使用できます。これはnewで作成されたインスタンスと同じではありません。

var obj = {
    foo: "bar",
    logFoo: function () {
        console.log(this.foo);
    }
};

obj.logFoo(); //logs "bar"
  • DOMイベントthis

HTML DOMイベントハンドラでは、thisは常にイベントが関連付けられたDOM要素への参照です。

function Listener() {
    document.getElementById("foo").addEventListener("click",
       this.handleClick);
}
Listener.prototype.handleClick = function (event) {
    console.log(this); //logs "<div id="foo"></div>"
}

var listener = new Listener();
document.getElementById("foo").click();

コンテキストをbindにしない限り

function Listener() {
    document.getElementById("foo").addEventListener("click", 
        this.handleClick.bind(this));
}
Listener.prototype.handleClick = function (event) {
    console.log(this); //logs Listener {handleClick: function}
}

var listener = new Listener();
document.getElementById("foo").click();
  • HTML this

JavaScriptを入れることができるHTML属性の中で、thisは要素への参照です。

<div id="foo" onclick="console.log(this);"></div>
<script type="text/javascript">
document.getElementById("foo").click(); //logs <div id="foo"...
</script>
  • eval this

evalを使用してthisにアクセスできます。

function Thing () {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {
    eval("console.log(this.foo)"); //logs "bar"
}

var thing = new Thing();
thing.logFoo();
  • これとともに

withを明示的に参照せずにthisを現在のスコープに追加してthisの値を読み書きするには、thisを使用します。

function Thing () {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {
    with (this) {
        console.log(foo);
        foo = "foo";
    }
}

var thing = new Thing();
thing.logFoo(); // logs "bar"
console.log(thing.foo); // logs "foo"
  • jQuery this

jQueryは多くの場所でthisがDOM要素を参照するようにします。

<div class="foo bar1"></div>
<div class="foo bar2"></div>
<script type="text/javascript">
$(".foo").each(function () {
    console.log(this); //logs <div class="foo...
});
$(".foo").on("click", function () {
    console.log(this); //logs <div class="foo...
});
$(".foo").each(function () {
    this.click();
});
</script>
10
zangw

おそらくthisに関する最も詳細で包括的な記事は次のとおりです。

JavaScriptの 'this'キーワードの簡単な説明

thisの背後にある考え方は、関数呼び出しタイプがthis値の設定において非常に重要であることを理解することです。


thisを識別するのに問題があるときは、 しないでください 自分自身に尋ねてください。

this from fromはどこにありますか?

しかし do 自分自身に尋ねる:

関数invokeはどうですか?

矢印機能(文脈透過の特別な場合)については、あなた自身に尋ねてください。

矢印関数がdefinedの場合、thisはどのような値になりますか?

この考え方はthisを扱うときに正しいので、頭痛からあなたを救うでしょう。

9
Dmitri Pavlutin

ダニエル、素晴らしい説明です。イベントハンドラの場合の、これとthis実行コンテキストポインタの適切なリストに関するいくつかの単語。

つまり、JavaScriptのthisは、現在の関数が実行された人(またはその実行コンテキスト)からのオブジェクトを指しており、常に読み取り専用です。それを設定することはできません。課題メッセージの手元.

イベントハンドラの場合: <element onclick="foo">などのインラインイベントハンドラは、以前および以前にアタッチされている他のハンドラをオーバーライドするので、注意してください。インラインイベントの委任を避けるようにしてください。そして、異議を唱える議論を通してこの例のリストに私を奮い立たせたZara Alaverdyanに感謝します:)

  • el.onclick = foo; // in the foo - obj
  • el.onclick = function () {this.style.color = '#fff';} // obj
  • el.onclick = function() {doSomething();} // In the doSomething - Window
  • el.addEventListener('click',foo,false) // in the foo - obj
  • el.attachEvent('onclick, function () { // this }') // window, all the compliance to IE :)
  • <button onclick="this.style.color = '#fff';"> // obj
  • <button onclick="foo"> // In the foo - window, but you can <button onclick="foo(this)">
9

これは私が見た中で最高の説明です。 JavaScriptを理解する this Clarity付き

this referenceは、オブジェクト(単数オブジェクト)を常に参照(およびその値を保持)し、グローバルスコープ内の関数の外部で使用することもできます。 。厳密モードを使用する場合、これはグローバル関数内およびオブジェクトにバインドされていない無名関数内のundefinedの値を保持します。

this が混乱を招く可能性がある4つの条件があります。

  1. メソッドとして( this を使用する)メソッドを渡すと、コールバック関数として使用されます。
  2. これが誤解されているもう1つの例は、内部メソッド(クロージャ)を使用したときです。 this変数は内部関数ではなく関数自体からのみアクセスできるため、クロージャーはthisキーワードを使用して外部関数の this 変数にアクセスすることはできません。
  3. メソッドが変数に割り当てられている場合は、 this を使用します。これを使用するメソッドを変数に割り当てると、 this の値は別のオブジェクトにバインドされます。
  4. Bind、apply、およびcallメソッドを使用する場合は、 this を使用します。

彼は、コード例、説明、そして私がとても役に立ちそうだと思ったコード修正を与えます。

7
James Drinkard

十分に理解していないと、JSを十分に理解したり、その中に何か些細なことを書いたりすることは困難です。私はJSを始めるための最良の方法はDouglas Crockfordによるこれらのビデオ講義を最初に見ることだと思います - http://yuiblog.com/crockford/ 、これをカバーしていますそれが、JSに関する他のすべてのことです。

6
tathagata

擬古典的用語では、多くの講義が 'this'キーワードを教える方法は、クラスまたはオブジェクトコンストラクターによってインスタンス化されたオブジェクトとしてです。新しいオブジェクトがクラスから構築されるたびに、内部で「this」オブジェクトのローカルインスタンスが作成されて返されると想像してください。私はそれがこのように教えられたのを覚えています:

function Car(make, model, year) {
var this = {}; // under the hood, so to speak
this.make = make;
this.model = model;
this.year = year;
return this; // under the hood
}

var mycar = new Car('Eagle', 'Talon TSi', 1993);
// ========= under the hood
var this = {};
this.make = 'Eagle';
this.model = 'Talon TSi';
this.year = 1993;
return this;
6
mrmaclean89

thisはJavaScriptの誤解されている概念の1つです。これは、場所によって動作が多少異なるためです。簡単に言うと、thisは、現在実行している関数の 「所有者」 を指します。

thisは、現在のオブジェクト(実行コンテキスト)を取得するのに役立ちます。現在の関数がどのオブジェクトで実行されているのか理解できれば、現在のthisがどんなものであるかを容易に理解することができます。

var val = "window.val"

var obj = {
    val: "obj.val",
    innerMethod: function () {
        var val = "obj.val.inner",
            func = function () {
                var self = this;
                return self.val;
            };

        return func;
    },
    outerMethod: function(){
        return this.val;
    }
};

//This actually gets executed inside window object 
console.log(obj.innerMethod()()); //returns window.val

//Breakdown in to 2 lines explains this in detail
var _inn = obj.innerMethod();
console.log(_inn()); //returns window.val

console.log(obj.outerMethod()); //returns obj.val

上記の同じ名前 'val'で3つの変数を作成します。一方はobjの内側に、もう一方はobjのinnerMethodの内側にあります。 JavaScriptは、ローカルからグローバルにスコープチェーンを上がることによって、特定のコンテキスト内の識別子を解決します。


thisを区別できる場所はほとんどありません

オブジェクトのメソッドを呼び出す

var status = 1;
var helper = {
    status : 2,
    getStatus: function () {
        return this.status;
    }
};

var theStatus1 = helper.getStatus(); //line1
console.log(theStatus1); //2

var theStatus2 = helper.getStatus;
console.log(theStatus2()); //1

Line1が実行されると、JavaScriptは関数呼び出しの実行コンテキスト(EC)を確立し、最後の "。"の前にくるものが参照する オブジェクトにthisを設定します。 。最後の行で、a()windowというグローバルコンテキストで実行されたことがわかります。

コンストラクタ付き

thisは、作成中のオブジェクトを参照するために使用できます。

function Person(name){
    this.personName = name;
    this.sayHello = function(){
        return "Hello " + this.personName;
    }
}

var person1 = new Person('Scott');
console.log(person1.sayHello()); //Hello Scott

var person2 = new Person('Hugh');
var sayHelloP2 = person2.sayHello;
console.log(sayHelloP2()); //Hello undefined

New Person()が実行されると、全く新しいオブジェクトが作成されます。 Personが呼び出され、そのthisがその新しいオブジェクトを参照するように設定されます。

関数呼び出し

function testFunc() {
    this.name = "Name";
    this.myCustomAttribute = "Custom Attribute";
    return this;
}

var whatIsThis = testFunc();
console.log(whatIsThis); //window

var whatIsThis2 = new testFunc();
console.log(whatIsThis2);  //testFunc() / object

console.log(window.myCustomAttribute); //Custom Attribute 

newキーワードを見逃した場合、whatIsThisはそれが見つけることができる最もグローバルなコンテキストを参照します(window

イベントハンドラとは

イベントハンドラがインラインの場合、thisはグローバルオブジェクトを参照します。

<script type="application/javascript">
    function click_handler() {
        alert(this); // alerts the window object
    }
</script>

<button id='thebutton' onclick='click_handler()'>Click me!</button>

JavaScriptを通してイベントハンドラを追加するとき、thisはイベントを生成したDOM要素を参照します。


5
Nipuna

「this」の値は、関数が実行される「コンテキスト」によって異なります。コンテキストは、任意のオブジェクトまたはグローバルオブジェクト、つまりウィンドウにすることができます。

そのため、「これ」の意味は伝統的なOOP言語とは異なります。そしてそれは問題を引き起こします:1.関数が他の変数(たぶん、コールバック)に渡されるとき。クロージャがクラスのメンバメソッドから呼び出されたとき。

どちらの場合も、これはwindowに設定されています。

5
Trombe

これ 助けになりますか? (JavaScriptでの 'this'の最も混乱は、それが一般的にあなたのオブジェクトではなく現在の実行スコープにリンクされているという事実から来ています - それは正確には機能しないかもしれませんがいつも私のように感じます - 完全な説明については記事を参照してください)

3

this キーワードについてのちょっとした情報

コードを追加せずに、グローバルスコープでthisキーワードをコンソールに記録しましょう。

console.log(this)

クライアント/ブラウザ thisキーワードはwindowであるグローバルオブジェクトです。

console.log(this === window) // true

そして

Server/Node/Javascript runtime thisキーワードもmodule.exportsであるグローバルオブジェクトです。

console.log(this === module.exports) // true
console.log(this === exports) // true

exportsは単にmodule.exportsへの参照です

3
unclexo

私はthisを他の答えとは違う見方をしています。

JavaScriptを見る1つの方法は、関数を呼び出す方法が1つしかないことを確認することです。1。それは

functionObject.call(objectForThis, arg0, arg1, arg2, ...);

objectForThisには常にいくつかの値が提供されています。

他のものはすべてfunctionObject.callの構文糖です

それで、他のすべてはfunctionObject.callに変換される方法によって記述することができます。

関数を呼び出すだけの場合、thisはブラウザ内のウィンドウである "グローバルオブジェクト"です。

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

foo();  // this is the window object

言い換えると、

foo();

に効果的に翻訳された

foo.call(window);

厳密モードを使用する場合、thisundefinedになります。

'use strict';

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

foo();  // this is the window object

つまり

言い換えると、

foo();

に効果的に翻訳された

foo.call(undefined);

JavaScriptには+-そして*のような演算子があります。 .であるドット演算子もあります

.演算子は、右側の関数と左側のオブジェクトと共に使用すると、事実上「functionにthisとしてオブジェクトを渡すことを意味します。

const bar = {
  name: 'bar',
  foo() { 
    console.log(this); 
  },
};

bar.foo();  // this is bar

言い換えれば、bar.foo()const temp = bar.foo; temp.call(bar);に変換されます。

関数の作成方法は関係ありません(ほとんどの場合...)。これらのすべてが同じ結果を生成します

const bar = {
  name: 'bar',
  fn1() { console.log(this); },
  fn2: function() { console.log(this); },
  fn3: otherFunction,
};

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

bar.fn1();  // this is bar
bar.fn2();  // this is bar
bar.fn3();  // this is bar

繰り返しますが、これらはすべて構文糖にすぎません。

{ const temp = bar.fn1; temp.call(bar); }
{ const temp = bar.fn2; temp.call(bar); }
{ const temp = bar.fn3; temp.call(bar); }

もう一つのしわはプロトタイプチェーンです。 a.bを使用すると、JavaScriptはまずaによって直接参照されているオブジェクトでプロパティbを調べます。オブジェクトにbが見つからない場合、JavaScriptはオブジェクトのプロトタイプを調べてbを見つけます。

オブジェクトのプロトタイプを定義するにはさまざまな方法があります。2019で最も一般的なのはclassキーワードです。 thisの目的では問題ありませんが。重要なのは、オブジェクトaのプロパティbがオブジェクトのproperty bを見つけた場合、またはプロトタイプチェーンの中でbが関数になった場合です。上記と同じ規則が適用されます。関数b参照は、callメソッドを使用し、object []としてaを渡すことで呼び出されます。この回答の冒頭に示したとおりです。

今すぐ別の関数を呼び出す前にthisを明示的に設定してから.(dot)演算子で呼び出す関数を作成したとしましょう。

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

function bar() {
  const objectForThis = {name: 'moo'}
  foo.call(objectForThis);  // explicitly passing objectForThis
}

const obj = {
  bar,
};

obj.bar();  

callを使用するように変換すると、obj.bar()const temp = obj.bar; temp.call(obj);になります。 bar関数に入るときは、fooを呼び出しますが、objectForThisに別のオブジェクトを明示的に渡したので、foo thisに到達したときはその内部オブジェクトです。

これがbind関数と=>関数の両方が効果的に行うことです。彼らはもっと統語的な砂糖です。指定された関数を呼び出す前に明示的にbarを設定する上記のthisとまったく同じように、見えない新しい関数を効果的に構築します。 bindの場合、thisbindに渡すものに設定されます。

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

const bar = foo.bind({name: 'moo'});

// bind created a new invisible function that calls foo with the bound object.

bar();  

// the objectForThis we are passing to bar here is ignored because
// the invisible function that bind created will call foo with with
// the object we bound above

bar.call({name: 'other'});

functionObject.bindが存在しない場合は、次のように独自のものを作成できます。

function bind(fn, objectForThis) {
  return function(...args) {
    return fn.call(objectForthis, ...args);
  };
}

そしてそれを次のように呼ぶことができます

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

const bar = bind(foo, {name:'abc'});

矢印関数、=>演算子はバインドのための構文糖です

const a = () => {console.log(this)};

と同じです

const tempFn = function() {console.log(this)}; 
const a = tempFn.bind(this);

bindと同じように、objectForThisのバインド値を使用して指定の関数を呼び出す新しい不可視関数が作成されますが、bindとは異なり、バインドされるオブジェクトは暗黙的です。 =>演算子が使用されたときにthisが発生することは何でもです。

それで、ちょうど上の規則のように

const a = () => { console.log(this); }  // this is the global object
'use strict';
const a = () => { console.log(this); }  // this is undefined
function foo() {
  return () => { console.log(this); }
}

const obj = {
  foo,
};
const b = obj.foo();
b();

obj.foo()const temp = obj.foo; temp.call(obj);に変換されます。これは、foo内の矢印演算子がobjを新しい不可視関数にバインドし、bに割り当てられた新しい不可視関数を返すことを意味します。 b()は、fooが作成した新しい不可視関数を呼び出すb.call(window)またはb.call(undefined)と同じように動作します。その見えない関数は、渡されたthisを無視し、object関数としてobjをarrow関数に渡します。

上記のコードは

function foo() {
  function tempFn() {
    console.log(this);
  }
  return tempFn.bind(this);
}

const obj = {
  foo,
};
const b = obj.foo();
b.call(window or undefined if strict mode);

1applycallに似た別の関数です。

functionName.apply(objectForThis, arrayOfArgs);

しかしES6では、概念的にそれを以下のようにも翻訳できます。

functionName.call(objectForThis, ...arrayOfArgs);
1
gman

このようにScopeに使用する

  <script type="text/javascript" language="javascript">
$('#tbleName tbody tr').each(function{
var txt='';
txt += $(this).find("td").eq(0).text();
\\same as above but synatx different
var txt1='';
 txt1+=$('#tbleName tbody tr').eq(0).text();
alert(txt1)
});
</script>

txt1とtxtの値は上の例と同じです$(this)= $( '#tbleName tbody tr')は同じです

要約this Javascript:

  • thisの値は、_関数の呼び出し方ではなく、作成場所によって決まります。
  • 通常thisの値はドットの左側にあるObjectによって決定されます。 (グローバル空間でwindow
  • イベントリスナーでは、thisの値はイベントが呼び出されたDOM要素を参照します。
  • 関数内でnewキーワードを使用して呼び出されると、thisの値は新しく作成されたオブジェクトを参照します
  • thisの値は、関数callapplybindを使って操作できます。

例:

let object = {
  prop1: function () {console.log(this);}
}

object.prop1();   // object is left of the dot, thus this is object

const myFunction = object.prop1 // We store the function in the variable myFunction

myFunction(); // Here we are in the global space
              // myFunction is a property on the global object
              // Therefore it logs the window object
              
             

イベントリスナーの例:

document.querySelector('.foo').addEventListener('click', function () {
  console.log(this);   // This refers to the DOM element the eventListener was invoked from
})


document.querySelector('.foo').addEventListener('click', () => {
  console.log(this);  // Tip, es6 arrow function don't have their own binding to the this v
})                    // Therefore this will log the global object
.foo:hover {
  color: red;
  cursor: pointer;
}
<div class="foo">click me</div>

コンストラクタの例:

function Person (name) {
  this.name = name;
}

const me = new Person('Willem');
// When using the new keyword the this in the constructor function will refer to the newly created object

console.log(me.name); 
// Therefore, the name property was placed on the object created with new keyword.
0

JavaScriptの「this」キーワードとは

このキーワードは、オブジェクト、つまりJavaScriptコードの現在のビットを実行しているオブジェクトを参照します。

言い換えれば、実行中のすべてのJavaScript関数は、thisという現在の実行コンテキストへの参照を持ちます。実行コンテキストとは、関数がどのように呼び出されるかを意味します。

このキーワードを理解するためには、関数が呼び出される場所、場所、場所、および宣言される方法や定義される場所が問題にならない方法を知っておく必要があります。

function bike() {
  console.log(this.name);
}

var name = "Ninja";
var obj1 = { name: "Pulsar", bike: bike };
var obj2 = { name: "Gixxer", bike: bike };

bike();           // "Ninja"
obj1.bike();      // "Pulsar"
obj2.bike();      // "Gixxer"

上記のコードスニペットでは、bike()関数の仕事はthis.nameを印刷することです。これは、現在の実行コンテキスト(i.e.this object)のnameプロパティの値を印刷しようとしていることを意味します。

上記のコードスニペットでは、関数bike()が呼び出されると、実行のコンテキストが指定されていないのでデフォルトでそのグローバルコンテキストがあり、グローバルコンテキストに値が "Ninja"の変数名が存在するため、 "Ninja"を出力します。

obj1().bike()呼び出しの場合、「Pulsar」が出力され、その背後にある理由は関数bike()が実行コンテキストをobj1として呼び出すため、this.nameobj1.nameになります。関数obj2.bike()の実行コンテキストがobj2であるbike()呼び出しと同じです。

「this」のデフォルトおよび暗黙の束縛

厳密モードの場合、このキーワードのデフォルト値は未定義です。それ以外の場合、このキーワードはグローバルオブジェクトとして機能します。このキーワードのデフォルトバインディングと呼びます。 ( ブラウザの場合のデフォルトはウィンドウオブジェクト )。

私たちがメソッドとして呼んでいるオブジェクトプロパティがあるとき、そのオブジェクトはこのオブジェクトまたはそのメソッドの実行コンテキストオブジェクトになります、それはこのキーワードの暗黙の束縛です。

var obj1 = {
  name: "Pulsar",
  bike: function() {
    console.log(this.name);
  }
}
var obj2 = { name: "Gixxer", bike: obj1.bike };
var name = "Ninja";
var bike = obj1.bike;

bike();           // "Ninja"
obj1.bike();      // "Pulsar"
obj2.bike();      // "Gixxer"

上記のコードスニペットでは、関数呼び出しbike()がデフォルトバインディングの例です。 obj1.bike()およびobj2.bike()は、暗黙的バインドの例です。ここではバイク関数はobj1の一部として宣言されていますが、それに関係なく、executeobj2.bike()の実行のコンテキストはobj2なので、obj2.nameが出力されます。

関数がいつ、どこから呼び出されても、どこで関数が宣言されていても構わないということを知っておくことは重要です。

「this」キーワードの明示的および固定的なバインディング

Callとapplyメソッドを呼び出し関数と一緒に使用する場合、それらのメソッドは両方とも実行コンテキストとしての最初のパラメータとして使用されます。それがこの拘束力です。

function bike() {
  console.log(this.name);
}

var name = "Ninja";
var obj = { name: "Pulsar" }

bike();           // "Ninja"
bike.call(obj);   // "Pulsar"

このスニペットで、実行コンテキストオブジェクトobjを最初の引数として渡してcall()メソッドで関数bikeを呼び出すと、objはこのオブジェクトに割り当てられ、obj.name以外の何もない“ Pulsar”を出力します。このキーワードの明示的な結合と呼ばれています。

固定綴じまたはハード綴じ

どこでどのように呼び出されても、thisオブジェクトを常に同じにすることができます。

var bike = function() {
  console.log(this.name);
}
var name = "Ninja";
var obj1 = { name: "Pulsar" };
var obj2 = { name: "Gixxer" };

var originalBikeFun = bike;
bike = function() {
  originalBikeFun.call(obj1);
};

bike();           // "Pulsar"
bike.call(obj2);  // "Pulsar"

上記のコードスニペットのとおり、bike()bike.call(obj2)はどちらも "Pulsar"を呼び出します。これはobj1.name以外の何ものでもなく、関数バイクの実行コンテキストは常にobj1であり、その理由はoriginalBikeFun.call(obj1)です。この種のこの束縛は、固定束縛と呼ばれるもう1つの明示的な束縛の一種です。

0
ashish