DEV Community

Oliver Mensah
Oliver Mensah

Posted on

Hiding details in JavaScript classes with symbols

Classes are now supported in JavaScript(ES6 feature). One key important of classes is bundling methods and data together for specific objects. Hence it helps in achieving encapsulation. Encapsulation is used to hide the values or state of a structured data object inside a class, preventing unauthorized parties' direct access to them. So how do we maintain data from being manipulated outside the class scope?

One way to do this is by using symbols. Symbol is a new built-in-type of JavaScript, which can be invoked to give a new symbol value. Every Symbol is Unique and can be used as a key on the object. So one use case of symbols is that you can add something to an object you might not own, and you might not want to collide with any other keys of the object so creating a new one and adding a property to that object using symbol is the safest.
Also when symbol value is added to an object; no one else will know how to get it.

With the above code even though we can access the properties outside the function to change their content what if we don't want that
Symbols come to rescue.

Note: I have just started blogging on concepts of technologies I have been using as "student developer". Corrections and feedback to help me become software engineer are welcome.

Discussion (22)

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 Author

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 on

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 Author

That's cool

Collapse
olivermensahdev profile image
Oliver Mensah Author

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 Author

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 Author • Edited on

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 Author

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 Author

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 on

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 Author • Edited on

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
kwabenberko profile image
Kwabena Bio Berko

Cool!

Collapse
dharnarh profile image
Umar Farouq Mohammed

Good tutorial! Keep it up

Collapse
olivermensahdev profile image
Oliver Mensah Author

Thank you for the feedback