2. Agenda
2 minutes of bla bla!
Setting the environment
ES6 Features…the coolest
Tips and Questions
3. History
May 1995, Created in ten days by Brendan Eich at Netscape
1997, Standardization ECMA-262 Ed. 1: ”ECMAScript” aka ES1
1999, ES3 − modern JS baseline
2009, ES5 − “use strict”, JSON, Object.create, etc.
June 2015, Official ES2015 release
4. ECMAScript or JavaScript?
ECMAScript is the name of the international
standard that defines the JavaScript language
“ECMAScript is based on several originating
technologies, the most well-known being JavaScript
(Netscape) and JScript (Microsoft)”
ECMAScript 2015
ECMAScript 6th version = ES6
6. Transpilers
“A source-to-source compiler, transcompiler or transpiler is a
type of compiler that takes the source code of a program written
in one programming language as its input and produces the
equivalent source code in another programming language”
9. Classes
ES6 Classes are syntactical sugar over existing prototype-based inheritance
Clearer syntax to create objects and deal with inheritance
The constructor method is a special method for creating and initializing an object
Properties can only be created inside a class constructor or method
Cannot be defined more than once
function Person(name, age) {
this.name = name;
}
Person.prototype.whoAreYou = function () {
console.log("I'm " + this.name);
}
class Person {
constructor(name, age) {
this.name = name;
}
whoAreYou() {
console.log("I'm " + this.name);
}
}
10. Getters and Setters
Classes allow you to define accessor properties on the prototype
The syntax for getters and setters is just like in ES5 object literals
class Person{
constructor(){
}
set firstName(fName){
this.fName = fName;
}
set lastName(lName){
this.lName = lName;
}
get name(){
return this.fName + " " + this.lName;
}
}
11. Static Members
ES6 classes simplify the creation of static members
Using static annotation before the method or accessor property
name
Can help to create a singleton class
class Foo {
constructor(prop) {
this.prop = prop;
}
static className() {
return 'Foo';
}
}
Foo.className();
12. Inheritance
The extends keyword is used to create a class as a child of another class
The super keyword is used to call functions on an object's parent.
class Rectangle {
constructor(length, width) {
this.length = length;
this.width = width;
}
getArea() {
return this.length * this.width;
}
}
class Square extends Rectangle {
constructor(length) {
super(length, length); // same as Rectangle.call(this, length, length)
}
}
14. Modules
Modules are JavaScript files that are loaded by parts
Ability to export and import only bindings you need (rather than
everything in a file)
anonymous functions or classes can be exported only using
default
import http from './src/http';
http.request('views/welcome.html')
class Http {
constructor() {
// do something
}
}
export default new Http();
15. Multiple Modules
// export data
export var color = "red";
export let name = "Roger";
export const magicNumber = 7;
// export function
export function sum(num1, num2) {
return num1 + num1;
}
// export class
export class Person {
constructor(name, width) {
this.name = name;
}
}
// define a function...
function multiply(num1, num2) {
return num1 * num2;
}
// ...and then export it later
export {multiply as kefel};
import {
color,
name,
magicNumber,
sum,
Rectangle,
multiply
} from './src/sample'
import {color} from './src/sample';
import {name} from './src/sample';
import {magicNumber} from './src/sample';
import {sum} from './src/sample';
import {Rectangle} from './src/sample';
import {kepel as multiply} from './src/sample'
import * as sample from './src/sample';
16. Modules are different
Automatically runs in strict mode
Variables in the top level of a module aren't added to the shared
global scope
‘this’ in the top level of a module is undefined
Must export anything that should be available to code outside of
the module
Modules may import bindings from other modules
In Node.js, the .mjs file extension signifies that the file should be
loaded as a JavaScript module
19. Hoisting, what?
Using var, the variables are set at the top of the function
Initialization remains in the same place
Functions and “global scope” are the unique scope know
function hoistingme(max) {
for (var i = 0; i <= max; i++) {
console.log(i);
}
alert(i); //--> i==?
}
hoistingme(10);
20. Block Declarations: Let & Const
Accessible only inside the scope as many C-base languages
function donthoistingme(max) {
for (let i = 0; i <= max; i++) {
console.log(i);
}
alert(i); //--> ReferenceError: i is not defined
}
const loops = 10;
hoistingme(loops);
21. Objects into Const
Objects declared with const can be modified (partially)
Prevent modification of the bindings, not of the value
const person = {
name: "Sebastian”
}
person = {
name: "Sebastian",
email: "sebastianp@sela.co.il"
} //--> Assignment to constant variable
const person = {
name: "Sebastian"
}
person.name = "Seba";
person.email = "sebastianp@sela.co.il";
22. Let & Const…more
No redeclaration…cannot be decleared twice
Const must be initialized on declaration
Variables declared with let & const cannot be accessed before
declaration – Temporal Dead Zone
let and const are safe to use in the global scope when you don't
want to create properties on the global object because cannot
be declare more than once
23. Loops
var funcs = [];
for (var i = 0; i < 10; i++) {
funcs.push(function () {
console.log(i);
});
}
funcs.forEach(function (func) {
func();
});
24. Loops
var funcs = [];
for (var i = 0; i < 10; i++) {
funcs.push((function (value) {
return function () {
console.log(value);
}
}(i)));
}
funcs.forEach(function (func) {
func();
});
25. Loops
var funcs = [];
for (let i = 0; i < 10; i++) {
funcs.push(function () {
console.log(i);
});
}
funcs.forEach(function (func) {
func();
});
26. Loop...special behavior
Each iteration, the loop created a new variable (i)
And initialize the value
Inside the loop gets its own copy of I
The behavior of let declarations in loops is a specially-defined behavior in
the specification
Consts cannot be used in for loops
But can be used in for-in and for-of loops
for (let i = 0; i <= max; i++) {
let i = 10;
console.log(i);
}
27. use const by default and only use let when
you know a variable's value needs to
change
29. Template Literals
“This scheme extends ECMAScript syntax with syntactic sugar to allow
libraries to provide DSLs that easily produce, query, and manipulate
content from other languages that are immune or resistant to
injection attacks such as XSS, SQL Injection, etc”
New strings delimited by backticks (`)
Comes to solve the following problems:
Multiline strings A formal concept of multiline strings
Basic string formatting The ability to substitute parts of the string for values
contained in variables
HTML escaping The ability to transform a string such that it is safe to insert into
HTML.
30. More templates
let count = 10;
let price = 0.25;
let message = `
<h1>Items</h1>
<h2>
All ${count} items will cost US$ ${(count * price).toFixed(2)}
</h2>`;
document.querySelector('body').innerHTML = message;
32. Arrow Functions
More concise syntax for writing function expressions
Arrow functions are anonymous
Binds “this” in a different way…as we expect! No ’this’ binding
setTimeout( (d)=>{
console.log('This is an Arrow Function', d);
}, 1000, "data data” );
setTimeout(d=>console.log('This is an Arrow Function', d), 1000, "data data");
setTimeout(function(d) {
console.log('This is an Arrow Function', d);
}, 1000, "data data");
33. Arrow Functions…more samples
const squares = arr.map(x => x * x);
var squares = arr.map(function (x) {
return x * x
});
var sum = (num1, num2) => num1 + num2;
var sum = function(num1, num2) {
return num1 + num2;
};
var utils = {
foo: function () {
setTimeout(()=>this.bar(), 500);
},
bar: function () {
console.log("hello");
}
}
utils.foo(); //hello
var utils = {
foo: function() {
setTimeout(function() {
this.bar();
}, 500);
},
bar:function(){
console.log("hello");
}
}
utils.foo(); // this.bar is not a function
34. Arrow Functions – Not a Traditional Function
No this, super, arguments, and new.target bindings
Cannot be called with new
No prototype
No arguments object
No duplicate named arguments
Can't change this
36. Default Parameters - Mimic in ES5
function Person(name, age) {
this.age = age || -1;
console.log("Age: " + this.age);
}
var joey = new Person("Joey", 48);
Age: 48
var ross = new Person("Ross");
Age: -1
var chandler = new Person("Chandler", 0);
Age: -1
37. Arguments in ES5
In ECMAScript 5 the arguments object reflects changes in the
named parameters of a function…weird!
function calc(firstNum, secondNum) {
console.log(arguments[0] * arguments[1]);
firstNum++
secondNum++;
console.log(arguments[0] * arguments[1]);
}
calc(2, 3);
//<-- 6
//<-- 12
38. Default Parameter
In ES6, a parameter default value is only triggered by undefined
Always behave in the same manner as ECMAScript 5 strict mode
function calc(firstNum = 0, secondNum = 0) {
console.log(arguments[0] * arguments[1]); //<-- 6
firstNum++;
secondNum++;
console.log(arguments[0] * arguments[1]); //<-- 6
}
calc(2, 3);
39. Expressions as Default Parameters
Default values not need to be primitives
The expression will be only called when “sleep” function is called
without a second parameter
function calculateSecond(){
return Math.round(Math.random()*1000);
}
function sleep(delay = calculateSecond()) {
console.log(delay);
//do something
}
sleep(); // 437
sleep(); // 755
40. Default Values and the Temporal Dead Zone
function sum(firstNum = secondNum, secondNum = 0) {
console.log(firstNum + secondNum);
}
sum(); //ReferenceError: secondNum is not defined
function sum(firstNum = 0, secondNum = firstNum) {
console.log(firstNum + secondNum);
}
sum(); //0
41. Arguments and Default Parameters
The presence of default parameter values triggers the
arguments object to remain detached from the named
parameters
function sum(firstNum = 0, secondNum = 0) {
console.log(arguments[0] * arguments[1]); //<-- NaN
console.log(firstNum++ * secondNum++); //<-- 0
console.log(arguments[0] * arguments[1]); //<-- NaN
}
sum(2);
42. No more arguments!... Rest of Parameters
Rest Parameters syntax allows us to represent an indefinite
number of arguments as an array
Unlike arguments, Rest Parameters is an Array object
function log(severity, message, ...values){
console[severity].call(console, message, values);
}
log('error', 'some error', "exception", "exceptionDetails");
log('log', 'everything OK', 'SDP2016');
43. The Spread Operator
The JavaScript engine then splits the array into individual
arguments and passes them in.
Calling to Math.max dynamically
let values = [25, 50, 75, 100];
Math.max(...values); // 100
Math.max(...values, 9999); // 9999
let values = [25, 50, 75, 100];
Math.max.apply(Math, values); // 100
45. New Methods – Object.assign()
Used to copy the values of all enumerable own properties from one or
more source objects to a target object
Ignores inherited properties
Similar to $.extend() or angular.extend()
//Cloning an object
var obj = {a: 1};
var copy = Object.assign({}, obj);
//Merging objects
var o1 = {a: 1}, o2 = {b: 2}, o3 = {c: 3};
var obj = Object.assign(o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
console.log(o1); // { a: 1, b: 2, c: 3 }, target object itself is changed.
46. New Methods…more
Object.is() method determines whether two values are the same
value
Object.is(NaN, 0/0)
Object.getOwnPropertySymbols() method returns an array of all
symbol properties found directly upon a given object
Object.setPrototypeOf() method sets the prototype (i.e., the
internal [[Prototype]] property) of a specified object to another
object or null.
47. Property value shorthands
Abbreviate the definition of a property in an object literal
Can omit the key when the key and variable are the same
function makeRequest(method, uri){
return {
method,
uri
}
}
function makeRequest(method, uri){
return {
method: method,
uri: uri
}
}
48. Computed Property Names
Allows you to put an expression in brackets [], that will be
computed as the property name
let obj = {
prop: "bla bla",
["new foo"]: "new foo",
["new bar"]: "very new foo",
["dyna" + ”mic"]: "dynamic prop”
}
let obj = {
prop: "bla bla”
}
obj["new foo"] = "foo";
obj["new bar"] = "very new foo";
obj["dyna" + "mic"] = "dynamic prop";
49. Object destructuring
Process of breaking a data structure down into smaller parts
How to extract the values is specified via patterns
let request = {
uri: "http://service.com",
method: "GET”
};
let {uri, method = "GET"} = request;
let request = {
uri: "http://service.com",
method: "GET”
};
// extract data from the object
let uri = request.uri;
let method = request.method || "GET";
let obj = {x: 4, y: 1};
let {x, y} = obj;
let obj = {x: 4, y: 1};
let x = obj.x;
let y = obj.y;
50. Nested Object Destructuring
let {loc: {start}} = node;
let {loc:{end:{line, column}}} = node;
let node = {
name: "foo",
loc: {
start: {
line: 1,
column: 1
},
end: {
line: 1,
column: 4
}
}
};
let start = node.loc.start;
let line = node.loc.end.line;
let column = node.loc.end.column;
The destructuring pattern can uses curly braces to indicate that
the pattern should descend into the property named loc on
node and look for the start/end property
51. Array Destructuring
let colors = ["red", ["green", "lightgreen"], "blue"];
let [ firstColor, [ secondColor ] ] = colors;
let colors = [ "red", "green", "blue" ];
let [ firstColor, ...restColors ] = colors;
console.log(firstColor); // "red”
console.log(restColors.length); // 2
console.log(restColors[0]); // "green”
console.log(restColors[1]); // "blue"
let countries = [ "Israel", "USA", "UK", "Italy" ];
let [ israel, , , italy, spain = "Spain" ] = countries;
53. Use Case…Function Parameters
function $http(requestConfig) {
var url = requestConfig.url,
method = requestConfig.method || 'GET,
headers = requestConfig.headers,
data = requestConfig.data;
//Rest of the code
}
function $http({url, method= 'GET', headers = {}, data = {}}) {
//Rest of the code
}
$http({
url: 'http://www.api.com',
method: 'POST’
});
55. Promises
Promises are an alternative to callbacks for delivering the results
of an asynchronous computation
Can chain promises together based on success or failure in ways
that make your code easier to understand and debug.
ajax("http://www.filltext.com/?rows=10&fname={firstName}&lname={lastName}")
.then( (data) => {
console.log(data);
})
.catch( (err) => {
console.error(err);
});
56. Promises…sample
function ajax(url, method = 'GET') {
return new Promise( (resolve, reject) => {
let client = new XMLHttpRequest();
client.onload = function () {
if (this.status >= 200 && this.status < 300) {
// "resolve" when this.status is equal to 2xx
resolve(this.response);
} else {
// "reject" when this.status is different than 2xx
reject(this.statusText);
}
};
client.onerror = function () {
reject(this.statusText);
};
client.open(method, url);
client.send();
});
}
57. Then/Catch returns a new promise
var p = ajax("https://www.filltext.com/?rows=10&fname={firstName}")
.then((data) => {
console.log('first then', data.length);
return ([]);
})
.then((data) => {
console.log('second then', data.length);
return ([]);
});
p.then((d, num) => {
console.log(’third then', d.length);
});
58. Multiple Promises
var p1 = ajax("https://www.filltext.com/?rows=10&fname={firstName");
var p2 = ajax("https://www.filltext.com/?rows=20&fname={firstName}");
var p3 = ajax("https://www.filltext.com/?rows=30&fname={firstName}");
Promise.all([p1, p2, p3])
.then((values) => {
console.log(values.length); //length: 3
})
.catch((err) => {
console.log(err);
});
61. Symbols
Symbols are a new primitive type in ECMAScript 6
Symbols began as a way to create private object members
The Symbol object is an implicit object wrapper for the symbol
primitive data type
let sym1 = Symbol(),
sym2 = Symbol("foo"),
sym3 = Symbol("foo");
sym2 == sym3; // false
Symbol("foo") === Symbol("foo"); // false
62. Symbols as properties
The symbol firstName is created and used to assign a new
property on the person object
let name = Symbol("name");
let person = {
[name]: "Albert Einstein”
};
person[name]; //Albert Einstein
Object.keys(person).length; //0
let symbols = Object.getOwnPropertySymbols(person);
symbols[0] //Symbol(first name)
63. Always providing a description to make
both reading and debugging symbols
easier.
1995 the languages was called Mocha
ES4 (2007/2008) would have been the first major update to ECMAScript since the third edition was published in 1999.
classes
a module system
optional type annotations and static typing
generators and iterators,
destructuring assignment
algebraic data types.
ES4 The update has not been without controversy.
Wilson (microsoft) cautioned that because the proposed changes to ECMAScript made it backwards incompatible in some respects to earlier versions of the language
ES5 promoted by Yahoo, Microsoft, Google
This standardized version of JavaScript, called ECMAScript
Not part of W3C
Latest Chrome & FF support most of the features
SourceMap
webpack is a module bundler.
Nicholas Zakas
Axel Rauschmayer
Sugar Syntax
Clear syntax
Still a function: typeof Person == “function”
Interesting:
Special "constructor" method
Calling the class constructor without 'new' throws an error.
Class are not hoisted.
Only methods - no data properties
Cannot overwrite the class!
All code inside of class declarations runs in strict mode
All methods are non-enumerable
Classes and functions are similar in that they have two forms: declarations and expressions
Classes as First-Class CitizensIn programming: when it can be used as a value
meaning it can be passed into a function, returned from a function, and assigned to a variable
Classes also allow using Computed Member Names
Static members are not accessible from instances.
You must always access static members from the class directly.
Keywords:
extends
super
if you specify a constructor on “derived classes” require you to use super();
if you don't, an error will occur.
Classes that inherit from other classes are referred to as derived classes.
Inheriting from Built-ins
In ECMAScript 5 and earlier, this wasn't possible
ECMAScript 6 classes allows inheritance from all built-ins
Can use "new.target" in Class Constructors in order to create abstract classes
Class declarations or class expressions
If there is no constructor, then super() is automatically called for you with all arguments upon creating a new instance of the class
If a base class has static members, then those static members are also available on the derived class
You can use extends with any expression as long as the expression resolves to a function with [[Construct]] and a prototype
Abstract classes
constructor() {
if (new.target === Shape) {
throw new Error("This class cannot be instantiated directly.")
}
}
JavaScript has had modules for a long time. However, they were implemented via libraries, not built into the language.
No supported in any browser! need transpilers
Modules are isolated!
ES6 is the first time that JavaScript has built-in modules.
Can't export anonymous functions or classes using this syntax unless you use the default keyword
When importing a binding from a module, the binding acts as if it were defined using const. That means you can't define another variable with the same name (including importing another binding of the same name), use the identifier before the import statement, or change its value.
no matter how many times you use a module in import statements, the module will only be executed once
Show also the “as” in order to change the alias
Some modules may not export anything, and instead, only make modifications to objects in the global scope.
Even though top-level variables, functions, and classes inside modules don't automatically end up in the global scope, that doesn't mean modules cannot access the global scope
<script type="module"> always acts as if the defer attribute is applied.
The defer attribute cause the module file begins downloading as soon as the HTML parser encounters <script type="module"> with a src attribute but doesn't execute until after the document has been completely parsed.
Modules are also executed in the order in which they appear in the HTML file
async causes the script file to be executed as soon as the file is completely downloaded and parsed.
The order of async scripts in the document doesn't affect the order in which the scripts are executed
The scripts are always executed as soon as they finish downloading without waiting for the containing document to finish parsing.
Worker modules are generally the same as worker scripts, but there are a couple of exceptions.
Worker scripts are limited to being loaded from the same origin as the web page in which they are referenced, but worker modules aren't quite as limited.
Although worker modules have the same default restriction, they can also load files that have appropriate Cross-Origin Resource Sharing (CORS) headers to allow access.
Another restriction, while a worker script can use the self.importScripts()method to load additional scripts into the worker, self.importScripts() always fails on worker modules because you should use import instead.
Automatically runs in strict mode
Variables in the top level of a module aren't added to the shared global scope
‘this’ in the top level of a module is undefined
Must export anything that should be available to code outside of the module
Modules may import bindings from other modules
In Node.js, the .mjs file extension signifies that the file should be loaded as a JavaScript module
The result is 11
Immediately-Invoked Function Expression (IIFE)
Block-level declarations are those that declared variables are accessible only inside the inside scope
Block scopes are also called “lexical scopes”
Inside functions or block { and }
A const declaration prevents the modifications of the bindings but not of the value
No redeclaration…cannot be decleared twice
don’t even start to run
Error: Identifier 'x' has already been declare
Const must be initialized on declaration
Variables declared with let & const cannot be accessed before declaration (even with typeof) – Temporal Dead Zone
let and const are safe to use in the global scope when you don't want to create properties on the global object because cannot be declare more than once
Temporal Dead Zone (TDZ) is not defined in ECMAScript specification – The community calls it like that
// outputs the number "10" ten times
// Sample in ES5
The solution is use Immediately-Invoked Function Expression (IIFE)
mimicking what the IIFE (immediately-invoked function expressions)
On each iteration, the loop creates a new variable and initializes it to the value of the variable with the same name from the previous iteration
On each iteration, the loop creates a new variable and initializes it to the value of the variable with the same name from the previous iteration
The same is true for for-in and for-of loops
Each time through the loop, a new keybinding is created, and so each function has its own copy of the key variable
It's important to understand that the behavior of let declarations in loops is a specially-defined behavior in the specification and is not necessarily related to the non-hoisting characteristics of let
In fact, early implementations of let did not have this behavior, as it was added later on in the process.
The for-in and for-of loops work with const because the loop initializer creates a new binding (storage space) on each iteration through the loop rather than attempting to modify the value of an existing binding (as was the case with the previous example using for instead of for-in).
const works like var, but you can’t change the initial value of a const-declared variable:
Template strings add new syntax to allow the creation of domain-specific languages (DSLs) for working with content in a way that is safer than the solutions we have today.
DSL: A domain-specific language (DSL) is a computer language specialized to a particular application domain
A tag is simply a function that is called with the processed template literal data.
The tag receives data about the template literal as individual pieces and must combine the pieces to create the result
backticks
Functions have some problems, default parameters, arguments, etc...
let see some of them!
Cannot be used to define new types
this is evident from the missing prototype property
No constructor
Use ”that” pattern or “bind”
The value of Constructor, this, super, arguments, and new.target inside of the function is by the closest containing non-arrow function
No [[Construct]] method and therefore cannot be used as constructors.
Arrow functions throw an error when used with new.
Since you can't use new on an arrow function, there's no need for a prototype.
The prototype property of an arrow function doesn't exist.
Must rely on named and rest parameters to access function arguments
As nonarrow functions that cannot have duplicate named arguments only in strict mode.
The value of this inside of the function can't be changed. It remains the same throughout the entire lifecycle of the function.
parameter default value is only triggered by undefined
Always behave in the same manner as ECMAScript 5 strict mode
Be careful if you forget the parentheses, you are passing a reference to the function rather than the result of the function call.
Arguments.length == 1, because the second arguments wasn’t passed!
we want to build a "log" function
Restriction:
Can be only one rest parameter
The rest parameter must be last
The second restriction is that rest parameters cannot be used in an object literal setter.
This restriction exists because object literal setters are restricted to a single argument
JavaScript engine then splits the array into individual arguments and passes them in.
Copy values between objects!
O1 changed
Object.assign(target, ...sources)
-
Object.assign() doesn’t work well for moving methods
you can’t move a method that uses super
SetPrototypeOf a very slow operation
Changing the [[Prototype]] of an object is, by the nature of how modern JavaScript engines optimize property accesses, a very slow operation, in every browser and JavaScript engine.
In ES66, you can eliminate the duplication that exists around property names and local variables by using the property initializer shorthand
When a property in an object literal only has a name, the JavaScript engine looks into the surrounding scope for a variable of the same name
Property value shorthands work well together with destructuring (last example)
The makeRequest() function creates an object whose property names are the same as the function parameter names. The result appears to be duplication of name and age even though one is the name of an object property while the other provides the value for that property
In ECMAScript 6, computed property names are part of the object literal syntax, and they use the same square bracket notation that has been used to reference computed property names in object instances
Destructuring is a convenient way of extracting values from data stored in (possibly nested) objects and Arrays.
When using destructuring to declare variables using var, let, or const, you must supply an initializer (the value after the equals sign).
It can be used in locations that receive data (such as the left-hand side of an assignment).
Assigning to Different Local Variable Names
let { type: localType, name: localName } = node;
Assigning to Different Local Variable Names
let { type: localType, name: localName } = node;
This approach works
you can't tell what input the function expects
just by looking at the function definition; you need to read the function body.
There are several implementation of Promises patters
Two states
Fulfilled
Rejected
Both arguments to then() are optional, so you can listen for any combination of fulfillment and rejection.
No callback-hell
Promise.race()
returned promise is settled as soon as the first promise is settled
A Symbol is a primitive data type whose instances are unique and immutable.
In some programming languages they are also called atoms.
Because symbols are primitive values, calling new Symbol() throws an error when called
A symbol never clashes with any other property key (symbol or string)
Use Symbol.for("") in order to create a symbol to be shared!
Use .toString to get the “string” of the symbol
Symbol.for("uid") === Symbol.for("uid")
A Symbol is a primitive data type whose instances are unique and immutable.
In some programming languages they are also called atoms.
Because symbols are primitive values, calling new Symbol() throws an error when called
A symbol never clashes with any other property key (symbol or string)