Table of Contents
var keyword
The birth of ES6 variables
Using functions
Module design mode
Another way
ES6 Class
Use underline
Put everything in the constructor
Using WeakMap
Use symbols to prevent conflict
TC39 Private Class Field Proposal
in conclusion
Home Web Front-end CSS Tutorial Implementing Private Variables In JavaScript

Implementing Private Variables In JavaScript

Apr 20, 2025 am 10:21 AM

Implementing Private Variables In JavaScript

JavaScript, the programming language that empowers the World Wide Web, has become a widely used and versatile technology since its creation by Brendan Eich in May 1995. Despite its success, it has also received considerable criticism, especially some features. For example, an object is cast to a string when used as an index, 1 == "1" returns true, or the infamous confusing this keyword. However, one particularly interesting feature is the existence of various techniques that implement variable privacy.

Currently, there is no way to directly create private variables in JavaScript. In other languages, you can use private keywords or double underscores and everything works fine, but in JavaScript, variable privateness has features that make it more similar to the emergent features of the language than the expected functionality. Let's first introduce the background of our question.

var keyword

Until 2015, there was basically only one way to create variables, and that was the var keyword. var is function scoped, which means that variables instantiated with this keyword can only be accessed by code within the function. In the case where the function is external or essentially "global", the variable will be accessible by anything executed after the variable is defined. If you try to access the variable in the same scope before its definition, you will get undefined instead of an error. This is due to the "upgrade" way of the var keyword.

 // Define "a" in global scope
var a = 123;

// Define "b" in function scope
(function() {
  console.log(b); //=> Due to promotion, "undefined" is returned instead of an error.
  var b = 456;
})();

console.log(a); // => 123
console.log(b); // Throws a "ReferenceError" exception because "b" cannot be accessed from outside the function scope.
Copy after login

The birth of ES6 variables

In 2015, ES6/ES2015 was officially released, and followed by two new variable keywords: let and const . Both are block-scoped, meaning that variables created with these keywords can be accessed by anything within the same pair of brackets. Same as var , but let and const variables cannot be accessed outside block scopes such as loops, functions, if statements, brackets, etc.

 const a = 123;

// Block Scope Example #1
if (true) {
  const b = 345;
}

// Block Scope Example #2
{
  const c = 678;
}

console.log(a); // 123
console.log(b); // Throws "ReferenceError" because "b" cannot be accessed from outside the block scope.
console.log(c); // Throws "ReferenceError" because "b" cannot be accessed from outside the block scope.
Copy after login

Since code outside the scope cannot access variables, we obtain the emergence of privateness. We will introduce some techniques to implement it in different ways.

Using functions

Since functions in JavaScript are also blocks, all variable keywords work with them. Furthermore, we can implement a very useful design pattern called "module".

Module design mode

Google relies on the Oxford Dictionary to define "modules":

The program may construct from it or may analyze any of a number of different but interrelated units of complex activities.

— “Module” definition 1.2

The module design pattern is very useful in JavaScript because it combines public and private components and allows us to break down programs into smaller components, exposing only what another program part should be able to access through a process called "encapsulation". In this way, we only expose what we need to use and hide what we don’t need to see. We can do this by leveraging the function scope.

 const CarModule = () => {
  let milesDriven = 0;
  let speed = 0;

  const accelerate = (amount) => {
    speed = amount;
    milesDriven = speed;
  }

  const getMilesDriven = () => milesDriven;

  // Using the "return" keyword, you can control what content is exposed and what content is hidden. In this case, we expose only the accelerate() and getMilesDriven() functions.
  return {
    accelerate,
    getMilesDriven
  }
};

const testCarModule = CarModule();
testCarModule.accelerate(5);
testCarModule.accelerate(4);
console.log(testCarModule.getMilesDriven());
Copy after login

This way we can get mileage and acceleration, but since the user does not need access speed in this case, we can hide it by exposing only accelerate() and getMilesDriven() methods. Essentially, speed is a private variable because it can only be accessed by code within the same scope. The benefits of private variables start to become clear in this case. When you delete the ability to access variables, functions, or any other internal components, you reduce the surface area that is wrongly used by others by mistake by others that should not have been used.

Another way

In this second example, you will notice the addition of this keyword. There is a difference between the ES6 arrow function (=>) and the traditional function (){}. With function keyword you can use this , which will bind to the function itself, and the arrow function does not allow the use of any type of this keyword. Both are equally effective ways to create modules. The core idea is to disclose the parts that should be accessed and retain other parts that should not be interacted with, so there is both public and private data.

 function CarModule() {
  let milesDriven = 0;
  let speed = 0;

  // In this case, we use the "this" keyword instead,
  // It refers to CarModule
  this.accelerate = (amount) => {
    speed = amount;
    milesDriven = speed;
  }

  this.getMilesDriven = () => milesDriven;
}

