Is there a convention for naming symbols in ES6? - javascript

I'm toying around with ES6, looking at symbols. Unlike ruby for example where you'd write :symbol, ES6 symbols seem to be allowed any "standard" variable name. To be honest I am finding this rather confusing:
var privateProperty = Symbol();
var obj = {};
obj[privateProperty] = 'some value goes here';
as it tends to make me think that privateProperty is probably a plain string like the years before. Using :privateProperty is not valid.
So just like using $bar for a jQuery object or bar$ for a RxJS/Bacon stream, I was wondering if there is already an established convention for naming symbols in ES6?

obj[privateProperty] = …; tends to make me think that privateProperty is probably a plain string like the years before.
Well, that's the old thinking that we will need to forget. privateProperty is a key, which can be either a string (property name) or symbol. Similarly, we already have learned to distinguish (integer) indices from "normal" properties.
ES6 seems to allow any "standard" variable name
Just as does Ruby. The difference is that ES6 doesn't introduce a literal notation for symbols (which resolve to the same thing), but allows them to be created only by using Symbol (locally) or Symbol.for (globally).
There is no standard convention for naming variables that hold symbol values.
Of course, you can always use hungarian notation if you tend to want such type annotations. If I had to coin a standard, I'd propose to use a more subtle leading underscore (var _myPrivate). Underscores in property names had always implied something special, and it would look similar for computed property keys (obj[_myPrivate]) then.
Is there a convention for naming symbols in ES6?
While there is no convention for naming symbol-holding variables (yet), there certainly is a convention for naming symbols themselves:
local symbols should have a very descriptive descriptor string (given as an argument to Symbol). Of course, they're still unique anyway, so you basically can use whatever name you want.
global symbols need to avoid collisions. The convention is to namespace them appropriately, and connect those namespace names with dots - like a Java package name. If the symbol is available as a global variable, its descriptor should have the same name (similar to the builtin, native symbols, which are like ##iterator = Symbol.for("Symbol.iterator");). If the symbol is exported by a module or library, its descriptor should be prefixed with the module/library name (to avoid collisions).
And it would probably be a best practise to use the same name for the variable (like the native symbols already do, Symbol.iterator.toString() == "Symbol(Symbol.iterator)").

Related

Understanding ES6 Symbols

I've been around the block when it comes to languages, having worked with everything from C# to Lisp to Scala to Haskell, and in every language that supported them, symbols have acted pretty much the same; that is, any two symbols with the same name, are guaranteed to be identical because they're singleton objects.
Racket: (equal? 'foo 'foo) true
Common Lisp: (eq 'foo 'foo) true
Ruby: :foo == :foo true
Scala: 'foo == 'foo true
ES6: Symbol('foo') === Symbol('foo') false
The benefit of symbols being singletons is obvious: You can use them in maps/dictionaries without risking your key not being equal to your input because the language suddenly decided to hash it differently (looking at you, Ruby)
So why is it that ECMAScript 6 takes a different approach on this, and how can I get around it?
You can (sort-of) get the effect of symbols being "knowable" by name by using registered (global) symbols:
var s1 = Symbol.for("foo");
var s2 = Symbol.for("foo");
s1 === s2; // true
Of course you can create your own Symbol registry too, with a Map instance or a plain object.
edit — I'll add that the intention of the optional string parameter when making a new Symbol instance is to provide a way of identifying the meaning and purpose of a symbol to the programmer. Without that string, a Symbol works just fine as a Symbol, but if you dump out an object in a debugger the properties keyed by such anonymous Symbol instances are just values. If you're keeping numeric properties on an object with Symbol keys, then you'll just see some numbers, and that would be confusing. The description string associated with a Symbol instances gives the programmer reference information without compromising the uniqueness of the Symbol as a key value.
Finally, you can always compare the result of calling .toString() on two similarly-constructed Symbol instances. I suspect that that practice would be considered questionable, but you can certainly do it.
edit more — it occurs to me that the fact that the default behavior of Symbol creation in JavaScript makes the type more useful than, say, atoms in Erlang or keys in Clojure. Because the language provides by default a value guaranteed to be unique, the fundamental problem of namespace collision is solved pretty nicely. It's still possible to work with "well-known" symbols, but having unique values available without having to worry about conflicts with other code that might also want to avoid collisions is nice. JavaScript has the somewhat unique, and certainly uniquely pervasive and uncontrollable, problem of a global namespace that may be polluted by code that a programmer does not even know exists, because code can collide in the browser enviroment due to the actions of a party different from, and unknown to, an arbitrary number of software architects.

Javascript convention when clashing with a reserved word

In python, when a variable name clashes with a reserved word (like in class, in, default, etcetera), the PEP8 convention states that a trailing underscore should be used (class_, in_, default_).
What is the most shared javascript convention for the same case?
As far as I know there isn't one. Basically you just avoid using reserved words. For class, for instance, I've seen: Class, cls, klazz, clazz, and className. As a further example, when doing the mappings of attributes to properties on DOM elements (which are ovewhelmingly used from JavaScript), the W3C folks went with className (for class), htmlFor (for for), cssFloat (for float), and such. I've never seen someone use a trailing _. (A leading _, on the other hand, is quite common — people use it for properties of objects they want people to consider private.)
When doing a property, technically you don't have to worry about it, because technically property names can be reserved words according to the specification, as the parser has enough context to know that the property name isn't something else. (That doesn't mean all implementations will get it right, and I don't recommend it.) This is because property names are just required to be what the spec calls IdentifierName, not Identifier. (Identifier is literally "IdentifierName but not ReservedWord").
For those who prefer not to risk it with property names, the common way to do it is to use quotes:
var obj = { "class": "is perfectly fine" };
// Access
console.log(obj["class"]);

unique preceding namespace characters for JS variables to handle scope

In different languages, you can have different characters in the variable names, and they also limit what can be the first character vs other characters as being legal.
In JS, what are these characters that are NOT used by other libraries? so that You can safely name a variable and nested ones that link to the global variable as you go down the rabbit hole in scope.
I am currently using underscore.js, so preceding a variable with _ can/could be problematic. Same goes with JQuery, and using $. I am getting errors if I try a ruby identifier such as # or ~, and I dont want to use . or # to avoid confusion with CSS selectors.
What do you know of (or suggest) to precede the variable names with to avoid confusion and overloading.
I would love a/several unique "golden" character(s), but realize this may be dependent on the stacks of libraries the project is using, so for this current project I am using: require, d3, jquery, underscore, backbone, text, dispatch.
sample code:
// for each measure in measuresCollection
_.each(this.measuresCollection.models, function(measure, index) {
var `this = this;
for (i=0; i<length; i++){
// ... some code with new preceding variable name `this
}

Using reserved words as property names, revisited

Can a reserved word be used as an object's property name?
This issue was raised indirectly in a previous Stack Overflow question: Browser support for using a reserved word as a property name in JavaScript. The answer seemed general consensus by Alex Wayne:
You can use those words, but only as strings and not shorthand
properties.
foo['class']; // cool
foo.class; // not cool
While I think that they are probably more knowledgeable than me in this area and it is probably a bad idea to use reserved words in some situations, I think their conclusion is wrong based on two points:
testing of the reserved words using them as a "shorthand" properties
the HTMLFormElement makes it impossible not to use reserved words in "shorthand"
First, using the reserved word list, each was added as a property to an Object and HTMLElement, both as obj["word"] and obj.word, and then retrieved as obj["word"] and obj.word. In each of the 63 cases all eight tests worked correctly.
Second, the HTMLFormElement necessitates this works because it retrieves in its elements using shorthand notation. If <input name='typeof' value='scalar' /> is an element of a form, then form.typeof == "scalar".
From my experience, reserved words are usually data inflicted (e.g. a column named "private"), not program inflicted. As such they contaminate JSON objects, and from there input, and from there the HTMLFormElement. Simply put, without a huge amount of (IMHO unnecessary) work, it's impossible to keep reserved words not being forced to work correctly in shorthand.
It seems to me these real problems:
care needs to be taken not to conflict with existent properties, not reserved words
(many if not all) variables cannot be reserved words
use of reserved words as properties can be (but are not necessarily) confusing
Is this conclusion correct then, that reserved words as property names, and accessing them either as strings or shorthand, is just fine - as long as a little common sense is applied to the situation?
In ECMAScript, starting from ES5, reserved words may be used as object property names "in the buff". This means that they don't need to be "clothed" in quotes when defining object literals, and they can be dereferenced (for accessing, assigning, and deleting) on objects without having to use square bracket indexing notation.
That said, reserved words may still NOT be used as identifier names. This is stated quite unambiguously in the spec and is stated somewhat emphatically here (if you don't want your eyes to bleed by having to read the actual language spec)...
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Reserved_Words
The following are keywords and may not be used as variables,
functions, methods, or object identifiers, because ECMAScript
specifies special behavior for them:
I'm not quite sure what the point is you want to make, so the only answer I can give is: Yes, it's ok to use reserved words as property names.
(However two small remarks: foo["class"] is ok, not foo[class]. And any way you should be using form.elements["xyz"] and not form.xyz to access an element named xyz.)
Yes, it can be used.
Just small remark, if you use YUI compressor you have to put property name which is equal to one of js reserved words in quotes.
For example, this won't compress
var a = { case : "foo"}; // syntax error, "invalid property id"
a.for = "bar"; // syntax error, "missing name after . operator"
This will do
var a = { "case" : "foo"}; //OK
a["for"] = "bar"; //OK
Here is Online JavaScript/CSS Compression Using YUI Compressor where this can be tested.
Yes, in most browsers (including IE9+)
There's actually an entry in the Kangax compatibility table for "Reserved words as property names"
http://kangax.github.io/compat-table/es5/#test-Object/array_literal_extensions_Reserved_words_as_property_names

Why Javascript doesn't include reserved keywords such as "Object", "Array", "Function", "Number" ...?

Some SPECIAL words such as Object, Array, Function, Method, Number etc are not belong to keywords in Javascrpt:
Reserved Keywords in Javascript.
But I have to use them carfully, they are not NORMAL words as object, array, method, number, foo ...
I'd like to know how many such SPECIAL words we have? Pls give me the list.
It all boils down to one thing, really: JavaScript is case sensitive. That's why it makes a distinction between Object and object.
Object, Array, Function and Number are not keywords, nor are they exactly "special" (whatever you think they mean) words.
They're nothing more than built-in function/class types in JavaScript (you can do a typeof on them and see). You don't directly use them often now though since there are syntactic alternatives to creating objects of each of those types, for example:
var obj = {};
var func = function() {};
var arr = [];
var num = 123;
The others you mention (object, array, method, number, foo) aren't keywords or "special" words either simply because, since as I say JavaScript is case sensitive, they mean nothing in JavaScript compared to their capitalized counterparts. Unless, of course, you give them meaning yourself by declaring variables with those names.
Just to clarify, "function" is a reserved word, "Function" is a predefined object in the global scope.
The special words you list (although I'm not sure about "Method"?) are predefined JavaScript Classes and Objects in the global scope. They aren't necessarily reserved words because they aren't part of the language syntax and can, in some cases, be overridden. But yes, ordinarily they should not be used and should otherwise be treated the same way as 'reserved words'. See also Global Properties and Methods.
EDIT: With reference to the list provided at developer.mozilla.org/en/JavaScript/Reference/Global_Objects - this appears to be a list of the core JavaScript Objects, irrespective of whether the JavaScript engine is running in the browser or not. This is a sub-list of the list provided at About.com. Although why 'Boolean' is omitted from the list of Global Objects at About.com I don't know - this does appear to be an omission?
Other objects defined by the (Mozilla) browser/DOM are listed in the Gecko DOM Reference.

Categories