Understanding the keyword ‘this’ in JavaScript — DeepSeek Blog | Neura Market
    Neura MarketNeura Market/DeepSeek
    ChatGPTChatGPTClaudeClaudeGeminiGeminiCursorCursorGrokGrokPerplexityPerplexityDeepSeekDeepSeek
    CoPilotCoPilotStable DiffusionStable DiffusionMidjourneyMidjourney
    View All Directories
    OverviewRulesPromptsMCPsAgentsBlogVideosGuidesCoursesCommunityTrendingGenerate
    DeepSeekBlogUnderstanding the keyword ‘this’ in JavaScript
    Back to Blog
    Understanding the keyword ‘this’ in JavaScript
    javascript

    Understanding the keyword ‘this’ in JavaScript

    Alan Lins February 2, 2026
    0 views

    Explained in 4 simple rules for better understanding

    --- title: Understanding the keyword ‘this’ in JavaScript published: true description: Explained in 4 simple rules for better understanding tags: javascript, this, karma, jest # cover_image: https://images.unsplash.com/photo-1507652955-f3dcef5a3be5?q=80&w=1470&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D # Use a ratio of 100:42 for best results. # published_at: 2026-02-02 17:11 +0000 canonical_url: "https://alanlins.hashnode.dev/understanding-the-keyword-this-in-javascript" --- ## Introduction The keyword `this` works differently for javascript language. It can change its value depending on how it is called. After facing many issues, I wrote this article explaining how it works with just 4 rules to simplify the understanding and avoid common issues like `undefined method` and calling wrong context. It explains how it works with callback functions, different platforms like nodejs and browser, and how to prevent bugs on testing with tools like jest. ## What is `this`? According to Mozilla, the keyword `this` works like below: > In most cases, the value of this is determined by how a function is called (runtime binding). It can't be set by assignment during execution, and it may be different each time the function is called. The problem below shows the value of `this` is different in two cases ## The problem See the two examples below: 1. using function ```javascript const a = [1,2,3].map(function(n){ return n*this; }, 2); ``` output ```sh [2,4,6] ``` 2. using arrow function ```javascript const b = [1,2,3].map( n => { return n*this; }, 2); ``` output ```sh [NaN,NaN,NaN] ``` This first example returns \[2,4,6\], while the second one, gets \[NaN, NaN, NaN\]. At the end of this article you will understand why they have different results. ## The 4 rules There are 4 rules that helps to understand how the keyword `this` works: * **Rule 1**: Inside a function, `this` refers to a global context(`window` for browser, `global` for nodejs); * **Rule 2**: Inside a method, refers to an object; * **Rule 3**: The value of `this` can be modified by `call` and `apply` functions and also when converts a method to a function and vice-versa; * **Rule 4**: The value of `this` will never change if is in an `arrow function` or a `bind` function, therefore invalidating the rules 1, 2 and 3; ### Rule 1 Within a function, `this` refers to a global object. In a browser, the global object is `windows`, while in NodeJs is `global`. ```javascript function print(){ console.log(this == window); } print() //true ``` Even nested functions refers to a global context ```javascript function print(){ console.log(this == window); function print2(){ console.log(this == window); } print2(); //true } print() //true ``` ### Rule 2 Within a method, `this` refers to an object. The code below `this` refers to object `account`. This applies to object literal, class constructor and function contructor: #### Object literal ```javascript const account = { balance: 100, showBalance: function(value){ console.log(this.balance) } } account.showBalance(); //100 ``` #### Class constructor ```javascript class Account{ constructor(){ this.balance = 100; } showBalance(value){ console.log(this.balance) } } const account = new Account(); account.showBalance(); //100 ``` #### Function constructor ```javascript function Account(){ this.balance = 100; this.showBalance = function(value){ console.log(this.balance) } } const account = new Account(); account.showBalance(); //100 ``` ### Rule 3 The value of `this` can be modified by using `call`, `apply` and converting a method to a function and vice-versa. #### Converting a method to a function The code below has two variables: * the global variable `balance`. Line 1 * the variable `balance` at object account. Line 2 On line 9 is doing `aliasing` which means, converting the `method` showBalance to `function` showBalance. The line 10 is calling a function(Rule 1), then the value of `this` will be global. On line 11, is a method(Rule 2), then it refers to object account. ```javascript var balance = 500; const account = { balance: 100, showBalance: function(value){ console.log(this.balance); } } const showBalance = account.showBalance; //aliasing showBalance(); //500 account.showBalance(); //100 ``` #### Converting a function to a method The opposite way, by assigning a function to a method, has also the same effect: ```javascript var balance = 500; function showBalance(value){ console.log(this.balance); } const account = { balance: 100 } account.showBalance = showBalance; showBalance(); //500 account.showBalance(); //100 ``` #### call and apply Another way to change the value of this is by using `call` or `apply`. The first parameter of call/apply is the value that sets `this`. ```javascript function showBalance(value){ console.log(this.balance); } const account1 = { balance: 100 } const account2 = { balance: 50 } showBalance.call(account1); //100 showBalance.apply(account2); //50 ``` ### Rule 4 The value of `this` will never change if is in an `arrow function` or a `bind` function, therefore invalidating the rules 1, 2 and 3; #### Arrow function As the method `account.showBalance` is a `arrow function`, then the value of `this` will always refer to `account` object, the `showBalance` will always return the same value regardless how it has been called. ```javascript function Account() { this.balance = 100; this.showBalance = () => { console.log(this.balance); }; } const account = new Account(); const showBalance = account.showBalance; account.showBalance(); //100 showBalance(); //100 showBalance.call(); //100 showBalance.apply(); //100 ``` #### bind The same behavior for `bind`. ```javascript function Account() { this.balance = 100; } const account = new Account(); function showBalance(){ console.log(this.balance); } accountShowBalance = showBalance.bind(account); accountShowBalance(); //100 accountShowBalance.call(); //100 accountShowBalance.apply(); //100 showBalance(); //undefined ``` The `accountShowBalance` is a `bind` function, then the `this` refers to `account` object. The `showBalance` is just a normal function, then the `this` value refers to global context, that's why it displayed `undefined`. ## Callback function Depending how a callback function is called and created the `this` will have different values. ### called as a function - Rule 1 See the code below: ```javascript var price = 200; const product = { price: 100, showPrice: function(callback){ callback(); // Rule 1 } } product.showPrice(function(){ console.log(this.price); //200 }); ``` The result will be 200. Why? As the callback has been created as `function` at line 9 and it was called as `function` at line 5, the `this` will refer to `window` that contains the price 200. ### called as a method - Rule 2 ```javascript var price = 200; const product = { price: 100, showPrice: function(callback){ this.callback = callback; // converting to method - Rule 3 this.callback(); // method - Rule 2 } } product.showPrice(function(){ console.log(this.price); }); ``` At the line 5, the callback function is assigned into a method, it is available now by product.callback. At the line 6, as it is been called by `this` which refers `product` object, so the line 11 returns 100. ### callback called by apply/call - Rule 3 The context of `this` of callback can be modified by `apply` or `call`. ```javascript const product2 = { price: 300 } const product = { price: 100, showPrice: function(callback){ callback.apply(product2); //Rule 3 } } product.showPrice(function(){ console.log(this.price); //300 }); ``` At the line 7, the contenxt of `this` is changed to `product2`, then line 12 will return 300. ### callback created by arrow function or bind - Rule 4 If the callback is created by arrow function or bind, the value of `this` never changes. ```javascript var value = 'value from global'; function App(){ this.value = 'value from app'; this.addCallback = function(callback){ this.callback = callback; } this.triggerCallback = function(){ const callback = this.callback; this.callback(); callback(); } } function System(){ this.value = 'value from system'; function callback(){ console.log(this.value); } this.run = function(){ var app = new App(); app.addCallback(()=>{ //Rule 4 console.log(this.value); }); app.triggerCallback(); //value from system //value from system app.addCallback(callback.bind(this)); //Rule 4 app.triggerCallback(); //value from system //value from system app.addCallback(callback); //Rule 3 app.triggerCallback(); //value from app //value from global } } var system = new System(); system.run(); ``` ## Arrow functions The arrow functions will access the enclosing lexical context's `this`, in another words, it will access the `this` from closest constructor function or class that surrounds it. ```javascript function Person(){ //contructor this.name = 'Foo'; const getName = () => { return this.name; } this.show = function(){ console.log(getName()); } } const p = new Person(); p.show(); class PersonClass{ //contructor constructor(){ this.name = 'Foo'; } show(){ const getName = () => { return this.name; } console.log(getName()); } } const pc = new PersonClass(); pc.show(); ``` output ```plaintext foo foo ``` The line 4 declares an arrow function. As it is in the constructor function `Person`, then `this` value will be the instance of `Person`; If a nested arrow function is created, the this' value will still be the same. ```javascript function Person(){ this.name = 'Foo'; const getName = () => { const nestedGetName = () => { return this.name; } return nestedGetName(); } this.show = function(){ console.log(getName()); } } const p = new Person(); p.show(); ``` output ```plaintext foo ``` The arrow function set `this` value from the closest constructor function or class. ```javascript function Person(){ this.name = 'Foo'; const getParentName = () => { return this.name; } function Child(){ this.name = 'bar'; this.surname = ' surname'; const getSurname = ()=>{ return this.surname; } this.getName = () =>{ return this.name+getSurname(); } } var child = new Child(); this.showChild = function(){ console.log(child.getName()); } this.show = function(){ console.log(getParentName()); } } const p = new Person(); p.show(); p.showChild(); ``` Output ```plaintext Foo bar surname ``` The line 4, the variable `getParentName` is inside of `Person` function. When it creates an arrow function, the lexical context is `Person`, so the `this` value belong to `Person` instance. The line 10 and 14 create an arrow function, but the lexical context now is `Child` which is a constructor function as it will be instantiated on line 19. Arrow function won't access object literal's context like a method. ```javascript function Person(){ this.name = 'Parent'; this.child = { name: 'child 1', show: () =>{ console.log(this.name); } } this.child2 = { name: 'child 2', show: function(){ console.log(this.name); } } } var p = new Person(); p.child.show(); p.child2.show(); ``` Output ```plaintext Parent child 2 ``` ## Nested functions On object literal, contructor or classes, the value of `this` refers to the context of the object. ```javascript const person = { //object literal name: 'foo', showName: function(){ console.log(this.name); // this == person }, child: { name: 'bar', showName: function(){ console.log(this.name); // this == child } } } function PersonConstructor(){ //constructor this.name = 'foo'; this.showName = function(){ console.log(this.name); // this == PersonContructor instance } } class PersonClass{ //class constructor(){ this.name = 'foo'; // this == PersonClass instance } showName(){ console.log(this.name); // this == PersonClass instance } } const p = new PersonConstructor(); const p2 = new PersonClass(); person.showName(); person.child.showName(); p.showName(); p2.showName(); ``` Output ```sh foo bar foo foo ``` On line 4, the function showName is assigned inside of `person` object, then its `this` will access the object. On line 6, the `child` is another object literal, then the line 9 `this` will accesss `child` context. After instantiated with keyword `new` on lines 29 and 30, the lines 17 and 26 will access the context of the object instantiate from PersonContructor and PersonClass. ## Value of `this` by platforms The value of `this` is different by plataform (browser or nodejs), strict mode or if is a ES6 module. ### Browser In browser the value of `this` in function(Rule 1) refers to `window`. Look the code below: ```javascript var a = 'world'; window.b = 'hello'; function hello(){ console.log(this.a) console.log(this.b) } hello(); ``` The lines 1 and 2 create global variables `a` and `b`. The individual function `hello` can access the global object by `this`. The lines 5 and 6 prints the `hello` and `world`. ```sh hello world ``` ### Browser with strict mode When the `’use strict’` is added to top of the file or function, the JavaScript stops to defaulting `this` to `window` object. #### Strict mode ```javascript 'use strict' function showThis(){ console.log(this) // output: undefined } hello(); ``` #### Normal mode ```javascript function showThis(){ console.log(this) // output: window } hello(); ``` ### Browser with module ES6 Introduced the "module". It doesn't even have global/window context. So, the code below won't work either. Create a module with the code below: Create the file `hello.js` with content below: ```javascript var a = 'world'; function hello(){ console.log(this.a)// it will fail } hello(); ``` Create a file index.html then add within the tag `<head>` the line below: ```html <script type="module" src="hello.js"></script> ``` Open the file in browser. The code will fail on line 4, `this` can't access `window`. > I would recommend to use "modules", because it can be transpiled with webpack or similar, and work in both environments browser and nodejs. If you want to learn to write a testable javascript code with jquery to run in both environment, read my article. ### Nodejs In nodejs works a little bit different. The `this` is a `global` value. ```javascript var a = 'hello'; global.b = 'world'; function hello(){ console.log(this.a) // fail console.log(this.b) // works } hello(); ``` The variable `a` can't be access from `global.a`. The `this` access only `global` object. ## Issues with testing Sometimes a JavaScript code can work on browser but its unit test fails. This happens quite often in legacy code that contains global variables spread among several files and consumed by `this` in somewhere. If this legacy code has been tested in tools like `jest` and `karma` they might have different results. ### Example Consider a legacy app where two JavaScript files are loaded in browser by "script" tags. The example is available on [GitHub](https://github.com/alanblins/jest-karma-sample). * **globalState.js**: Initialize global variables, * **legacy.js**: Access global variables through `this`. globalState.js ```javascript var globalValue = 10; window.globalValue2 = 5; ``` legacy.js ```javascript function getGlobalValue() { return this.globalValue; } function getGlobalValue2() { return this.globalValue2; } window.getGlobalValue = getGlobalValue; window.getGlobalValue2 = getGlobalValue2; ``` Below are test files to verify if the functions "getGlobalValue" and getGlobalValue2" returns right values. The first one is written in `jest` while the second in `karma`. ### jest test ```javascript test("result is 10", () => { expect(getGlobalValue()).toBe(10); //FAIL }); test("result is 5", () => { expect(getGlobalValue2()).toBe(5); }); ``` ### karma test ```javascript describe("getGlobalValue test", function() { it("result is 10", function() { expect(getGlobalValue()).toBe(10); }); it("result is 5", function() { expect(getGlobalValue2()).toBe(5); }); }); ``` Both tests in `karma` will all pass, while the `jest` will fail on the first test `result is 10`. Why? The issue is in the line 1 of `globalState.js`. ```js var globalValue = 10; ``` As `jest` runs in a Nodejs environment and Karma in browser environment, the variable `globalValue = 10` will be available only on browser’s object `window` but not in NodeJS’s object `global`. This is deeply explained on "Value of this by plataforms" item. If the line 1 is replace by `window` like below, the code will work on both `jest` and `karma` globalState.js modified ```javascript window.globalValue = 10; //fixed window.globalValue2 = 5; ``` `jest` will automatically copy all `window` values into nodejs `global` object. Then the `jest` test will pass. ## Explaining the first example To help to understand how the native JavaScript function `.map` works under the hood, let’s implement a custom version called `modifyArray`. ```javascript function modifyArray(array, callback ,thisArg){ var newArray = []; for(var i=0;i<array.length;i++){ newArray[i] = callback.call(thisArg, array[i]); } return newArray; } ``` The function `modifyArray` receives an array. It will iterate each element and replace it with the return of the callback function. Note that the callback function is using the `.call` function changing the value of `this` by the value `thisArg` as it shows on the 4th line. ### Simple function Let's multiply all the elements and passing a simple function `multiply` as a callback to the function `modifyArray`: ```javascript const array = [1,2,3]; const multiply = function(element){ return element*this; } const newArray = modifyArray(array, multiply, 2); console.log(newArray); ``` The result will be `[2,4,6]`. On the 5th line the third parameter `thisArg` has the value `2`. In the `modifyArray` `callback.call(thisArg, array[i])` update the `this` value with `2`. ```javascript newArray[i] = callback.call(thisArg, array[i]); //callback is `multiply` and `thisArgs` is 2. ``` According to the rule 3, because the `multiply` function was called using `call`, then the value of `this` will be `2`. ```javascript const multiply = function(element){ return element*this; // => element * 2 } ``` ### Arrow function Let's modify the `’multiply` function to an arrow function: ```javascript const array = [1,2,3]; const multiply = () => { return element*this; // element * window } const newArray = modifyArray(array, multiply, 2); console.log(newArray); ``` The result will be `[NaN, NaN, NaN]`. Why? Because the callback is an arrow function a two things happend here: * The line `callback.call(thisArg, array[i])` from `modifyArray` doesn’t change the value of `this`, look the Rule 4. * The value of `this` is `window` because it set the `this` to the nearest scope, which in this case is `window` When it calls `element*this` it tries to multiply a number with the `window` value `element * window` resulting to NaN value. Now, by understanding the previous example, the same idea may apply to the function `map`. ```javascript const a = [1,2,3].map(function(n){ return n*this; }, 2); const b = [1,2,3].map( n => { return n*this; }, 2); ``` The `map` function has two parameters function and thisArg. ```plaintext map(function callback( currentValue[, index[, array]]) { // return element for new_array }[, thisArg]) ``` The `thisArg` will be the value of `this` inside a function callback. In `arrow function` the value of `this` won't be `thisArg`. Inside the `map` function it does something similar to our function `modifyArray`. It might use the `call` or `apply` method to change the value of `this`. ## Summary ### 4 Rules 1. Inside a function, `this` refers to a global context(window for browser, global for nodejs); 2. Inside a method, refers to an object; 3. The value of `this` can be modified by `call` and `apply` functions and also when converts a method to a function and vice-versa; 4. The value of `this` will never change if is in an `arrow function` or a `bind` function, therefore invalidating the rules 1, 2 and 3; ### Callback * If the callback is a bind function or an `arrow function`, the value of `this` will never change regardless of how it is called. Rule 4 * if the callback is just a function, the value of `this` depends on how will be called then could apply the rules 1, 2 or 3. ### Browser * `this` is `window` * declare `var` outside any function is accessible via `this` ### Browser with strict mode * `this` doesn't access `window` ### Browser with module * `this` doesn't access `window` ### Nodejs * `this` is `global` * declare `var` outside any function is NOT accessible via `this` ### All cases in one code ```javascript var name = 'Foo global'; function getNameGlobalFunc(){ console.log(this.name); } const getNameGlobalVar = function(){ console.log(this.name); } const personObjectLiteral = { name: 'Foo object literal', getName: function(){ console.log(this.name); } } function PersonConstructor(){ this.name = 'Foo constructor'; this.setCallback = function( callback ){ this.callback = callback; } this.callCallback = function(){ this.callback(); } function getNameGlobal(){ console.log(this.name); } const getNameArrow = () => { console.log(this.name); }; const getNameBind = getNameGlobal.bind(this); this.getName = function(){ console.log(this.name); } this.getNameReassigned = getNameGlobal; const reasignAsGlobal = this.getName; this.callThisGlobals = function(){ getNameGlobal() reasignAsGlobal(); } this.callThisPersonContext = function(){ getNameArrow(); getNameBind(); this.getName(); this.getNameReassigned(); } } const person = new PersonConstructor(); getNameGlobalFunc(); getNameGlobalVar(); person.callThisGlobals(); personObjectLiteral.getName(); person.callThisPersonContext(); console.log(getNameGlobalVar.call(personObjectLiteral)) console.log(getNameGlobalVar.apply(person)) ``` ## Cheat sheet | **Scenario** | **Execution Example** | **Value of this** | | --- | --- | --- | | **Global Scope** | `console.log(this)` | `window` (Browser) or `global` (Node) | | **Simple Function** | `myFunc()` | `window` (Non-strict) / `undefined` (Strict, ES6 module) | | **Object Method** | `user.greet()` | The object before the dot (`user`) | | **Arrow Function** | `() => { ... }` | Inherited from the surrounding scope | | **Constructor** | `new Person()` | The brand new object being created | | **Explicit Binding** | [`func.call`](http://func.call)`(obj)` | The object passed as the argument (`obj`) |

    Tags

    javascriptthiskarmajest

    Comments

    More Blog

    View all
    How I'm using ASTs and Gemini to solve the "Codebase Onboarding" problem 🧠ai

    How I'm using ASTs and Gemini to solve the "Codebase Onboarding" problem 🧠

    Hi everyone! 👋 I’m Tara, a Senior Software Engineer and Consultant. Over the years, I've jumped...

    T
    tworrell
    Local AI Will Save Us All (The Math Says So, Trust Me)ai

    Local AI Will Save Us All (The Math Says So, Trust Me)

    Every few weeks a take goes viral in tech circles making the case for ditching cloud AI and running...

    S
    Sebastian Schürmann
    Lost in the AI Hype, I Started Smallai

    Lost in the AI Hype, I Started Small

    And it helped me get back into tech without drowning TL;DR at the end Coming back to...

    R
    Rohini Gaonkar
    Building a Replay-Tested Interactive Brokers Client in Gogo

    Building a Replay-Tested Interactive Brokers Client in Go

    I wanted an IBKR library that felt like Go and had testing I could trust. So I wrote one.

    T
    Thomas Marcelis
    Playwright in Pictures: Fully Parallel Modeplaywright

    Playwright in Pictures: Fully Parallel Mode

    Playwright’s fullyParallel mode is often treated as a simple performance switch. In practice, it...

    V
    Vitaliy Potapov
    Designing a CLI for Both Humans and Agentscli

    Designing a CLI for Both Humans and Agents

    Learn how Alpic designed its CLI for both human developers and AI agents — covering tradeoffs like polling, context windows, interactivity, and statelessness.

    J
    Julien Vallini

    Stay up to date

    Get the latest DeepSeek prompts, rules, and resources delivered to your inbox weekly.

    Neura Market LogoNeura Market

    Discover the best AI prompts, plugins, and resources for DeepSeek and more.

    Content Types

    • Rules
    • Prompts
    • MCPs
    • Agents
    • Guides

    Platforms

    • ChatGPT Directory
    • Claude Directory
    • Gemini Directory
    • Cursor Directory
    • Grok Directory
    • Perplexity Directory
    • DeepSeek Directory
    • CoPilot Directory
    • Stable Diffusion Directory
    • Midjourney Directory
    • All Directories

    Resources

    • Blog
    • Documentation
    • Help Center
    • Marketplace

    Legal

    • Privacy Policy
    • Terms of Service

    © 2026 Neura Market. All rights reserved.

    |

    Not affiliated with any AI platform vendors.