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.

1

2

3

4

5

6

7

8

9

10

11

// 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.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

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.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

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.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

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.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

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:

1

2

3

4

5

6

7

8

9

// 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.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

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.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

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:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

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.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

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 Article

Roblox: Bubble Gum Simulator Infinity - How To Get And Use Royal Keys
3 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
Nordhold: Fusion System, Explained
3 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
Mandragora: Whispers Of The Witch Tree - How To Unlock The Grappling Hook
3 weeks ago By 尊渡假赌尊渡假赌尊渡假赌

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)

Hot Topics

Java Tutorial
1667
14
PHP Tutorial
1273
29
C# Tutorial
1255
24
A Comparison of Static Form Providers A Comparison of Static Form Providers Apr 16, 2025 am 11:20 AM

Let’s attempt to coin a term here: "Static Form Provider." You bring your HTML

A Proof of Concept for Making Sass Faster A Proof of Concept for Making Sass Faster Apr 16, 2025 am 10:38 AM

At the start of a new project, Sass compilation happens in the blink of an eye. This feels great, especially when it’s paired with Browsersync, which reloads

Weekly Platform News: HTML Loading Attribute, the Main ARIA Specifications, and Moving from iFrame to Shadow DOM Weekly Platform News: HTML Loading Attribute, the Main ARIA Specifications, and Moving from iFrame to Shadow DOM Apr 17, 2025 am 10:55 AM

In this week's roundup of platform news, Chrome introduces a new attribute for loading, accessibility specifications for web developers, and the BBC moves

Some Hands-On with the HTML Dialog Element Some Hands-On with the HTML Dialog Element Apr 16, 2025 am 11:33 AM

This is me looking at the HTML element for the first time. I've been aware of it for a while, but haven't taken it for a spin yet. It has some pretty cool and

Paperform Paperform Apr 16, 2025 am 11:24 AM

Buy or build is a classic debate in technology. Building things yourself might feel less expensive because there is no line item on your credit card bill, but

Where should 'Subscribe to Podcast' link to? Where should 'Subscribe to Podcast' link to? Apr 16, 2025 pm 12:04 PM

For a while, iTunes was the big dog in podcasting, so if you linked "Subscribe to Podcast" to like:

It's All In the Head: Managing the Document Head of a React Powered Site With React Helmet It's All In the Head: Managing the Document Head of a React Powered Site With React Helmet Apr 15, 2025 am 11:01 AM

The document head might not be the most glamorous part of a website, but what goes into it is arguably just as important to the success of your website as its

Options for Hosting Your Own Non-JavaScript-Based Analytics Options for Hosting Your Own Non-JavaScript-Based Analytics Apr 15, 2025 am 11:09 AM

There are loads of analytics platforms to help you track visitor and usage data on your sites. Perhaps most notably Google Analytics, which is widely used

See all articles