Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>I recommend reading <a href="https://mikewest.org" rel="noreferrer">Mike West</a>'s article <a href="http://www.digital-web.com/articles/scope_in_javascript/" rel="noreferrer">Scope in JavaScript</a> (<a href="http://web.archive.org/web/20110725013125/http://www.digital-web.com/articles/scope_in_javascript/" rel="noreferrer">mirror</a>) first. It is an excellent, friendly introduction to the concepts of <code>this</code> and scope chains in JavaScript.</p> <p>Once you start getting used to <code>this</code>, the rules are actually pretty simple. The <a href="https://ecma-international.org/ecma-262/5.1" rel="noreferrer">ECMAScript 5.1 Standard</a> defines <code>this</code>:</p> <blockquote> <h3><a href="https://ecma-international.org/ecma-262/5.1/#sec-11.1.1" rel="noreferrer">§11.1.1</a> The <code>this</code> keyword</h3> <p>The <code>this</code> keyword evaluates to the value of the ThisBinding of the current execution context</p> </blockquote> <p>ThisBinding is something that the JavaScript interpreter maintains as it evaluates JavaScript code, like a special CPU register which holds a reference to an object. The interpreter updates the ThisBinding whenever establishing an execution context in one of only three different cases:</p> <h3>1. Initial global execution context</h3> <p>This is the case for JavaScript code that is evaluated at the top-level, e.g. when directly inside a <code>&lt;script&gt;</code>:</p> <pre><code>&lt;script&gt; alert("I'm evaluated in the initial global execution context!"); setTimeout(function () { alert("I'm NOT evaluated in the initial global execution context."); }, 1); &lt;/script&gt; </code></pre> <p>When evaluating code in the initial global execution context, ThisBinding is set to the global object, <code>window</code> (<a href="https://ecma-international.org/ecma-262/5.1/#sec-10.4.1.1" rel="noreferrer">§10.4.1.1</a>).</p> <h3>Entering eval code</h3> <ul> <li><p>…by a direct call to <code>eval()</code> ThisBinding is left unchanged; it is the same value as the ThisBinding of the calling execution context (<a href="https://ecma-international.org/ecma-262/5.1/#sec-10.4.2" rel="noreferrer">§10.4.2</a> (2)(a)).</p></li> <li><p>…if not by a direct call to <code>eval()</code><br> ThisBinding is set to the global object <em>as if</em> executing in the initial global execution context (<a href="https://ecma-international.org/ecma-262/5.1/#sec-10.4.2" rel="noreferrer">§10.4.2</a> (1)).</p></li> </ul> <p>§15.1.2.1.1 defines what a direct call to <code>eval()</code> is. Basically, <code>eval(...)</code> is a direct call whereas something like <code>(0, eval)(...)</code> or <code>var indirectEval = eval; indirectEval(...);</code> is an indirect call to <code>eval()</code>. See <a href="https://stackoverflow.com/a/9107491/196844">chuckj's answer</a> to <a href="https://stackoverflow.com/q/9107240/196844">(1, eval)(&#39;this&#39;) vs eval(&#39;this&#39;) in JavaScript?</a> and <a href="http://dmitrysoshnikov.com/ecmascript/es5-chapter-2-strict-mode/#indirect-eval-call" rel="noreferrer">Dmitry Soshnikov’s ECMA-262-5 in detail. Chapter 2. Strict Mode.</a> for when you might use an indirect <code>eval()</code> call.</p> <h3>Entering function code</h3> <p>This occurs when calling a function. If a function is called on an object, such as in <code>obj.myMethod()</code> or the equivalent <code>obj["myMethod"]()</code>, then ThisBinding is set to the object (<code>obj</code> in the example; <a href="https://ecma-international.org/ecma-262/5.1/#sec-13.2.1" rel="noreferrer">§13.2.1</a>). In most other cases, ThisBinding is set to the global object (<a href="https://ecma-international.org/ecma-262/5.1/#sec-10.4.3" rel="noreferrer">§10.4.3</a>).</p> <p>The reason for writing "in most other cases" is because there are eight ECMAScript 5 built-in functions that allow ThisBinding to be specified in the arguments list. These special functions take a so-called <code>thisArg</code> which becomes the ThisBinding when calling the function (<a href="https://ecma-international.org/ecma-262/5.1/#sec-10.4.3" rel="noreferrer">§10.4.3</a>).</p> <p>These special built-in functions are:</p> <ul> <li><code>Function.prototype.apply( thisArg, argArray )</code></li> <li><code>Function.prototype.call( thisArg [ , arg1 [ , arg2, ... ] ] )</code></li> <li><code>Function.prototype.bind( thisArg [ , arg1 [ , arg2, ... ] ] )</code></li> <li><code>Array.prototype.every( callbackfn [ , thisArg ] )</code></li> <li><code>Array.prototype.some( callbackfn [ , thisArg ] )</code></li> <li><code>Array.prototype.forEach( callbackfn [ , thisArg ] )</code></li> <li><code>Array.prototype.map( callbackfn [ , thisArg ] )</code></li> <li><code>Array.prototype.filter( callbackfn [ , thisArg ] )</code></li> </ul> <p>In the case of the <code>Function.prototype</code> functions, they are called on a function object, but rather than setting ThisBinding to the function object, ThisBinding is set to the <code>thisArg</code>.</p> <p>In the case of the <code>Array.prototype</code> functions, the given <code>callbackfn</code> is called in an execution context where ThisBinding is set to <code>thisArg</code> if supplied; otherwise, to the global object.</p> <p>Those are the rules for plain JavaScript. When you begin using JavaScript libraries (e.g. jQuery), you may find that certain library functions manipulate the value of <code>this</code>. The developers of those JavaScript libraries do this because it tends to support the most common use cases, and users of the library typically find this behavior to be more convenient. When passing callback functions referencing <code>this</code> to library functions, you should refer to the documentation for any guarantees about what the value of <code>this</code> is when the function is called.</p> <p>If you are wondering how a JavaScript library manipulates the value of <code>this</code>, the library is simply using one of the built-in JavaScript functions accepting a <code>thisArg</code>. You, too, can write your own function taking a callback function and <code>thisArg</code>:</p> <pre><code>function doWork(callbackfn, thisArg) { //... if (callbackfn != null) callbackfn.call(thisArg); } </code></pre> <p>There’s a special case I didn’t yet mention. When constructing a new object via the <code>new</code> operator, the JavaScript interpreter creates a new, empty object, sets some internal properties, and then calls the constructor function on the new object. Thus, when a function is called in a constructor context, the value of <code>this</code> is the new object that the interpreter created:</p> <pre><code>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); </code></pre> <h2>Just for fun, test your understanding with some examples</h2> <p><em>To reveal the answers, mouse over the light yellow boxes.</em></p> <ol> <li><p>What is the value of <code>this</code> at the marked line? Why?</p> <blockquote class="spoiler"> <p> <code>window</code> — The marked line is evaluated in the initial global execution context.</p> </blockquote> <pre><code>if (true) { // What is `this` here? } </code></pre></li> <li><p>What is the value of <code>this</code> at the marked line when <code>obj.staticFunction()</code> is executed? Why?</p> <blockquote class="spoiler"> <p> <code>obj</code> — When calling a function on an object, ThisBinding is set to the object.</p> </blockquote> <p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false"> <div class="snippet-code"> <pre class="snippet-code-js lang-js prettyprint-override"><code>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); </code></pre> </div> </div> </p></li> <li><p>What is the value of <code>this</code> at the marked line? Why?</p> <blockquote class="spoiler"> <p> <code>window</code> <p>In this example, the JavaScript interpreter enters function code, but because <code>myFun</code>/<code>obj.myMethod</code> is not called on an object, ThisBinding is set to <code>window</code>. <p>This is different from Python, in which accessing a method (<code>obj.myMethod</code>) creates a <a href="http://docs.python.org/3/library/stdtypes.html#methods" rel="noreferrer">bound method object</a>.</p> </blockquote> <p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false"> <div class="snippet-code"> <pre class="snippet-code-js lang-js prettyprint-override"><code>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); </code></pre> </div> </div> </p></li> <li><p>What is the value of <code>this</code> at the marked line? Why?</p> <blockquote class="spoiler"> <p> <code>window</code> <p>This one was tricky. When evaluating the eval code, <code>this</code> is <code>obj</code>. However, in the eval code, <code>myFun</code> is not called on an object, so ThisBinding is set to <code>window</code> for the call.</p> </blockquote> <pre><code>function myFun() { return this; // What is `this` here? } var obj = { myMethod: function () { eval("myFun()"); } }; </code></pre></li> <li><p>What is the value of <code>this</code> at the marked line? Why?</p> <blockquote class="spoiler"> <p> <code>obj</code> <p>The line <code>myFun.call(obj);</code> is invoking the special built-in function <code>Function.prototype.call()</code>, which accepts <code>thisArg</code> as the first argument.</p> </blockquote> <p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false"> <div class="snippet-code"> <pre class="snippet-code-js lang-js prettyprint-override"><code>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); </code></pre> </div> </div> </p></li> </ol>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload