Facebook                 Github                 Linkedin                 Twitter                 Google+                 Skype                 Outlook                 Aboutme

Sunday, November 6, 2016

Some less known facts about JavaScript


Whenever we run a JavaScript code or even refer an empty JavaScript code file in HTML and run that code, the JavaScript engine creates an execution context and in that context it creates a global object and a special variable called 'this’ (also a link to outer environment is created if the outer environment exists). The global variable is available everywhere in the current window or current JavaScript file. If you are running the code inside a browser (unlike node.js) then the global object is the ‘window’ object. When you create a variable or function which is not inside any function(global level) then those variable or function gets attached to the global object. So if you create a global variable 'a' then you can refer to it as just 'a' or 'this.a' or 'window.a' (if running inside a browser).

The execution context works in 2 steps:
In the first 'creation’ step, the parser parses the whole JavaScript code and sets up memory for the variables(if the execution context is for a function then this will also include variables which are parameters of the function) and functions declared in current execution context (the variables or functions declared nested inside current level functions will not be available). This phase is called ‘hoisting’. (Note: variables are only declared and not initialized at this time, so their value will be 'undefined’, but function definitions will be stored so their definitions will be available). This means before the interpreter starts executing the code line by line, all variables and functions are available in memory for access by the code.
‘Undefined’ is a special value which means the value is not defined. So in the creation phase mentioned above, when memory is allocated to all declared variables, this undefined value is set at those memory locations. Although we can set a variable’s value to undefined, it is not recommended to set it manually as while debugging it will be difficult for a programmer to determine whether a variable is not defined till now or whether he manually set it to undefined. So you should set it to null instead of undefined.
The second step is execution step in which the code is executed line by line.
Whenever a function is invoked, a new execution context is created and put on the top of stack. The execution context on top of the stack is always the current execution context. This will also work in 2 phases i.e. creation and execution. Once the function execution is complete, the execution context is popped out of the stack. Even when a function invokes itself, a new execution context is created and pushed on top of the stack. 
When a referred variable is not found in current execution context, then it is searched in the outer environment using the link created in the creation phase of the execution context.
JavaScript runs synchronously (single threaded) but other parts of browser like rendering engine are working in parallel with JavaScript engine. When an event e.g. click, occurs in browser and the JavaScript engine needs to be notified for this event, then that event is put in the event queue of the JavaScript engine.
When the stack is empty i.e. all execution context are complete including the global execution context (i.e. all code is executed), then only JavaScript will look periodically into this event queue and create and execute execution contexts for the event handler functions one by one.

When we write multiple <script></script> blocks one below the other to include JavaScript files in our HTML page, JavaScript behaves as if it is a single JavaScript file. Therefore all these files will share the same global execution context and all global variables will be attached to the same global object (window object in case of JavaScript running inside browser). So if a variable x is present in multiple JavaScript files at global level, it will be considered as the same variable.

JavaScript uses dynamic typing means datatype of variable is determined at runtime and not at compile time. So a single variable can hold different types of data. 

The operators like ×-+ are basically functions with a different syntax.
Coercion is the implicit type casting that happens when two different types of parameters are passed to an operator.
Few conversions:
Number(true)=1
Number(false)=0
Number(undefined)=NaN
Number(null)=0
When we use strict equality(===) or strict inequality(!==) operators then coercion does not happen. So false == 0 is true but false === 0 is false. Hence always use strict equality/inequality operators unless it is required to ignore the types.
But, sometimes coercion can be useful. e.g. Boolean(undefined)==Boolean(null)==Boolean(“”)==Boolean(0)==false. So we can use ‘if(x)’ at the beginning of a block so that the block will execute only when x exists and has a valid value.

The || (or operator) behaves in a special way while comparing a non Boolean value. It returns the value which coerces to true instead of true. e.g. undefined || “hello” will return “hello” because undefined will coerce to false and “hello” will coerce to true as it is a non empty string. If both the arguments coerces to true then it will return the first one. We can use this behavior of or operator to assign default values to function parameters by writing x = x || 1  (Note: be careful while using 0 as Boolean(0)=false).


Reference:
JavaScript under the hood: https://youtu.be/Bv_5Zv5c-Ts

Ordering events on distributed machines using logical clocks


A distributed system generally consists of a set of processes. These processes communicate with each other by sending messages. A process can also be viewed as a sequence of events occurring in an order.

In order to avoid synchronization problems in such an environment, it is important to determine the order of occurrence of events in a process or among different processes. A "happened before' relation can be used to provide a partial order for these events. Using physical clocks to define the ordering of events may not be the best approach as the physical clocks may not show perfectly accurate time. Therefore, the concept of logical clocks was introduced.

Happened before relationship:
The happened before relationship denoted by "->" can be defined as the smallest relation satisfying the below 3 criteria:
a) If an event x comes before event y and both event are part of the same process, then x happened before y (denoted by x->y).
b) If x is an event corresponding to transmission of a message by a process and b is an event corresponding to the receipt of that message by another process, then x happened before y (x->y).
c) If an event x happened before another event y (x->y) and y happened before a third event z (y->z), then x happened before z (x->z).
An event cannot happen before itself.
If an event x does not happen before event y and also the event y does not happen before x, then both the events are concurrent.

Logical clocks:
A logical clock Ci for a process Pi can be considered as a function which assigns a number Ci(x) to every event x in that process. Furthermore, the entire system of clocks can be represented by a function C in such a way that it assigns the number C(x) to any event x such that C(x) = Ci(x), where x is an event in process Pi.
This number depends on the order at which that event occurs. Therefore, if x->y then C(x) < C(y). In other words,
               1) If a process Pi has two distinct events x and y and event x occurs before event y then Ci(x) < Ci(y).
               2) If x is an event corresponding to transmission of a message by process Pi and y is an event corresponding to receipt of the message by another process Pj, then Ci(x) < Cj(y).
This logical clock can be considered to tick between the process's events. Also it is considered to tick between the transmission of a message by a process and receipt of that message by another process. We can represent this by drawing dashed tick lines in such way that there is always a tick line between two events of a process and also each message lines crosses a tick line.




Implementation of logical clocks:
For a process Pi, a logical clock can be implemented as a register Ci which contains the value Ci(x) during the event x, but changing value of Ci will not be considered as an event. To implement a logical clock, we need to make sure that the above mentioned two conditions are satisfied. This can be achieved in below way:
For condition 1): Every process Pi will increment the value of Ci between two successive events.
For condition 2): When a process Pi transmits a message at event x, the transmitted message will contain a timestamp t which will be equal to Ci(x). When the process Pj receives this message, it will increment its clock Cj to a value greater than t.
This way a system of logical clocks can be implemented to causally order events in a distributed system.


Reference: 
Leslie Lamport’s paper on time, clocks and the ordering of events in a distributed system : http://amturing.acm.org/p558-lamport.pdf