const testCarModule = new CarModule();
testCarModule.accelerate(5);
testCarModule.accelerate(4);
console.log(testCarModule.getMilesDriven());
Copy after login

ES6 Class

Classes are another new feature in ES6. Classes are essentially syntactic sugar—in other words, still a function, but may "beautify" it into a more easily expressed form. For classes, variable privateness (as of now) is nearly impossible unless some major changes are made to the code.

Let's look at an example of a class.

 class CarModule {
  /*
    milesDriven = 0;
    speed = 0;
  */
  constructor() {
    this.milesDriven = 0;
    this.speed = 0;
  }
  accelerate(amount) {
    this.speed = amount;
    this.milesDriven = this.speed;
  }
  getMilesDriven() {
    return this.milesDriven;
  }
}

const testCarModule = new CarModule();
testCarModule.accelerate(5);
testCarModule.accelerate(4);
console.log(testCarModule.getMilesDriven());
Copy after login

The first thing to note is that milesDriven and speed variables are located in constructor() function. Note that you can also define variables outside of the constructor (as shown in the code comments), but they are functionally the same anyway. The problem is that these variables will be public and can be accessed by elements outside the class.

Let's take a look at some solutions to this problem.

Use underline

In situations where privateness is to prevent collaborators from making some catastrophic mistakes, using an underscore (_) as a variable prefix, although it is still "visible" to the outside, is enough to signal the developer, "Don't touch this variable". So, for example, we now have the following:

 // This is the new constructor of the class. Note that it can also be represented as the following content outside the constructor().
/*
  _milesDriven = 0;
  _speed = 0;
*/
constructor() {
  this._milesDriven = 0;
  this._speed = 0;
}
Copy after login

While this works for its specific use cases, it is still safe to say that it is not ideal in many ways. You can still access the variables, but you also have to modify the variable name.

Put everything in the constructor

Technically, there is indeed a way to use private variables in a class, which is to put all variables and methods in constructor() function. Let's take a look.

 class CarModule {
  constructor() {
    let milesDriven = 0;
    let speed = 0;

    this.accelerate = (amount) => {
      speed = amount;
      milesDriven = speed;
    }

    this.getMilesDriven = () => milesDriven;
  }
}

const testCarModule = new CarModule();
testCarModule.accelerate(5);
testCarModule.accelerate(4);
console.log(testCarModule.getMilesDriven());
console.log(testCarModule.speed); // undefined -- We now have real variable privacy.
Copy after login

This approach implements true variable privacy because there is no direct access to any variable that is not intentionally disclosed. The problem is that we have now, well, not looking very good code compared to ours, and it also breaks the benefits of syntax sugar when we use classes. At this time, we might as well use function() method.

Using WeakMap

There is also a more creative way to create private variables, which is to use WeakMap() . While it may sound similar to Map , the two are very different. While the mapping can take any type of value as a key, WeakMap only accepts objects and deletes the values ​​in WeakMap when garbage collects object keys. Additionally, WeakMap cannot iterate, meaning you have to access a reference to the object key to access the value. This makes it very useful for creating private variables, because variables are actually invisible.

 class CarModule {
  constructor() {
    this.data = new WeakMap();
    this.data.set(this, {
      milesDriven: 0,
      speed: 0
    });
    this.getMilesDriven = () => this.data.get(this).milesDriven;
  }

  accelerate(amount) {
    // In this version, we instead create a WeakMap and // use the "this" keyword as the key, which is unlikely // will be accidentally used as the key for the WeakMap.
    const data = this.data.get(this);
    const speed = data.speed amount;
    const milesDriven = data.milesDriven data.speed;
    this.data.set({ speed, milesDriven });
  }

}

const testCarModule = new CarModule();
testCarModule.accelerate(5);
testCarModule.accelerate(4);
console.log(testCarModule.getMilesDriven());
console.log(testCarModule.data); //=> WeakMap { [items unknown] } -- This data cannot be easily accessed from the outside!
Copy after login

This solution is good at preventing accidental use of data, but it is not really private, as it can still be accessed from outside by replacing this with CarModule . Furthermore, it adds quite a bit of complexity and is therefore not the most elegant solution.

Use symbols to prevent conflict

