Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to declare private variables and private methods in es6 class [duplicate]

in es5 we use constructor function

function Person(name,gender){

    var initial ="";    // we use var key word to make variable private

    function getNameWithInitial(){ // this is the private method to get name with initial
        console.log(this);
        initial = this.gender ==="male"?"Mr. ":"Mrs. ";
        return initial + this.name;
    }


    this.name = name;
    this.gender = gender;
    this.getName = function(){
        return getNameWithInitial.call(this);
    }


}


var manas = new Person("Manas","male");

console.log(manas.getName());

My question is how to declare a private variable and private method in es6 class

like image 238
manas Avatar asked Jan 19 '16 05:01

manas


People also ask

How do you declare a private variable in JavaScript?

Alternatively, we may also use the “this” keyword to make method (function) calls to stick to the main method itself which thus makes the variables private. The main idea for using the “this” keyword is just to make things directly visible that is making methods directly accessible.

Can we declare private variable in method?

No, it is a syntax error, you can not use access modifiers within a method.

Is Private allowed in ES6 class definition?

Short answer, no, there is no native support for private properties with ES6 classes. But you could mimic that behaviour by not attaching the new properties to the object, but keeping them inside a class constructor, and use getters and setters to reach the hidden properties.

What is the standard keyword used to declare private method variables in js classes?

The "hash mark" ( # ) is what marks a field as being private. It also prevents private fields and property names from ever being in conflict: private names must start with # , whereas property names can never start that way.


1 Answers

One way to achieve this is using another ES2015 feature known as modules.

You may already be familiar with AMD modules, or commonJS modules (used by Nodejs). Well ES6 / ES2015 brings a standard for JS - we'll call them ES6 modules but they are part of the JS language now. Once you have modules, you have the ability to do information hiding for both private functions and object variables. Bear in mind, only what you "export" is visible to client calling code.

Lets work through your example code. Here is a first cut:

person.js

 const getNameWithInitial = function () {
      let initial = this._gender === 'male' ?
      'Mr. ' :
      'Mrs. ';
      return initial + this._name;
    }

  export class Person {

    constructor(name, gender) {
        this._name = name;
        this._gender = gender;
      }

      get name() {
          return getNameWithInitial.call(this);
        }
    }
  }

client.js

import {Person} from './person';
const manas = new Person('Manas', 'male');
console.log(manas.name);  // this calls what was your getName function

Now, the getNameWithInitial function is effectively private, as it is not exported, so client.js cannot see it.

However, we still have a problem for the Person class, since this is exported. At the moment you can just walk up to manas object and do:

manas._name = 'Joe'

With properties like _name, we can combine modules and symbols. This is a powerful yet lightweight information hiding technique available with ES6+/ES2015.

Symbol is a new built-in type. Every new Symbol value is unique. Hence can be used as a key on an object.

If the client calling code doesn't know the symbol used to access that key, they can't get hold of it since the symbol is not exported.

Let's see our modified code to make use of symbols and modules to hide Class attributes.

person.js

const s_name = Symbol();
const s_gender = Symbol();

const getNameWithInitial = function () {
  let initial = this[s_gender] === 'male' ?
    'Mr. ' :
    'Mrs. ';
  return initial + this[s_name];
}

export class Person {

  constructor(name, gender) {
    this[s_name] = name;
    this[s_gender] = gender;
  }

  get name() {
    return getNameWithInitial.call(this);
  }
}

So, now a client cannot just do:

 manas._name = 'Joe' 

because _name is not being used as the key for the name value.

However, symbols are exposed via reflection features such as Object.getOwnPropertySymbols so be aware they are not "completely' private using this technique.

import {Person} from './person';
const manas = new Person('Manas', 'male');
const vals = Object.getOwnPropertySymbols(manas);
manas[vals[0]] = 'Joanne';
manas[vals[1]] = 'female';

Takeaway message - Modules in general are a great way to hide something because if not exported then not available for use outside the module, and used with privately stored Symbols to act as the keys, then class attributes too can become hidden (but not strictly private). Using modules today is available with build tools eg. webpack / browserify and babel.

like image 131
arcseldon Avatar answered Oct 05 '22 22:10

arcseldon