• 例 句 : JavaScript Symbols: The Most Misunderstood Feature of the Language?
  • Fernando Doglio
  • The Nuggets translation Project
  • Permanent link to this article: github.com/xitu/gold-m…
  • Translator: Zavier
  • Proofread by: jaredliw, niayyy

String asks the developer: “What feature of Symbol does String not have?” . “Well, Symbol is unique.”

I know, this is a bad answer, but please take a look with me, ok? Symbol is one of the oddest features in JavaScript because few people really understand it and don’t use it.

But Symbol exists for a reason, don’t you think? Just as with has its value, whether you like it or not. Symbol also has its value. So here, let’s analyze it.

What is Symbol?

To cut a long story short, Symbol is a new primitive data type that you can now access just like strings, values, booleans, undefined, and NULL.

Let’s break it down. Values of primitive data types are directly assigned to variables as follows:

let a = "foo"
Copy the code

The original value here is the string “foo”, not a. The latter is simply a variable assigned to the original value. Why am I making this distinction here? Because normally you don’t use a raw value directly, you assign it to a variable and give it meaning. In other words, the value 2 itself has no meaning, but let double = 2; It has meaning.

Another interesting point is that raw values are immutable in JavaScript. This means you can never change the number 2. But in fact, you can reassign a variable to another (immutable) original value.

Symbol also has the same properties as the original value:

  • Symbol is a primitive value that can be assigned directly to a variable.
  • Symbol is immutable, no matter how hard you try, you cannot change it.

It has an additional feature: Symbol is globally unique.

The first two are common to all primitive types, but the third is not, which is what makes them so special.

Unique Symbol

Let’s test it out:

2= = =2 // TRUE
true= = =true // TRUE
"this is a string"= = ="this is a string" // TRUE
undefined= = =undefined // TRUE
null= = =null // TRUE
Symbol() = = =Symbol(a)// FALSE!
Copy the code

This result demonstrates the unique nature of Symbol: every time you create a Symbol, it is a new value, even if you pass them the same name.

If you want to debug, you can supply the Symbol constructor with a string value as an argument. This value is not useful for anything other than debugging.

So what’s the use of a value that you can never really match?

let obj = {}
obj[Symbol= ()]10;
console.log(obj[Symbol() ");Copy the code

The result was not what we expected. Of course, you can store the Symbol in a variable and use the variable to access the unique attribute value. But you must save each Symbol into a variable. Really, it’s kind of a variation on strings, isn’t it?

Until you realize the global Symbol cache!

You can create symbols using the symbol. for method instead of calling the Symbol function directly.

let obj = {}
obj[Symbol.for('unique_prop')] = 10;

console.log(obj[Symbol.for('unique_prop')]); // Will output 10!
Copy the code

The first call to symbol. for creates a new Symbol value, and the second call returns it. This is where Symbol deviates from the string. Obviously, the string “hello” and the other string “hello” are equal, but they are different strings. Like when we:

let obj = {}
obj["prop"] = 10;
console.log(obj["prop"]);
Copy the code

We created:

  • A primitive value of type Number (10)
  • Two raw String values (two"prop"String)

What’s the connection between them? Let’s look at some examples of symbols!

When to use Symbol?

In the last example, what was the cost in terms of resources? How much memory does it take to create an extra string? So little that I don’t even care about it.

But especially if it works in a Web environment.

Alternatively, if you have some marginal situations where you might need to do some data processing to generate a large memory dictionary, for example, or you might be using JavaScript on a device with limited memory, Symbol might be a good way to maintain memory utilization.

Add invisible methods

Another interesting use of symbols comes from the fact that they are unique to such a feature. They can be used to provide custom, unique “hooks” for objects. Just like the toString hooks you can add to custom objects, this is called when console.log is serialized.

The point here is that by using Symbol, you can avoid potential name conflicts with any names the user provides for their methods. Unless they deliberately use your Symbol, there will be no problem.

// Add a custom hook for "Object"
Object.prototype.symbols = {
    serialize: Symbol.for('serialize')}// Use hook in function
function myconsol_log(obj) {
    if(typeof obj[Object.symbols.serialize] === 'function') {
        console.log(obj[Object.symbols.serialize]())
    } else {
        console.log(obj)
    }
}


// Write your own hook
class MyObject {[Object.symbols.serialize]() {
        return "Damn son!"
    }

    serialize() {
        return "Definitely not the same!"
    }
}


myconsol_log(new MyObject())
Copy the code

What do you think the output will be from the above code?

Will print “damn son!” Because that’s how you define it using Symbol. And the other one is essentially treated as a string, so they’re not the same and you don’t overwrite it.

Note that I have added an attribute to Object for simplicity, which is not necessary. Instead, you should create a custom class to properly control who inherits the custom hook.

Metadata as a class

The last interesting use case for Symbol is to add properties to your classes and objects that are not actually part of their “structure”.

To explain: the “structure” of an object is determined by its properties. The only way to add data to an object without affecting its structure (its original set of attributes) is to add them as symbols. This is because these types of attributes are not used as for.. Occurs as part of the in loop and does not occur as a result of calling Object.keys.

You can think of these properties as being at a higher level of abstraction than regular properties.

const lastAccessedProp = Symbol.for('last_accessed_prop');
const lastAccessedTime = Symbol.for('last_accessed_time');

class User {
    constructor(f_name, l_name, address) {
        this.first_name = f_name;
        this.last_name = l_name;
        this.address = address;
    }

    get FirstName() {
        this[lastAccessedProp] = 'first_name'
        this[lastAccessedTime] = new Date(a);return this.first_name;
    }

    get LastName() {
        this[lastAccessedProp] = 'last_name'
        this[lastAccessedTime] = new Date(a);return this.last_name;
    }

    get Address() {
        this[lastAccessedProp] = 'address'
        this[lastAccessedTime] = new Date(a);return this.address; }}let myUser = new User('Fernando'.'Doglio'.'Madrid, Spain');
console.log(myUser.FirstName, myUser.LastName)
console.log("Metadata:", myUser[lastAccessedProp], " read at ", myUser[lastAccessedTime].toTimeString())

console.log("Iterating over attributes: ")
for(k in myUser) {
    console.log(k, "=", myUser[k])
}
Copy the code

Notice how I added two metadata to my object: the property that was last accessed through the getter method I defined, and the date and time that was accessed. This is metadata because it is information that is not related to my business needs, but rather information that is relevant to the object.

After the class definition, I do a few things:

  • The Symbol attribute is public. This is obvious because private properties are not yet part of the ES standard. Once they’re done testing, we can look at how private attributes are defined.
  • In the abovefor.. inMy custom Symbol attribute will not show up in any of the attributes of the iteration. This comes in handy if you’re trying to access these properties as debug data in a class, because you know it won’t affect how your code works.

As mentioned above, Symbol is not the most convenient feature of JavaScript, but it’s not the worst either. Symbols are part of the standard for good reason, now that you know some of their interesting use cases, consider taking the time to try them out.

Do you use Symbol in any other way in your code? Share your code in the comments and let’s show everyone the power of Symbol!

If you find any mistakes in your translation or other areas that need to be improved, you are welcome to the Nuggets Translation Program to revise and PR your translation, and you can also get the corresponding reward points. The permanent link to this article at the beginning of this article is the MarkDown link to this article on GitHub.


The Nuggets Translation Project is a community that translates quality Internet technical articles from English sharing articles on nuggets. The content covers Android, iOS, front-end, back-end, blockchain, products, design, artificial intelligence and other fields. If you want to see more high-quality translation, please continue to pay attention to the Translation plan of Digging Gold, the official Weibo, Zhihu column.