Category Archives: javascript

Symbols in JS, and why

ref –

  • https://www.keithcirkel.co.uk/metaprogramming-in-es6-symbols/
  • https://flaviocopes.com/javascript-symbols/
  • https://medium.com/intrinsic/javascript-symbols-but-why-6b02768f4a5c
  • https://javascript.info/symbol

Basics info

A symbol represents a unique identifier.
A value of this type can be created using Symbol():

Upon creation, we can give the symbol a description (also called a symbol name) , mostly useful for debugging purposes:

Symbols are guaranteed to be unique. Even if we create many symbols with the same description, they are different values. The description is just a label that doesn’t affect anything.

For instance, here are two symbols with the same description – they are not equal:

…But if we used a string “id” instead of a symbol for the same purpose, then there would be a conflict:

“Hidden” properties

Symbols allow us to create hidden properties of an object, that no other part of code can accidentally access or overwrite.

For instance, if we’re working with user objects, that belong to third-party code. We’d like to add identifiers to them.

Let’s use a symbol key for it:

What’s the benefit of using Symbol(“id”) over a string “id”?

As user objects belong to another code, and that code also works with them, we shouldn’t just add any fields to it. That’s unsafe. Notice the public use of string “name” to change user object value.

But a symbol cannot be accessed accidentally, the third-party code (hidden away in some module) cannot be accessed by us.

Also, imagine that another script wants to have its own identifier inside ‘user’, for its own purposes. That may be another JavaScript library so that the scripts are completely unaware of each other.

Then that script can create its own Symbol(“id”), like this:

Now, there will be no conflict between the original and other id values, because symbols are always different, even if they have the same name.

…But if we used a string “id” instead of a symbol for the same purpose, then there would be a conflict:

Symbols in a literal

If we want to use a symbol in an object literal {…}, we need square brackets around it.

Like this:

That’s because we need the value from the variable id as the key, not the string “id”.

Symbols are skipped by for…in

For…in iterates through all the indexes of an object/array.
However, symbolic properties do not participate in for..in loop.

For instance:

Object.keys(user) also ignores them.

That’s a part of the general “hiding symbolic properties” principle.

If another script or a library loops over our object, it won’t unexpectedly access a symbolic property.

In contrast, Object.assign copies both string and symbol properties:

There’s no paradox here. That’s by design. The idea is that when we clone an object or merge objects, we usually want all properties to be copied (including symbols like id).

Other Stuff

object keys could only be strings

If we ever attempt to use a non-string value as a key for an object, the value will be coerced to a string. We can see this feature here:

A symbol is a primitive which cannot be recreated

They are useful in situations where disparate libraries want to add properties to objects without the risk of having name collisions.

For example:

By making use of symbols, each library can generate their required symbols upon instantiation. Then the symbols can be checked on objects, and set to objects, whenever an object is encountered.

For this reason, it would seem that symbols do benefit JavaScript.
However, you may be wondering, why can’t each library simply generate a random string, or use a specially namespaced string, upon instantiation?

Well, you’d be right. This approach is actually pretty similar to the approach with symbols. Unless two libraries would choose to use the same property name, then there wouldn’t be a risk of overlap.

Object.keys() does not return symbols

Here is an example of using a symbol as a key within an object:

Notice how they are not returned in the result of Object.keys(). This is, again, for the purpose of backward compatibility. Old code isn’t aware of symbols and so this result shouldn’t be returned from the ancient Object.keys() method.

In addition to that, Symbols do not show up on an Object using for in, for of or Object.getOwnPropertyNames – the only way to get the Symbols within an Object is Object.getOwnPropertySymbols:

This means Symbols give a whole new sense of purpose to Objects – they provide a kind of hidden under layer to Objects – not iterable over, not fetched using the already existing Reflection tools and guaranteed not to conflict with other properties in the object!

Symbols are completely unique…

By default, each new Symbol has a completely unique value. If you create a symbol (var mysym = Symbol()) it creates a completely new value inside the JavaScript engine. If you don’t have the reference for the Symbol, you just can’t use it.
This also means two symbols will never equal the same value, even if they have the same description.