If the purpose is to prevent name conflicts, you can use Symbol to provide a useful solution. These are essentially instances that can act as unique values, and they will never equal any other value except its own unique instance. Here is an example of it in real-life applications:

 class CarModule {
  constructor() {
    this.speedKey = Symbol("speedKey");
    this.milesDrivenKey = Symbol("milesDrivenKey");
    this[this.speedKey] = 0;
    this[this.milesDrivenKey] = 0;
  }

  accelerate(amount) {
    // This data is almost impossible to access unexpectedly. It is by no means private.
    // But it stays away from anyone who will implement this module.
    this[this.speedKey] = amount;
    this[this.milesDrivenKey] = this[this.speedKey];
  }

  getMilesDriven() {
    return this[this.milesDrivenKey];
  }
}

const testCarModule = new CarModule();
testCarModule.accelerate(5);
testCarModule.accelerate(4);
console.log(testCarModule.getMilesDriven());
console.log(testCarModule.speed); // => undefined -- We need to access the internal key to access the variable.

Like the underscore solution, this approach relies more or less on naming conventions to prevent confusion.
Copy after login

TC39 Private Class Field Proposal

Recently, a new proposal was proposed that would introduce private variables to the class. It's simple: add # before the variable name and it becomes private. No additional structural changes are required.

 class CarModule {
  #speed = 0
  #milesDriven = 0

  accelerate(amount) {
    // This data is almost impossible to access unexpectedly.
    this.#speed = amount;
    this.#milesDriven = speed;
  }

  getMilesDriven() {
    return this.#milesDriven;
  }
}

const testCarModule = new CarModule();
testCarModule.accelerate(5);
testCarModule.accelerate(4);
console.log(testCarModule.getMilesDriven());
console.log(testCarModule.speed); //=> undefined -- We need to access the internal key to access the variable.
Copy after login

Private class features have become a reality and have quite good browser support.

in conclusion

This is a summary of the various ways to implement private variables in JavaScript. There is no "correct" approach. These methods are suitable for different requirements, existing code bases, and other constraints. While each approach has its advantages and disadvantages, ultimately, all approaches are equally effective as long as they effectively solve your problem.

Thank you for reading! I hope this gives you some insight on how to apply scope and variable privacy to improve your JavaScript code. This is a powerful technology that supports many different methods and makes your code easier to use and error-free. Try some new examples yourself to get a better feeling.

The above is the detailed content of Implementing Private Variables In JavaScript. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

Vue 3 Vue 3 Apr 02, 2025 pm 06:32 PM

It's out! Congrats to the Vue team for getting it done, I know it was a massive effort and a long time coming. All new docs, as well.

Building an Ethereum app using Redwood.js and Fauna Building an Ethereum app using Redwood.js and Fauna Mar 28, 2025 am 09:18 AM

With the recent climb of Bitcoin’s price over 20k $USD, and to it recently breaking 30k, I thought it’s worth taking a deep dive back into creating Ethereum

Can you get valid CSS property values from the browser? Can you get valid CSS property values from the browser? Apr 02, 2025 pm 06:17 PM

I had someone write in with this very legit question. Lea just blogged about how you can get valid CSS properties themselves from the browser. That's like this.

A bit on ci/cd A bit on ci/cd Apr 02, 2025 pm 06:21 PM

I'd say "website" fits better than "mobile app" but I like this framing from Max Lynch:

Stacked Cards with Sticky Positioning and a Dash of Sass Stacked Cards with Sticky Positioning and a Dash of Sass Apr 03, 2025 am 10:30 AM

The other day, I spotted this particularly lovely bit from Corey Ginnivan’s website where a collection of cards stack on top of one another as you scroll.

Using Markdown and Localization in the WordPress Block Editor Using Markdown and Localization in the WordPress Block Editor Apr 02, 2025 am 04:27 AM

If we need to show documentation to the user directly in the WordPress editor, what is the best way to do it?

Comparing Browsers for Responsive Design Comparing Browsers for Responsive Design Apr 02, 2025 pm 06:25 PM

There are a number of these desktop apps where the goal is showing your site at different dimensions all at the same time. So you can, for example, be writing

Why are the purple slashed areas in the Flex layout mistakenly considered 'overflow space'? Why are the purple slashed areas in the Flex layout mistakenly considered 'overflow space'? Apr 05, 2025 pm 05:51 PM

Questions about purple slash areas in Flex layouts When using Flex layouts, you may encounter some confusing phenomena, such as in the developer tools (d...

See all articles