「this」キーワードはどのように機能しますか?
this
Stack OverflowサイトのJavaScriptでキーワードが何であり、どのように正しく(そして誤って)使用されているかについて明確な説明がないように思われることに気づきました。
私はそれでいくつかの非常に奇妙な振る舞いを目撃しました、そしてそれがなぜ起こったのか理解できませんでした。
どのように機能しthis
、いつ使用する必要がありますか?
回答
私は読んでお勧めのマイク・西の記事JavaScriptで適用範囲(ミラー)最初に。これは、this
JavaScriptの概念とスコープチェーンの優れたフレンドリーな紹介です。
慣れ始めるthis
と、ルールは実際には非常に単純です。ECMAScriptの5.1標準の定義this
:
§11.1.1
this
キーワード
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)。
2.評価コードの入力
…
eval()
ThisBindingへの直接呼び出しによるものは変更されません。これは、呼び出し元の実行コンテキストのThisBindingと同じ値です(§10.4.2(2)(a))。…
eval()
ThisBindingを直接呼び出さない場合は、最初のグローバル実行コンテキストで実行されているかのようにグローバルオブジェクトに設定されます(§10.4.2(1))。
§15.1.2.1.1は、直接の呼び出しが何であるかを定義しますeval()
。基本的に、eval(...)
は直接呼び出しですが、(0, eval)(...)
またはのようなものvar indirectEval = eval; indirectEval(...);
はへの間接呼び出しeval()
です。JavaScriptの(1、eval)( 'this')vs eval( 'this')に対するchuckjの答えを参照してください。とドミトリーソシュニコフのECMA-262-5の詳細。第2章厳密モード。間接eval()
呼び出しを使用する可能性がある場合。
3.機能コードの入力
これは、関数を呼び出すときに発生します。inobj.myMethod()
または同等のオブジェクトなどで関数が呼び出されるとobj["myMethod"]()
、ThisBindingがオブジェクトに設定されます(obj
例では、§13.2.1)。他のほとんどの場合、ThisBindingはグローバルオブジェクトに設定されます(§10.4.3)。
「他のほとんどの場合」と書く理由は、ThisBindingを引数リストで指定できるようにする8つのECMAScript5組み込み関数があるためです。これらの特別な関数は、関数を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
、ライブラリは、を受け入れる組み込みのJavaScript関数の1つを使用しているだけthisArg
です。あなたも、コールバック関数を使って独自の関数を書くことができます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
矢印関数が定義されている環境内の値を参照します。
楽しみのために、いくつかの例であなたの理解をテストしてください
答えを表示するには、薄い灰色のボックスにマウスを合わせます。
this
マークされた行の値は何ですか?どうして?
window
—マークされた行は、最初のグローバル実行コンテキストで評価されます。
if (true) {
// What is `this` here?
}
- が実行された
this
ときのマークされた行の値は何obj.staticFunction()
ですか?どうして?
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);
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);
this
マークされた行の値は何ですか?どうして?
window
これはトリッキーでした。評価コードを評価する場合、
this
はobj
です。ただし、evalコードでmyFun
は、はオブジェクトで呼び出されないため、ThisBindingはwindow
呼び出しに対してに設定されます。
<!-- no snippet because, seemingly, eval doesn’t work in snippets -->
function myFun() {
return this; // What is `this` here?
}
var obj = {
myMethod: function () {
eval("myFun()");
}
};
this
マークされた行の値は何ですか?どうして?
obj
この行
myFun.call(obj);
は、最初の引数としてFunction.prototype.call()
受け入れる特別な組み込み関数を呼び出していthisArg
ます。
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);
this
異なっJavaScriptでキーワード振る舞いは他の言語と比較します。オブジェクト指向言語では、this
キーワードはクラスの現在のインスタンスを参照します。JavaScriptでは、の値はthis
関数(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
ます。それらを指定します。 - オブジェクトリテラル表記は、すぐに使用できるオブジェクトのインスタンスを作成します。関数では、最初に
new
演算子を使用してインスタンスを作成する必要がある場合があります。 - また、オブジェクトリテラルのアプローチでは、ドット演算子を使用して、定義済みのオブジェクトにメンバーを明示的に追加できます。これは特定のインスタンスにのみ追加されます。ただし、関数のすべてのインスタンスに反映されるように、関数プロトタイプに変数を追加しました。
以下では、Objectthis
以上で行ったすべてのことを試しましたが、オブジェクトを直接書き込むのではなく、最初に関数を作成しました。
/*********************************************************************
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
ます。 - これらのメソッドを使用すると、関数を1回記述して、別のコンテキストで呼び出すことができます。つまり、
this
関数の実行中に使用される値を指定できます。また、呼び出されたときに元の関数に渡されるパラメーターも受け取ります。 fun.apply(obj1 [, argsArray])
insideobj1
の値として設定し、引数としての受け渡し要素を呼び出します。this
fun()
fun()
argsArray
fun.call(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]])
-設定obj1
の値として、this
内部fun()
および通話fun()
渡すarg1, arg2, arg3, ...
引数として。fun.bind(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]])
-指定されたパラメーターにバインドされたinsidefunとバインドされたパラメーターをfun
持つ関数への参照を返します。this
obj1
fun
arg1, arg2, arg3,...
- ここまでで
apply
、call
とのbind
違いが明らかになったに違いありません。apply
配列のようなオブジェクト、つまり数値length
プロパティと対応する非負の整数プロパティを持つオブジェクトとして機能する引数を指定できます。一方call
、関数への引数を直接指定することができます。とは両方とも、指定されたコンテキストで指定された引数を使用して関数apply
をcall
すぐに呼び出します。一方、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
。 - 同様に、要素の
this
イベントプロパティ(など<button onclick="...this..." >
)内で直接使用すると、要素を参照します。 - ただし
this
、イベント処理関数またはイベントプロパティ内で呼び出される他の関数を介して間接的に使用すると、グローバルオブジェクトに解決されますwindow
。 - Microsoftのイベント登録モデルメソッドを使用して関数をイベントハンドラーにアタッチすると、上記と同じ動作が実現され
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>
8. this
ES6矢印機能で
矢印関数でthis
は、は一般的な変数のように動作します。字句スコープから継承されます。関数のthis
矢印関数が定義され、矢印機能のだろうthis
。
つまり、これは次と同じ動作です。
(function(){}).bind(this)
次のコードを参照してください。
const globalArrowFunction = () => {
return this;
};
console.log(globalArrowFunction()); //window
const contextObject = {
method1: () => {return this},
method2: function(){
return () => {return this};
}
};
console.log(contextObject.method1()); //window
const contextLessFunction = contextObject.method1;
console.log(contextLessFunction()); //window
console.log(contextObject.method2()()) //contextObject
const innerArrowFunction = contextObject.method2();
console.log(innerArrowFunction()); //contextObject
Javascriptの this
単純な関数呼び出し
次の関数について考えてみます。
function foo() {
console.log("bar");
console.log(this);
}
foo(); // calling the function
Note that we are running this in the normal mode, i.e. strict mode is not used.
When running in a browser, the value of this
would be logged as window
. This is because window
is the global variable in a web browser's scope.
If you run this same piece of code in an environment like node.js, this
would refer to the global variable in your app.
Now if we run this in strict mode by adding the statement "use strict";
to the beginning of the function declaration, this
would no longer refer to the global variable in either of the environments. This is done to avoid confusions in strict mode. this
would, in this case just log undefined
, because that is what it is, it is not defined.
In the following cases, we would see how to manipulate the value of this
.
Calling a function on an object
There are different ways to do this. If you have called native methods in Javascript like forEach
and slice
, you should already know that the this
variable in that case refers to the Object
on which you called that function (Note that in javascript, just about everything is an Object
, including Array
s and Function
s). Take the following code for example.
var myObj = {key: "Obj"};
myObj.logThis = function () {
// I am a method
console.log(this);
}
myObj.logThis(); // myObj is logged
If an Object
contains a property which holds a Function
, the property is called a method. This method, when called, will always have it's this
variable set to the Object
it is associated with. This is true for both strict and non-strict modes.
Note that if a method is stored (or rather, copied) in another variable, the reference to this
is no longer preserved in the new variable. For example:
// continuing with the previous code snippet
var myVar = myObj.logThis;
myVar();
// logs either of window/global/undefined based on mode of operation
Considering a more commonly practical scenario:
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
The new
keyword
Consider a constructor function in 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`
How does this work? Well, let's see what happens when we use the new
keyword.
- Calling the function with the
new
keyword would immediately initialize anObject
of typePerson
. - The constructor of this
Object
has its constructor set toPerson
. Also, note thattypeof awal
would returnObject
only. - This new
Object
would be assigned the prototype ofPerson.prototype
. This means that any method or property in thePerson
prototype would be available to all instances ofPerson
, includingawal
. - The function
Person
itself is now invoked;this
being a reference to the newly constructed objectawal
.
Pretty straightforward, eh?
Note that the official ECMAScript spec nowhere states that such types of functions are actual constructor
functions. They are just normal functions, and new
can be used on any function. It's just that we use them as such, and so we call them as such only.
Calling functions on Functions: call
and apply
So yeah, since function
s are also Objects
(and in-fact first class variables in Javascript), even functions have methods which are... well, functions themselves.
All functions inherit from the global Function
, and two of its many methods are call
and apply
, and both can be used to manipulate the value of this
in the function on which they are called.
function foo () { console.log (this, arguments); }
var thisArg = {myObj: "is cool"};
foo.call(thisArg, 1, 2, 3);
This is a typical example of using call
. It basically takes the first parameter and sets this
in the function foo
as a reference to thisArg
. All other parameters passed to call
is passed to the function foo
as arguments.
So the above code will log {myObj: "is cool"}, [1, 2, 3]
in the console. Pretty nice way to change the value of this
in any function.
apply
is almost the same as call
accept that it takes only two parameters: thisArg
and an array which contains the arguments to be passed to the function. So the above call
call can be translated to apply
like this:
foo.apply(thisArg, [1,2,3])
Note that call
and apply
can override the value of this
set by dot method invocation we discussed in the second bullet. Simple enough :)
Presenting.... bind
!
bind
is a brother of call
and apply
. It is also a method inherited by all functions from the global Function
constructor in Javascript. The difference between bind
and call
/apply
is that both call
and apply
will actually invoke the function. bind
, on the other hand, returns a new function with the thisArg
and arguments
pre-set. Let's take an example to better understand this:
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]`
See the difference between the three? It is subtle, but they are used differently. Like call
and apply
, bind
will also over-ride the value of this
set by dot-method invocation.
Also note that neither of these three functions do any change to the original function. call
and apply
would return the value from freshly constructed functions while bind
will return the freshly constructed function itself, ready to be called.
Extra stuff, copy this
Sometimes, you don't like the fact that this
changes with scope, especially nested scope. Take a look at the following example.
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"
});
}
};
In the above code, we see that the value of this
changed with the nested scope, but we wanted the value of this
from the original scope. So we 'copied' this
to that
and used the copy instead of this
. Clever, eh?
Index:
- What is held in
this
by default? - What if we call the function as a method with Object-dot notation?
- What if we use the
new
keyword? - How do we manipulate
this
withcall
andapply
? - Using
bind
. - Copying
this
to solve nested-scope issues.
"this" is all about scope. Every function has its own scope, and since everything in JS is an object, even a function can store some values into itself using "this". OOP 101 teaches that "this" is only applicable to instances of an object. Therefore, every-time a function executes, a new "instance" of that function has a new meaning of "this".
Most people get confused when they try to use "this" inside of anonymous closure functions like:
(function(value) { this.value = value; $('.some-elements').each(function(elt){ elt.innerHTML = this.value; // uh oh!! possibly undefined }); })(2);
So here, inside each(), "this" doesn't hold the "value" that you expect it to (from
this.value = value;above it). So, to get over this (no pun intended) problem, a developer could:
(function(value) { var self = this; // small change self.value = value; $('.some-elements').each(function(elt){ elt.innerHTML = self.value; // phew!! == 2 }); })(2);
Try it out; you'll begin to like this pattern of programming
Since this thread has bumped up, I have compiled few points for readers new to this
topic.
How is the value of this
determined?
We use this similar to the way we use pronouns in natural languages like English: “John is running fast because he is trying to catch the train.” Instead we could have written “… John is trying to catch the train”.
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);
}
}
this
is not assigned a value until an object invokes the function where it is defined. In the global scope, all global variables and functions are defined on the window
object. Therefore, this
in a global function refers to (and has the value of) the global window
object.
When use strict
, this
in global and in anonymous functions that are not bound to any object holds a value of undefined
.
The this
keyword is most misunderstood when: 1) we borrow a method that uses this
, 2) we assign a method that uses this
to a variable, 3) a function that uses this
is passed as a callback function, and 4) this
is used inside a closure — an inner function. (2)
What holds the future
Defined in ECMA Script 6, arrow-functions adopt the this
binding from the enclosing (function or global) scope.
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!
While arrow-functions provide an alternative to using bind()
, it’s important to note that they essentially are disabling the traditional this
mechanism in favor of more widely understood lexical scoping. (1)
References:
- this & Object Prototypes, by Kyle Simpson. © 2014 Getify Solutions.
- javascriptissexy.com - http://goo.gl/pvl0GX
- Angus Croll - http://goo.gl/Z2RacU
this
in JavaScript always refers to the 'owner' of the function that is being executed.
If no explicit owner is defined, then the top most owner, the window object, is referenced.
So if I did
function someKindOfFunction() {
this.style = 'foo';
}
element.onclick = someKindOfFunction;
this
would refer to the element object. But be careful, a lot of people make this mistake.
<element onclick="someKindOfFunction()">
In the latter case, you merely reference the function, not hand it over to the element. Therefore, this
will refer to the window object.
Every execution context in javascript has a this parameter that is set by:
- How the function is called (including as an object method, use of call and apply, use of new)
- Use of bind
- Lexically for arrow functions (they adopt the this of their outer execution context)
- Whether the code is in strict or non-strict mode
- Whether the code was invoked using eval
You can set the value of this using func.call
, func.apply
or func.bind
.
By default, and what confuses most beginners, when a listener is called after an event is raised on a DOM element, the this value of the function is the DOM element.
jQuery makes this trivial to change with jQuery.proxy.
Daniel, awesome explanation! A couple of words on this and good list of this
execution context pointer in case of event handlers.
In two words, this
in JavaScript points the object from whom (or from whose execution context) the current function was run and it's always read-only, you can't set it anyway (such an attempt will end up with 'Invalid left-hand side in assignment' message.
For event handlers: inline event handlers, such as <element onclick="foo">
, override any other handlers attached earlier and before, so be careful and it's better to stay off of inline event delegation at all. And thanks to Zara Alaverdyan who inspired me to this list of examples through a dissenting debate :)
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)">
Here is one good source of this
in JavaScript
.
Here is the summary:
global this
In a browser, at the global scope,
this
is thewindow
object<script type="text/javascript"> console.log(this === window); // true var foo = "bar"; console.log(this.foo); // "bar" console.log(window.foo); // "bar"
In
node
using the repl,this
is the top namespace. You can refer to it asglobal
.>this { ArrayBuffer: [Function: ArrayBuffer], Int8Array: { [Function: Int8Array] BYTES_PER_ELEMENT: 1 }, Uint8Array: { [Function: Uint8Array] BYTES_PER_ELEMENT: 1 }, ... >global === this true
In
node
executing from a script,this
at the global scope starts as an empty object. It is not the same asglobal
\\test.js console.log(this); \\ {} console.log(this === global); \\ fasle
function this
Except in the case of DOM event handlers or when a thisArg
is provided (see further down), both in node and in a browser using this
in a function that is not called with new
references the global scope…
<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>
If you use use strict;
, in which case this
will be undefined
<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>
If you call a function with new
the this
will be a new context, it will not reference the global 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 this
Functions you create become function objects. They automatically get a special prototype
property, which is something you can assign values to. When you create an instance by calling your function with new
you get access to the values you assigned to the prototype
property. You access those values using this
.
function Thing() {
console.log(this.foo);
}
Thing.prototype.foo = "bar";
var thing = new Thing(); //logs "bar"
console.log(thing.foo); //logs "bar"
It is usually a mistake to assign arrays or objects on the prototype
. If you want instances to each have their own arrays, create them in the function, not the 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
You can use this
in any function on an object to refer to other properties on that object. This is not the same as an instance created with new
.
var obj = {
foo: "bar",
logFoo: function () {
console.log(this.foo);
}
};
obj.logFoo(); //logs "bar"
- DOM event this
In an HTML DOM event handler, this
is always a reference to the DOM element the event was attached to
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();
Unless you bind
the context
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
Inside HTML attributes in which you can put JavaScript, this
is a reference to the element.
<div id="foo" onclick="console.log(this);"></div>
<script type="text/javascript">
document.getElementById("foo").click(); //logs <div id="foo"...
</script>
- eval this
You can use eval
to access 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
You can use with
to add this
to the current scope to read and write to values on this
without referring to this
explicitly.
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
the jQuery will in many places have this
refer to a DOM element.
<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>
There is a lot of confusion regarding how "this" keyword is interpreted in JavaScript. Hopefully this article will lay all those to rest once and for all. And a lot more. Please read the entire article carefully. Be forewarned that this article is long.
Irrespective of the context in which it is used, "this" always references the "current object" in Javascript. However, what the "current object" is differs according to context. The context may be exactly 1 of the 6 following:
- Global (i.e. Outside all functions)
- Inside Direct "Non Bound Function" Call (i.e. a function that has not been bound by calling functionName.bind)
- Inside Indirect "Non Bound Function" Call through functionName.call and functionName.apply
- Inside "Bound Function" Call (i.e. a function that has been bound by calling functionName.bind)
- While Object Creation through "new"
- Inside Inline DOM event handler
The following describes each of this contexts one by one:
Global Context (i.e. Outside all functions):
Outside all functions (i.e. in global context) the "current object" (and hence the value of "this") is always the "window" object for browsers.
Inside Direct "Non Bound Function" Call:
Inside a Direct "Non Bound Function" Call, the object that invoked the function call becomes the "current object" (and hence the value of "this"). If a function is called without a explicit current object, the current object is either the "window" object (For Non Strict Mode) or undefined (For Strict Mode) . Any function (or variable) defined in Global Context automatically becomes a property of the "window" object.For e.g Suppose function is defined in Global Context as
function UserDefinedFunction(){ alert(this) }
it becomes the property of the window object, as if you have defined it as
window.UserDefinedFunction=function(){ alert(this) }
In "Non Strict Mode", Calling/Invoking this function directly through "UserDefinedFunction()" will automatically call/invoke it as "window.UserDefinedFunction()" making "window" as the "current object" (and hence the value of "this") within "UserDefinedFunction".Invoking this function in "Non Strict Mode" will result in the following
UserDefinedFunction() // displays [object Window] as it automatically gets invoked as window.UserDefinedFunction()
In "Strict Mode", Calling/Invoking the function directly through "UserDefinedFunction()" will "NOT" automatically call/invoke it as "window.UserDefinedFunction()".Hence the "current object" (and the value of "this") within "UserDefinedFunction" shall be undefined. Invoking this function in "Strict Mode" will result in the following
UserDefinedFunction() // displays undefined
However, invoking it explicitly using window object shall result in the following
window.UserDefinedFunction() // "always displays [object Window] irrespective of mode."
Let us look at another example. Please look at the following code
function UserDefinedFunction() { alert(this.a + "," + this.b + "," + this.c + "," + this.d) } var o1={ a:1, b:2, f:UserDefinedFunction } var o2={ c:3, d:4, f:UserDefinedFunction } o1.f() // Shall display 1,2,undefined,undefined o2.f() // Shall display undefined,undefined,3,4
In the above example we see that when "UserDefinedFunction" was invoked through o1, "this" takes value of o1 and the value of its properties "a" and "b" get displayed. The value of "c" and "d" were shown as undefined as o1 does not define these properties
Similarly when "UserDefinedFunction" was invoked through o2, "this" takes value of o2 and the value of its properties "c" and "d" get displayed.The value of "a" and "b" were shown as undefined as o2 does not define these properties.
Inside Indirect "Non Bound Function" Call through functionName.call and functionName.apply:
When a "Non Bound Function" is called through functionName.call or functionName.apply, the "current object" (and hence the value of "this") is set to the value of "this" parameter (first parameter) passed to call/apply. The following code demonstrates the same.
function UserDefinedFunction() { alert(this.a + "," + this.b + "," + this.c + "," + this.d) } var o1={ a:1, b:2, f:UserDefinedFunction } var o2={ c:3, d:4, f:UserDefinedFunction } UserDefinedFunction.call(o1) // Shall display 1,2,undefined,undefined UserDefinedFunction.apply(o1) // Shall display 1,2,undefined,undefined UserDefinedFunction.call(o2) // Shall display undefined,undefined,3,4 UserDefinedFunction.apply(o2) // Shall display undefined,undefined,3,4 o1.f.call(o2) // Shall display undefined,undefined,3,4 o1.f.apply(o2) // Shall display undefined,undefined,3,4 o2.f.call(o1) // Shall display 1,2,undefined,undefined o2.f.apply(o1) // Shall display 1,2,undefined,undefined
The above code clearly shows that the "this" value for any "NON Bound Function" can be altered through call/apply. Also,if the "this" parameter is not explicitly passed to call/apply, "current object" (and hence the value of "this") is set to "window" in Non strict mode and "undefined" in strict mode.
Inside "Bound Function" Call (i.e. a function that has been bound by calling functionName.bind):
A bound function is a function whose "this" value has been fixed. The following code demonstrated how "this" works in case of bound function
function UserDefinedFunction() { alert(this.a + "," + this.b + "," + this.c + "," + this.d) } var o1={ a:1, b:2, f:UserDefinedFunction, bf:null } var o2={ c:3, d:4, f:UserDefinedFunction, bf:null } var bound1=UserDefinedFunction.bind(o1); // permanantly fixes "this" value of function "bound1" to Object o1 bound1() // Shall display 1,2,undefined,undefined var bound2=UserDefinedFunction.bind(o2); // permanantly fixes "this" value of function "bound2" to Object o2 bound2() // Shall display undefined,undefined,3,4 var bound3=o1.f.bind(o2); // permanantly fixes "this" value of function "bound3" to Object o2 bound3() // Shall display undefined,undefined,3,4 var bound4=o2.f.bind(o1); // permanantly fixes "this" value of function "bound4" to Object o1 bound4() // Shall display 1,2,undefined,undefined o1.bf=UserDefinedFunction.bind(o2) // permanantly fixes "this" value of function "o1.bf" to Object o2 o1.bf() // Shall display undefined,undefined,3,4 o2.bf=UserDefinedFunction.bind(o1) // permanantly fixes "this" value of function "o2.bf" to Object o1 o2.bf() // Shall display 1,2,undefined,undefined bound1.call(o2) // Shall still display 1,2,undefined,undefined. "call" cannot alter the value of "this" for bound function bound1.apply(o2) // Shall still display 1,2,undefined,undefined. "apply" cannot alter the value of "this" for bound function o2.bf.call(o2) // Shall still display 1,2,undefined,undefined. "call" cannot alter the value of "this" for bound function o2.bf.apply(o2) // Shall still display 1,2,undefined,undefined."apply" cannot alter the value of "this" for bound function
As given in the code above, "this" value for any "Bound Function" CANNOT be altered through call/apply. Also, if the "this" parameter is not explicitly passed to bind, "current object" (and hence the value of "this" ) is set to "window" in Non strict mode and "undefined" in strict mode. One more thing. Binding an already bound function does not change the value of "this". It remains set as the value set by first bind function.
While Object Creation through "new":
Inside a constructor function, the "current object" (and hence the value of "this") references the object that is currently being created through "new" irrespective of the bind status of the function. However if the constructor is a bound function it shall get called with predefined set of arguments as set for the bound function.
Inside Inline DOM event handler:
Please look at the following HTML Snippet
<button onclick='this.style.color=white'>Hello World</button> <div style='width:100px;height:100px;' onclick='OnDivClick(event,this)'>Hello World</div>
The "this" in above examples refer to "button" element and the "div" element respectively.
In the first example, the font color of the button shall be set to white when it is clicked.
In the second example when the "div" element is clicked it shall call the OnDivClick function with its second parameter referencing the clicked div element. However the value of "this" within OnDivClick SHALL NOT reference the clicked div element. It shall be set as the "window object" or "undefined" in Non strict and Strict Modes respectively (if OnDivClick is an unbound function) or set to a predefined Bound value (if OnDivClick is a bound function)
The following summarizes the entire article
In Global Context "this" always refers to the "window" object
Whenever a function is invoked, it is invoked in context of an object ("current object"). If the current object is not explicitly provided, the current object is the "window object" in NON Strict Mode and "undefined" in Strict Mode by default.
The value of "this" within a Non Bound function is the reference to object in context of which the function is invoked ("current object")
The value of "this" within a Non Bound function can be overriden by call and apply methods of the function.
The value of "this" is fixed for a Bound function and cannot be overriden by call and apply methods of the function.
Binding and already bound function does not change the value of "this". It remains set as the value set by first bind function.
The value of "this" within a constructor is the object that is being created and initialized
The value of "this" within an inline DOM event handler is reference to the element for which the event handler is given.
Probably the most detailed and comprehensive article on this
is the following:
Gentle explanation of 'this' keyword in JavaScript
The idea behind this
is to understand that the function invocation types have the significant importance on setting this
value.
When having troubles identifying this
, do not ask yourself:
Where is
this
taken from?
but do ask yourself:
How is the function invoked?
For an arrow function (special case of context transparency) ask yourself:
What value has
this
where the arrow function is defined?
This mindset is correct when dealing with this
and will save you from headache.
This is the best explanation I've seen: Understand JavaScripts this with Clarity
The this reference ALWAYS refers to (and holds the value of) an object—a singular object—and it is usually used inside a function or a method, although it can be used outside a function in the global scope. Note that when we use strict mode, this holds the value of undefined in global functions and in anonymous functions that are not bound to any object.
There are Four Scenarios where this can be confusing:
- When we pass a method (that uses this) as an argument to be used as a callback function.
- When we use an inner function (a closure). It is important to take note that closures cannot access the outer function’s this variable by using the this keyword because the this variable is accessible only by the function itself, not by inner functions.
- When a method which relies on this is assigned to a variable across contexts, in which case this references another object than originally intended.
- When using this along with the bind, apply, and call methods.
He gives code examples, explanations, and solutions, which I thought was very helpful.
this
is one of the misunderstood concept in JavaScript because it behaves little differently from place to place. Simply, this
refers to the "owner" of the function we are currently executing.
this
helps to get the current object (a.k.a. execution context) we work with. If you understand in which object the current function is getting executed, you can understand easily what current this
is
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
Above we create 3 variables with same name 'val'. One in global context, one inside obj and the other inside innerMethod of obj. JavaScript resolves identifiers within a particular context by going up the scope chain from local go global.
Few places where this
can be differentiated
Calling a method of a object
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
When line1 is executed, JavaScript establishes an execution context (EC) for the function call, setting this
to the object referenced by whatever came before the last ".". so in the last line you can understand that a()
was executed in the global context which is the window
.
With Constructor
this
can be used to refer to the object being created
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
When new Person()
is executed, a completely new object is created. Person
is called and its this
is set to reference that new object.
Function call
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
If we miss new
keyword, whatIsThis
referes to the most global context it can find(window
)
With event handlers
If the event handler is inline, this
refers to global object
<script type="application/javascript">
function click_handler() {
alert(this); // alerts the window object
}
</script>
<button id='thebutton' onclick='click_handler()'>Click me!</button>
When adding event handler through JavaScript, this
refers to DOM element that generated the event.
- You can also manipulate the context using
.apply()
.call()
and.bind()
- JQuery proxy is another way you can use to make sure this in a function will be the value you desire. (Check Understanding $.proxy(), jQuery.proxy() usage)
- What does var that = this means in JavaScript
In pseudoclassical terms, the way many lectures teach the 'this' keyword is as an object instantiated by a class or object constructor. Each time a new object is constructed from a class, imagine that under the hood a local instance of a 'this' object is created and returned. I remember it taught like 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;
The value of "this" depends on the "context" in which the function is executed. The context can be any object or the global object, i.e., window.
So the Semantic of "this" is different from the traditional OOP languages. And it causes problems: 1. when a function is passed to another variable (most likely, a callback); and 2. when a closure is invoked from a member method of a class.
In both cases, this is set to window.
Whould this help? (Most confusion of 'this' in javascript is coming from the fact that it generally is not linked to your object, but to the current executing scope -- that might not be exactly how it works but is always feels like that to me -- see the article for a complete explanation)
A little bit info about this keyword
Let's log this
keyword to the console in global scope without any more code but
console.log(this)
In Client/Browser this
keyword is a global object which is window
console.log(this === window) // true
and
In Server/Node/Javascript runtime this
keyword is also a global object which is module.exports
console.log(this === module.exports) // true
console.log(this === exports) // true
Keep in mind exports
is just a reference to module.exports
this use for Scope just like this
<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>
value of txt1 and txt is same in Above example $(this)=$('#tbleName tbody tr') is Same
I have a different take on this
from the other answers that I hope is helpful.
One way to look at JavaScript is to see that there are only 1 way to call a function1. It is
functionObject.call(objectForThis, arg0, arg1, arg2, ...);
There is always some value supplied for objectForThis
.
Everything else is syntactic sugar for functionObject.call
So, everything else can be described by how it translates into functionObject.call
.
If you just call a function then this
is the "global object" which in the browser is the window
function foo() {
console.log(this);
}
foo(); // this is the window object
In other words,
foo();
was effectively translated into
foo.call(window);
Note that if you use strict mode then this
will be undefined
'use strict';
function foo() {
console.log(this);
}
foo(); // this is the window object
which means
In other words,
foo();
was effectively translated into
foo.call(undefined);
In JavaScript there are operators like +
and -
and *
. There is also the dot operator which is .
The .
operator when used with a function on the right and an object on the left effectively means "pass object as this
to function.
Example
const bar = {
name: 'bar',
foo() {
console.log(this);
},
};
bar.foo(); // this is bar
In other words bar.foo()
translates into const temp = bar.foo; temp.call(bar);
Note that it doesn't matter how the function was created (mostly...). All of these will produce the same results
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
Again these all are just syntactic sugar for
{ const temp = bar.fn1; temp.call(bar); }
{ const temp = bar.fn2; temp.call(bar); }
{ const temp = bar.fn3; temp.call(bar); }
One other wrinkle is the prototype chain. When you use a.b
JavaScript first looks on the object referenced directly by a
for the property b
. If b
is not found on the object then JavaScript will look in the object's prototype to find b
.
There are various ways to define an object's prototype, the most common in 2019 is the class
keyword. For the purposes of this
though it doesn't matter. What matters is that as it looks in object a
for property b
if it finds property b
on the object or in it's prototype chain if b
ends up being a function then the same rules as above apply. The function b
references will be called using the call
method and passing a
as objectForThis as shown a the top of this answer.
Now. Let's imagine we make a function that explicitly sets this
before calling another function and then call it with the .
(dot) operator
function foo() {
console.log(this);
}
function bar() {
const objectForThis = {name: 'moo'}
foo.call(objectForThis); // explicitly passing objectForThis
}
const obj = {
bar,
};
obj.bar();
Following the translation to use call
, obj.bar()
becomes const temp = obj.bar; temp.call(obj);
. When we enter the bar
function we call foo
but we explicitly passed in another object for objectForThis so when we arrive at foo this
is that inner object.
This is what both bind
and =>
functions effectively do. They are more syntactic sugar. They effectively build a new invisible function exactly like bar
above that explicitly sets this
before it calls whatever function is specified. In the case of bind this
is set to whatever you pass to bind
.
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'});
Note that if functionObject.bind
did not exist we could make our own like this
function bind(fn, objectForThis) {
return function(...args) {
return fn.call(objectForthis, ...args);
};
}
and then we could call it like this
function foo() {
console.log(this);
}
const bar = bind(foo, {name:'abc'});
Arrow functions, the =>
operator are syntactic sugar for bind
const a = () => {console.log(this)};
is the same as
const tempFn = function() {console.log(this)};
const a = tempFn.bind(this);
Just like bind
, a new invisible function is created that calls the given function with a bound value for objectForThis
but unlike bind
the object to be bound is implicit. It's whatever this
happens to be when the =>
operator is used.
So, just like the rules above
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()
translates to const temp = obj.foo; temp.call(obj);
which means the arrow operator inside foo
will bind obj
to a new invisible function and return that new invisible function which is assigned to b
. b()
will work as it always has as b.call(window)
or b.call(undefined)
calling the new invisible function that foo
created. That invisible function ignores the this
passed into it and passes obj
as objectForThis` to the arrow function.
The code above translates to
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);
1apply
is another function similar to call
functionName.apply(objectForThis, arrayOfArgs);
But as of ES6 conceptually you can even translate that into
functionName.call(objectForThis, ...arrayOfArgs);
Summary this
Javascript:
- The value of
this
is determined by how the function is invoked not, where it was created! - Usually the value of
this
is determined by the Object which is left of the dot. (window
in global space) - In event listeners the value of
this
refers to the DOM element on which the event was called. - When in function is called with the
new
keyword the value ofthis
refers to the newly created object - You can manipulate the value of
this
with the functions:call
,apply
,bind
Example:
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
Example event listeners:
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>
Example constructor:
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.
To understand "this" properly one must understand the context and scope and difference between them.
Scope: In javascript scope is related to the visibility of the variables, scope achieves through the use of the function. (Read more about scope)
Context: Context is related to objects. It refers to the object to which a function belongs. When you use the JavaScript “this” keyword, it refers to the object to which function belongs. For example, inside of a function, when you say: “this.accoutNumber”, you are referring to the property “accoutNumber”, that belongs to the object to which that function belongs.
If the object “myObj” has a method called “getMyName”, when the JavaScript keyword “this” is used inside of “getMyName”, it refers to “myObj”. If the function “getMyName” were executed in the global scope, then “this” refers to the window object (except in strict mode).
Now let's see some example:
<script>
console.log('What is this: '+this);
console.log(this);
</script>
Runnig abobve code in browser output will:
According to the output you are inside of the context of the window object, it is also visible that window prototype refers to the Object.
Now let's try inside of a function:
<script>
function myFunc(){
console.log('What is this: '+this);
console.log(this);
}
myFunc();
</script>
Output:
Now let's create our own object. In javascript, you can create an object in many ways.
<script>
var firstName = "Nora";
var lastName = "Zaman";
var myObj = {
firstName:"Lord",
lastName:'Baron',
printNameGetContext:function(){
console.log(firstName + " "+lastName);
console.log(this.firstName +" "+this.lastName);
return this;
}
}
var context = myObj.printNameGetContext();
console.log(context);
</script>
Output:
So from the above example, we found that 'this' keyword is referring to a new context that is related to myObj, and myObject also has prototype chain to Object.
Let's go throw another example:
<body>
<button class="btn">Click Me</button>
<script>
function printMe(){
//Terminal2: this function declared inside window context so this function belongs to the window object.
console.log(this);
}
document.querySelector('.btn').addEventListener('click', function(){
//Terminal1: button context, this callback function belongs to DOM element
console.log(this);
printMe();
})
</script>
</body>
output: Make sense right? (read comments)
If you having trouble to understand the above example let's try with our own callback;
<script>
var myObj = {
firstName:"Lord",
lastName:'Baron',
printName:function(callback1, callback2){
//Attaching callback1 with this myObj context
this.callback1 = callback1;
this.callback1(this.firstName +" "+this.lastName)
//We did not attached callback2 with myObj so, it's reamin with window context by default
callback2();
/*
//test bellow codes
this.callback2 = callback2;
this.callback2();
*/
}
}
var callback2 = function (){
console.log(this);
}
myObj.printName(function(data){
console.log(data);
console.log(this);
}, callback2);
</script>
output:
Now let's Understand Scope, Self, IIFE and THIS how behaves
var color = 'red'; // property of window
var obj = {
color:'blue', // property of window
printColor: function(){ // property of obj, attached with obj
var self = this;
console.log('In printColor -- this.color: '+this.color);
console.log('In printColor -- self.color: '+self.color);
(function(){ // decleard inside of printColor but not property of object, it will executed on window context.
console.log(this)
console.log('In IIFE -- this.color: '+this.color);
console.log('In IIFE -- self.color: '+self.color);
})();
function nestedFunc(){// decleard inside of printColor but not property of object, it will executed on window context.
console.log('nested fun -- this.color: '+this.color);
console.log('nested fun -- self.color: '+self.color);
}
nestedFunc(); // executed on window context
return nestedFunc;
}
};
obj.printColor()(); // returned function executed on window context
</script>
Output is pretty awesome right?