Well, there’s a small caveat to that – as there is also another way to make Symbols that can be easily fetched and re-used: Symbol.for(). This method creates a Symbol in a “global Symbol registry”. Small aside: this registry is also cross-realm, meaning a Symbol from an iframe or service worker will be the same as one generated from your existing frame:

Cross Realm

Problem:

main usage

Macros
As a unique value where you’d probably normally use a String or Integer:
Let’s assume you have a logging library, which includes multiple log levels such as logger.levels.DEBUG, logger.levels.INFO, logger.levels.WARN and so on. In ES5 code you’d like make these Strings (so logger.levels.DEBUG === ‘debug’), or numbers (logger.levels.DEBUG === 10). Both of these aren’t ideal as those values aren’t unique values, but Symbols are! So logger.levels simply becomes:

A place to put metadata values in an Object

You could also use them to store custom metadata properties that are secondary to the actual Object. Think of this as an extra layer of non-enumerability (after all, non-enumerable keys still come up in Object.getOwnProperties). Let’s take our trusty Collection class and add a size reference, which is hidden behind the scenes as a Symbol (just remember that Symbols are not private – and you can – and should – only use them in for stuff you don’t mind being altered by the rest of the app):

WeakSet and Set in JS

Generally, references to objects are strongly held in JavaScript, meaning that as long you have a reference to the object, it won’t be garbage-collected.

Here, the literal object has retain count of 1 because ref is pointing to it.

A Set can hold characters, numbers, symbols, and objects.

Primitive values are not referenced, rather it literal values.
If we were to add an object, it will be strongly referenced.
That’s why for Sets, we can add them all. It goes with the meaning of Set, which is strongly hold on to the values/objects.

Let’s test this with some code.

Set

Double click on the index.html to run it. Click the button and you’ll see the Set’s data being displayed. The Set has a weak reference to the objects we declared. Since our output is currently displayed, there is a strong reference to the Set data structure. In order to demonstrate our Set and weak Set, we must get rid of any external references.

et’s clear the console so that we let the JS engine know to get rid of this string reference.

Once the console is empty, let’s click on the Performance tab. This way, the garbage collector will collect any JS objects with zero references on them.

Now go back to the console, click on the button, and look at the Set’s data output. There are still two objects in there. That is because Set has a strong reference to our objects. These objects still has a retain count of 1. Thus, when the garbage collector saw this, it didn’t garbage collect.


Set
0: value: {}
1: value: {}
__proto__: Set

When we point objectB away to null, the literal object decreases its retain count to 1. It is still pointed to by Set. Thus, when the garbage collector comes around, it sees that the object is still valid at 1. Thus, it will not collect.

WeakSet

Currently, WeakMaps and WeakSets are the only way to kind-of-weakly reference an object in JavaScript. When it references an object, it does not increment an object’s retain count. Thus, adding an object as a key to a WeakMap or WeakSet doesn’t prevent it from being garbage-collected.

Now let’s replace our Set with a WeakSet.

Run the index.html and clear the console of any output. Click on Performance tan and click on the garbage icon to run the garbage collector.

Because our Weakset weakly retains our literal object B, and reference B already pointed it away to null, the retain count lowers to 0. Hence when our garbage collector runs, it will see that literal object B’s retain count is 0, and collects it.

Push the button again and we see that our Set only has literal Object A.


WeakSet
0: value: {}
__proto__: WeakSet

Due to this characteristic, WeakSet only makes sense if it is working with objects. Thus, they only take objects. If you were to try to set a primitive value, it will give you an error.

Because WeakMpa’s reference does not increase the retain count, when we re-point our objectB reference to null, the literal object decreases from 1 to 0. Thus, when the garbage collector comes, it’ll see that this object is 0 and collects it.

this context (strict, non-strict, arrow)

es5

In non-strict environment, the ‘this’ keyword is bound to the context that is calling it
Context refers to the object to which a function belongs.

Yet when ‘this’ is inside of a function:

  • either stand-alone function
  • or within another method

it will always refer to the window/global object

stand-alone

…within method

Use strict

However, if you were to use strict mode, ‘this’ inside functions that are standalone, or within a method, would reference undefined

standalone functions within functions.
functions within methods

es6

With arrow functions, ‘this’ is lexically bound. It means that it uses ‘this’ from the code that contains the arrow function. In other words, it always uses ‘this’ from the parent scope.

class Greetings

In the class Greetings, for the constructor function’s this, we see that the parent scope’s ‘this’ is class Greetings. Thus, the ‘this’ references the instance Greetings.

In the method ‘print’, the parent scope is the constructor function. The constructor function’s ‘this’ is the instance (Greetings).

In the private method ‘haha’, the parent scope is also the constructor function. The constructor function’s ‘this’ is the instance (Greetings).

in setTimeout, the callback function’s ‘this’ parent scope is the private function haha. As mentioned above, private function haha’s context is the instance (Greetings).

In the next example, we are executing a callback. We are using an es5 function. es5 function ‘this’ references the object that is calling it. In our case, the setTimeout’s context is executing this callback function. Thus, ‘this’ references a Timeout instance.

Finally, we have the method ‘print2’. Since its an arrow function, its parent scope is class Greetings. Hence its ‘this’ references the instance (Greetings).

Literal Object bracket is NOT lexical scope

Our arrow function uses ‘this’ from the lexical scope that contains the arrow function. In the case of arrow function x, bar is the literal object that contains our arrow function.

It is NOT a lexical scope

Hence, bar’s this comes from the lexical scope that is the global scope. Global scope’s this is {}. Hence that is what the ‘this’ is inside of arrow function x.

In this example, we have a literal object. Then we have es5 function bar. The ‘this’ is bound to the calling context, which is literal obj. That is the ‘this’ inside function bar is ‘obj’.

Then, inside function bar, we have es6 arrow function. Arrow function says ‘this’ is bound to its lexical parent. Hence, since its lexical parent is bar’s this, it references literal obj. Thus that’s why in arrow function x, the ‘this’ also references ‘obj’.


output:

— obj calling function bar —
{ bar: [Function: bar] }
— in arrow function —
{ bar: [Function: bar] }

ref – https://stackoverflow.com/questions/31095710/methods-in-es6-objects-using-arrow-functions

Our arrow function uses ‘this’ from the code that contains the arrow function The containing code is the literal object.
Since the literal object itself has no ‘this’, we cannot say it will log profile. Instead, the ‘this’ of literal object ‘profile’ is the global scope. And ‘this’ at global scope is {}

Lots of times, I would mistakenly believe that it should be literal object ‘profile’. That would be true in es5 function because it binds ‘this’ to the calling object as shown in the above example.

However, since we’re dealing with es6 arrow function, we bind ‘this’ to the parent scope’s this. NOT the parent object.

Hence, we cannot bind it to the literal object profile. We can only bind it to profile’s ‘this’.

Literal objects do not have ‘this’ context. So profile’s this defaults to global {} because literal object profile is at the global scope.

click handlers

means that when the element is clicked, the function ‘test’ is fired. But this function test is bound as an event handler, so ‘this’ is set to the reference to the button DOM element.

In test function’s definition, the this is the global obj, as it is when any function that’s not an event handler or an object method is.

Deep Copy a JS object/array using recrusion

Check if its of type ‘object’

Arrays and objects are both of type “Object”, so if the inObject is neither an array nor object, we exit because we only deep copy objects and arrays.

Initialize to [] or {} depending on whether its an array or object

Initialization Phase. If the incoming object is an array, we initialize to an empty array [].
If its an object, we initialize our source to empty literal object {}

iterate over the index/key

Now that we have a correctly initialized empty data structure, we go on to doing the copying.
In JS, using for (key in obj) works for both object/arrays.

If its an array, each key is the element index
If its an object, then its key/value as is

