JavaScript Private Methods

JavaScript private methods

You can do it, but the downside is that it can't be part of the prototype:

function Restaurant() {
var myPrivateVar;

var private_stuff = function() { // Only visible inside Restaurant()
myPrivateVar = "I can set this here!";
}

this.use_restroom = function() { // use_restroom is visible to all
private_stuff();
}

this.buy_food = function() { // buy_food is visible to all
private_stuff();
}
}

How to implement private method in ES6 class with Traceur

There are no private, public or protected keywords in current ECMAScript 6 specification.

So Traceur does not support private and public. 6to5 (currently it's called "Babel") realizes this proposal for experimental purpose (see also this discussion). But it's just proposal, after all.

So for now you can just simulate private properties through WeakMap (see here). Another alternative is Symbol - but it doesn't provide actual privacy as the property can be easily accessed through Object.getOwnPropertySymbols.

IMHO the best solution at this time - just use pseudo privacy. If you frequently use apply or call with your method, then this method is very object specific. So it's worth to declare it in your class just with underscore prefix:

class Animal {

_sayHi() {
// do stuff
}
}

Have private properties & methods in ES6 classes

It seems like classes in ES6 doesn't explicitly provide anything to have private data or methods.

Correct. The class syntax is for normal classes with prototype methods. If you want private variables, you put them in the constructor as always:

class Deferred {
constructor() {
// initialise private data
var isPending = true;
var handlers = {
resolve: [],
reject: [],
notify: []
};

// Private method
function trigger(event, params) {
...
}

// initialise public properties
this.promise = new Promise(this);

// and create privileged methods
this.resolve = trigger.bind(null, 'resolve');
this.reject = trigger.bind(null, 'reject');
this.notify = trigger.bind(null, 'notify');

this.on = function(event, handler) {

};
}
}

ES6 Private Methods with access to this keyword JavaScript idioms

Private methods are safe now (they are finally stage 4 after a long time). If your browser supports it this should work:

class A {
#myPrivateMethod(){
console.log('this is my private method');
}
constructor(){
this.#myPrivateMethod();
}
}

new A;

What is the syntax for private method in browser Javascript class(not node.js)?

This illustrates how to hide a method name, effectively making the method uncallable outside the hiding closure:

const Klass = (function() {
const privName = Symbol("priv");

class Klass {
publ() {
console.log("in publ");
this[privName]();
}
[privName]() {
console.log("in priv");
}
}

return Klass;
})()

let inst = new Klass();
inst.publ();
// => in publ
// in priv

It uses the fact that Symbol() returns an entity that cannot be replicated, the fact that privName is not exposed anywhere outside the closure, and the fact that we can define properties with calculated names using the square bracket notation.

Unlike the function-hiding mechanism demonstrated by ultratoad, this is not just a helper function, it is a true method. Just note that you can't call it using the dot notation - dot notation only works when you know the name, and here, no-one does except privName.

Private properties in JavaScript ES6 classes

Private class features is in Stage 3 proposal. The majority of its features are supported by all major browsers.

class Something {
#property;

constructor(){
this.#property = "test";
}

#privateMethod() {
return 'hello world';
}

getPrivateMessage() {
return this.#property;
}
}

const instance = new Something();
console.log(instance.property); //=> undefined
console.log(instance.privateMethod); //=> undefined
console.log(instance.getPrivateMessage()); //=> test
console.log(instance.#property); //=> Syntax error

Can there be private members in an exported class?

Edit in 2021:

Javascript has a proposal (currently at Stage 3 as of early 2021) for private members/methods. See this description on MDN for more details. Portions of this are implemented in Chrome and Nodejs, not yet in Safari and Firefox.

To use this feature, you prefix the method with # as in:

class ClassWithPrivateMethod {
#privateMethod() {
return 'hello world'
}

getPrivateMessage() {
return this.#privateMethod()
}
}

This will be a syntax error in a Javascript engine that does not support this feature.


Original answer from 2019.

Work-arounds for private members.

Javascript does not, by itself, have the notion of private methods. So, if you define a method on a class, then any code that has a reference to an instance of that class can call that method. There is no such thing as a method definition that is private in Javascript.

That said, there are numerous work-arounds that can give you code that operates on an object that is private and not callable from outside your module. Here's an example:

'use strict'

// declare privateMethod as a local function that can only be called from within this module
function privateMethod(obj, args) {
// private code here
// reference instance with obj.method() or obj.data
obj.otherPublicMethod()
}

module.exports = class DBConnector {
constructor() {}
publicMethod() {
// call code for private method
privateMethod(this, ...);
}
otherPublicMethod() {}
}

This is truly private because the code for the method is not on the prototype and thus is not discoverable or callable from outside this module. Of course, you have to call it slightly differently because it's not a "real" method. But, that's because all "real" methods are discoverable and callable from the outside.


If you want the private method itself to use this to reference the current object, then you just change how you call the method:

'use strict'

// declare privateMethod as a local function that can only be called from within this module
function privateMethod(args) {
// private code here
// can reference this as in any normal method this.method() or this.data
this.otherPublicMethod()
}

module.exports = class DBConnector {
constructor() {}
publicMethod() {
// call code for private method using .call()
privateMethod.call(this, ...);
}
otherPublicMethod() {}
}

FYI, TypeScript supports both private methods and properties. Here's an article that gives you a look at how that works. Of course, this means buying into the whole TypeScript syntax and type checking and transpiling your code.


There's also a closure-based method of implementing private methods and private instance variables described here: http://crockford.com/javascript/private.html. but that means you can't put any methods that wish to access the private methods in the class definition or on the prototype. But, it does work.

How to declare private variables and private methods in es6 class

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.



Related Topics



Leave a reply



Submit