DEV Community

Hiding details in JavaScript classes with symbols

Oliver Mensah on October 30, 2017

Classes are now supported in JavaScript(ES6 feature). One key important of classes is bundling methods and data together for specific objects. Henc...
Collapse
 
joelnet profile image
JavaScript Joel

Symbol only changes the property key it does not add any privacy.

The first example is equivalent to this:

// here the key is type 'string'
p['s_firstname'] = 'Nana'; 
Enter fullscreen mode Exit fullscreen mode

The 2nd example is equivalent to this:

// here the key is type 'Symbol'
p[s_firstname] = 'Nana'; 
Enter fullscreen mode Exit fullscreen mode

Using the symbol will still allow you to set the firstname.

let s_firstname  = Symbol();

class Person {
    constructor(firstName) {
        this[s_firstname] = firstName;
    }

    log() {
        console.log('I am', this[s_firstname]);
    }

}

let p = new Person("Oliver")
p.log(); // I am Oliver
p[s_firstname] = "Nana";
p.log()// I am Nana
Enter fullscreen mode Exit fullscreen mode
Collapse
 
joelnet profile image
JavaScript Joel

Alternatively, you can also achieve privacy by switching from using a Class to using a closure.

// firstname cannot be modified!
const person = (firstName) => ({
  log: () => console.log('I am', firstName)
})

let p = person("Oliver")
p.log(); // I am Oliver
Enter fullscreen mode Exit fullscreen mode
Collapse
 
olivermensahdev profile image
Oliver Mensah

I am concerned about the classical way of preventing outside modification of class properties. I have been finding means to do that until I tried using symbols. In my approach, it works and that is why I wanted to share with others but I did not know that they modified using another approach as you have stated. I like how you have outlined the process. But can you help in the classical way of hiding details in JavaScript?

Thread Thread
 
joelnet profile image
JavaScript Joel • Edited

I am not a fan of classes in JavaScript. As a matter of fact, I never create code with classes. I have found that functions will serve the same purpose. I prefer using the revealing module pattern over JavaScript classes.

Here's an example:

const createPerson = (firstName) => {
  var s_firstname = firstName

  const log = () =>
    console.log('I am', s_firstname)
  const setName = firstName =>
    (s_firstname = firstName)

  return {
    log,
    setName
  }
}

const me = createPerson('unknown')
me.setName('Joel')
me.log()

I added a setName function to demonstrate how to set the private var s_firstname.

Thread Thread
 
olivermensahdev profile image
Oliver Mensah

That's cool

Collapse
 
olivermensahdev profile image
Oliver Mensah

Okay. Thanks for the feedback

Collapse
 
joelnet profile image
JavaScript Joel

You can also enumerate property-symbols with this command:

Object.getOwnPropertySymbols(p)

So if you do not know the symbol, you can still set the property using code like this:

let p = new Person("Oliver")
// set first property-symbol to 'Nana'
p[Object.getOwnPropertySymbols(p)[0]] = 'Nana'
p.log() // I am Nana

Collapse
 
olivermensahdev profile image
Oliver Mensah

Well noted.

Collapse
 
galvao profile image
Er Galvão Abbott

"Encapsulation is used to hide the values or state of a structured data object inside a class, preventing unauthorized parties' direct access to them."

You're basing your argument on the wrong premises:

  1. It's a common misconception that encapsulation is about "hiding" something. It isn't.
  2. Symbols aren't about that.

Yes, encapsulation is - among other things - used to prevent direct access to a property or method, but this has nothing to do with "authorization" (another common misconception).

Collapse
 
olivermensahdev profile image
Oliver Mensah • Edited

The whole idea here is to hide the details in a class so they cannot be changed outside class. It is obvious that using the approach I propose, they cannot be changed outside the class, however,@joelnet , outlined means that they can be accessed outside the class and then modified, which refutes the article.

Collapse
 
galvao profile image
Er Galvão Abbott

I'm sorry this will seem like nitpicking, but I believe concepts are truly important: every property, unless static (which I don't believe JS has, but I might be wrong), is always being accessed "outside the class", since they are being accessed in an object, and not the class itself.

My goal is not the final result you wish (protecting the properties), but just to set OO straight.

Sammy Israwi is absolutely correct: the way to do it in OO is through what we call visibility (setting a property or method as public, protected or private), which seems to be in ES' future.

Thread Thread
 
olivermensahdev profile image
Oliver Mensah

No worries. I appreciate the way, we are tackling the flaws though. That is a good way of critiquing an article.

Collapse
 
olivermensahdev profile image
Oliver Mensah

Thanks for the feedback too.

Collapse
 
joegaudet profile image
Joe Gaudet

Cool concept, I didn't know symbols had made their way into JS. Shame you have to explicitly invoke them with a constructor and there isn't some sugar like in ruby / scala

:a_symbol

WRT to data hiding encapsulation, not sure if you've seen the draft spec for private properties / methods. The syntax is ugly, but nice to finally get it in.

github.com/hemanth/es-next#orthogo...

Collapse
 
mariosant profile image
Marios Antonoudiou • Edited

Here is my two cents when it comes to private members.

const Person = function(firstName) {
    const privateFirstName = firstName  // This is "private"

    this.log = () => console.log(`Hi! I am ${privateFirstName}`)   // This is "public"
}

const m = new Person('Marios')
m.log()

But then again, this is just a personal preference.

Collapse
 
sammyisa profile image
Sammy Israwi

Fantastic! I didn't know about Symbols before.

But why not use Private Fields? (which has been merged into the Class Fields proposal).

It's not yet implemented, but it is on Stage 3 so hopefully, it will be coming soon!

Collapse
 
olivermensahdev profile image
Oliver Mensah • Edited

Most often _ is prefixed before the properties to signify private properties but they can still be modified outside the class.

Thanks for the feedback and I will look into Private Fields

Collapse
 
galvao profile image
Er Galvão Abbott

That's because prefixing something with an underscore is a convention and not a language feature. In order to truly protect object properties you need visibility, as pointed by Sammy and explained in my latest reply to my own comment.

If the language doesn't have visibility features any method you use to try and protect the properties will simply be an ugly jerry-rig (that includes the prefix).

Collapse
 
theodesp profile image
Theofanis Despoudis

Even though _firstname does not change the property doing something like:

p[s_firstname] = "Nana";

does, which totally defeats the purpose of it

Collapse
 
dharnarh profile image
Umar Farouq Mohammed

Good tutorial! Keep it up

Collapse
 
olivermensahdev profile image
Oliver Mensah

Thank you for the feedback

Collapse
 
kwabenberko profile image
Kwabena Bio Berko

Cool!