Hence, say we create an array pass it in. Since all elements in the array are primitives, we do normal copying via assignment operator (=)


-- myDeepCopy -- [ 'a', 'b', 'c', 'd', 'e' ]
incoming object is an array!
key 0
value a
key 1
value b
key 2
value c
key 3
value d
key 4
value e
outObject [ 'a', 'b', 'c', 'd', 'e' ]

But! there’s a problem

If one of the values is an object, we’d be doing a shallow copy because the assignment operator (=) simply points the array[i] or obj[i] reference to the object.

This means we’re simply just pointing our outObject[key] to the same object value (inObject[key]) is pointing to. Hence, we dont’ have our own copy.
Let’s look at a test case here:

In our test, we have our src obj change its array luckyNumbers. However, we see the same change in our destination object. This proves that the two arrays’ luckyNumbers reference are pointing to the same array. This is an example of shallow copy.


-- myDeepCopy -- { name: 'ricky', age: 40, luckyNumbers: [ 6, 8 ] }
incoming object is an object!
key name
value ricky
key age
value 40
key luckyNumbers
value [ 6, 8 ]
outObject { name: 'ricky', age: 40, luckyNumbers: [ 6, 8 ] }

src object { name: 'ricky', age: 40, luckyNumbers: [ 8, 8 ] }
destination obj { name: 'ricky', age: 40, luckyNumbers: [ 8, 8 ] }

In order to make our own copy, we use recursion and let our ‘Initialization Phase’
create the deep initial object first, then copy over the primitives one by one.

where recursion executes myDeepCopy with array luckyNumbers [6, 8].
Then in that myDeepCopy, we allocate our own array to use during the Initialization Phase. We don’t want to share with others

Now when you run your test code, you’ll see that changes do the source won’t affect the destination:


-- myDeepCopy -- { name: 'ricky', age: 40, luckyNumbers: [ 6, 8 ] }
incoming object is an object!
key name
value ricky
key age
value 40
key luckyNumbers
value [ 6, 8 ]
-- myDeepCopy -- [ 6, 8 ]
incoming object is an array!
key 0
value 6
key 1
value 8
outObject [ 6, 8 ]
outObject { name: 'ricky', age: 40, luckyNumbers: [ 6, 8 ] }

src object { name: 'ricky', age: 40, luckyNumbers: [ 8, 8 ] }
destination obj { name: 'ricky', age: 40, luckyNumbers: [ 6, 8 ] }

Full Source

DNY client (12 – basic site)

dnyNodeAPI-basic-site
npm install to install all node modules
Then, npm run dev to run the server

dny-client-basic-site
npm install to install all node modules
Then, npm run start to run the client

So far we have a basic site with these functionalities:

Create a user

POST on http://localhost:8080/signup
body: JSON.stringify(user)

src/auth/index.js

src/user/Signup.js

When the user successfully creates an account, we will show a link to sign in.

Authenticate a user

POST on http://localhost:8080/signin
body: JSON.stringify(user)

We first use the email and password to try to get user user data and a token back, which are both packaged into a object called ‘data’. Once we get the data, we pass it into AuthenticateUser, which will store it via localStorage at property ‘jwt’. Thus, we can always access the value at property ‘jwt’. We get this value, which has properties token and user, which we can use.

src/user/Signup.js

Once we get the token and user data successfully into the localStorage, we redirect to the main page.
The main page’s component is Home

Also, we have a Menu for navigation and showing/hiding of links according to authentication.

Menu

Basically, we use IsAuthenticated to read localStorage’s jwt value. If it’s available, we show what we want to show, like the sign-out link, user’s name, id.

User Profile

GET on http://localhost:8080/user/${userId}

The main idea is that we must give the userId so the backend knows which user to fetch. We also need to give a token so that the backend can authenticate it.

There is a situation where if you’re on someone else’s (say tom’s) profile, and you click on the user profile (john) link in the Menu, the Profile’s component render function will be called first, which will fetch and render tom’s data again. But soon after, your click on john’s profile link will trigger john’s data to be fetched also. Hence, there will two fetches.

Edit user profile

PUT on http://localhost:8080/user/${userId}
body: user

Editing is basically about updating the user on the backend.

Once we update the user, we must remember to update the localStorage with the latest retrieved user data.

Delete user profile

removeUser does a fetch for Delete on http://localhost:8080/user/${userId}
where SignOutUser does a fetch for GET on http://localhost:8080/signout

Here, we tell the backend to clear cookie for this particular client. Cookies are stored per-user on the user’s machine. A cookie is usually just a bit of information. Cookies are usually used for simple user settings colours preferences ect. No sensitive information should ever be stored in a cookie.

View all users

GET on http://localhost:8080/users

DNY client (11 – Profile Photo Display)

Server side

First we put in the route

routes/user.js

Then we implement the function responder for when the user goes to /user/photo/:userId

Since we already retrieved the user object at function userById, everything is already in req.profile
We simply check for the image data, and then set the content type.

controllers/user.js

Client Side

we create a photoUrl so that our image control has a src.

src/user/EditProfile.js

However, there is an issue. The browser cache images and when you try to upload another image, and you come back to this page, the browser will be showing the old image.

In this situation, simply give the latest time and append it to the URL

DNY client (9 – Edit Users)

We first create our EditProfile component

src/user/EditProfile.js

Then, we add a Route to our EditProfile component. Whenever this link is clicked, it hits our EditProfile component.
src/MainRouter.js

Make sure we implement UpdateUser fetch operation, which does a PUT operation on the server for a particular user. That way, we can tell the server to update this particular user with this particular data.

Remember that when we give the user data in body, we need to stringify it. The server does not take objects as data. It takes a string.
If you were to send a body, the updateUser function on the server side won’t be triggered and it will be hard to debug. So make sure you always JSON stringify body data.

src/user/apiUser.js

EditProfile component source

Editing forms is about presenting a html form with textfield controls. We then put our state’s value in the textfield’s value property. Our state has already been updated with the latest value from the server via the initUserID function when the component was loaded.

DNY client (8 – Delete Users)

Client Side

removeUser tells the server side to look for the user with the specific ID. Then, remove that user from the database.

user/apiUser.js

auth/index.js

SignOutUser first looks at the client’s local storage. It removes the jwt key/value.
Then it tells the server to clear the cookie for this client.

Cookies are stored per-user on the users machine. A cookie is usually just a bit of information. Cookies are usually used for simple user settings colours preferences ect.

Cookies can be cleared through the browser’s settings via a “clear cookie” button. A cookie file can also be opened by the user when they go through your temporary Internet files history and can locate your cookie there. They can then open it and look at the contents. Hence, No sensitive information should ever be stored in a cookie.

We use server calls for removing the user and clearing the cookie in our DeleteUser functionality. After deleting is complete, we simply redirect the user to the home screen.

user/DeleteUser.js

Server side

controllers/user.js

DNY client (7 – Users)

Create the User file under user folder.

Include it into the router.

Then put it into the menu.

user/Users.js

The result is a list of users.

Props Change on Users

1) Go the users list http://localhost:3000/users
2) Click on View Profile link of any user. You’ll get to the profile page of that user with that user’s data.
3) If you were to click on your own profile link above, the component data wouldn’t change. This is because the URL is part of prop. Since you’ve changed the URL, you’re changing the prop. This change happens at this.props.match.params.userId.

This is the props of the component and when it changes, we need to fetch data for the profile user again. However, in our Profile component, we only do this for when componentDidMount. Thus, we need to implement fetch data in a component hook called componentDidUpdate like so:

user/Profile.js

DNY client (6 – Profile Page)

src/user/Profile.js

Notice when we added our Profile page, the path is /user/:userId.
This says whenever we have a URL in that format, we’ll hit the Profile component.

src/MainRouter.js

Use the user object you get from localStorage. Inside that object, you’ll get the user object. Access the _id of the user and use it for the url parameter when we click on the profile link.

src/core/Menu.js

When fetching data from Server