JS Tips
JS Tips
- Creation phase
JS engine creates GlobalObject, ‘this’ object and the outer environment (that also defines the
scope)
JS engine sets up the variables (setting their values to undefined) and functions expressions in
memory. This phase enables whats called hoisting, that is the ability to execute functions
declared in the code below or reference variables declared in the code below ; the functions
get executed well, whereas the value of variables would be undefined (not throwing the
exception“Uncaught ReferenceError: variableName is not defined”, which would be the case
when the variable isn’t declared anywhere in the code).
- Code Execution
Javascript behaves in a Single Threaded (one command at a time) Synchronous (one by one in order) manner =
one command at a time.
Every time a function gets called, a new execution context fort this function gets created. This new execution
context performs the two phases of executions contexts (creation (sets up the variables and functions in
menmory )and code execution) and put on the stack of execution contexts, right on top of the execution
context corresponding to the function that called it (or the global execution context if the function was called
not inside any function).
Once the function finishes its execution, it gets popped out of the execution context stack.
The lexical environment, that is the environment, the place in the code at which a function is declared defines
where the function will look for the variables that are referenced inside it but not declared.
Scope chaining
Let’s say function B is declared inside function A which is created itself at global environment. If, in the function
B there is a reference to a variable x (let’s say console.log(x);) which is not declared within function B, the scope
chaining process will look in function B’s lexical environment (or outer environment), which is function A. If the
variable x is declared within function A, it’s value will be used within function B, otherwise, scope chaining will
look into function A’s lexical environment, which is global environment. If variable x is declared in the global
environment, it’s value (any value, including undefined = if the variable is only declared but not initialized) will
be used in function B, otherwise there will be the exception “Uncaught ReferenceError: variableName is not
defined”.
So, scope (scope is where I can get the variable referenced in a function) chaining is the process of going
through lexical environments to get the value of a variable that isn’t declared in one function, until a lexical
environment where the variable is declared is found or the global environment is reached.
“let” keyword is introduced in esx6 and same as “var” allows creation of variable in the memory (at the
creation phase of the execution context), but the variable won’t be initialized to undefined, hence there will be
an error “Uncaught Reference Error: Cannot access 'x' before initialization”, when referenced in the lines of
code above variable declaration.
var vs let
1)Scoping rules (var = function scope, let = block scope)
Main difference is scoping rules. Variables declared by var keyword are scoped to the immediate function body
(hence the function scope) while let variables are scoped to the immediate enclosing block denoted
by { } (hence the block scope).
2)Hoisting
Variables declared with “var” in the creation phase of execution context will be allocated in memory and set to
undefined, hence can be referenced in their scope even in the lines above declaration, whereas variables
declared with “let” in the creation phase of execution context will be only allocated in memory but not set to
undefined or any value, hence there will be a reference error if referenced in their scope in the lines of code
above their declaration.
At the top level, let, unlike var, does not create a property on the global object:
console.log(window.foo); // Foo
console.log(window.bar); // undefined
4)Redeclaration
In strict mode, var will let you re-declare the same variable in the same scope while let raises a SyntaxError.
'use strict';
var foo = "foo1";
var foo = "foo2"; // No problem, 'foo' is replaced.
const is similar to let, but the variable initialized with const cannot be reassigned after initialization.
Javascript Engine works synchronously. There are though other engines, such as Rendering Engine, Http
Handling eninges, that asynchronously might do work asynchronously (such a setTimeout, http.get,
eventHandlers etc). Events, such as click event or http response, are managed in the Event Queue.
When JS runtime (or JS engine) reaches a line of asynchronous code, it passes this code to the other engines
that do the asynchronous work. These engines perform the asynchronous job and once completed, put the
callback function in the Event Queue. Once the call stack (execution context stack) gets empty, the callback
function gets into JS engine, which created the execution context for this function.
<script>
function WaitThreeSeconds()
{
var ms = 5000 + new Date().getTime();
while(new Date() < ms){
}
console.log("WaitThreeSeconds finished");
}
function clickHandler()
{
console.log("click event handler fired");
}
document.addEventListener("click",clickHandler);
WaitThreeSeconds();
</script>
When loading the page, the function WaitThreeSeconds will be executed -> it will take 5 seconds before it
writes in console “WaitThreeSeconds finished”. If during this period of time (this 5 secs) user clicks on the page,
the event added to the event queue will not be looked at by JS engine, until the execution context stack is
empty (in this case when WaitThreeSeconds function completes its executes and leaves the stack). Once the
context execution stack is empty, the JS engine will look at the Event queue and since user had already clicked
on the page, there will be created the execution context (in JS engine) for the event handler function in order
to proceed with execution of the function.
Javascript engine periodically looks at the Event Queue only when it’s execution context stack is empty.
Beside Callback Queue (or Event queue) there is also a Rendering Queue, which also can’t perform rendering
while call stack is not empty (this is the reason that heavy synchronous operations cause performance
degradation), but it has higher priority than Event Queue.
setTimeout(function(){do something},0); is a way to execute a function when the execution context stack is
empty (all synchronous code has finished its execution).
setTimeout is not a guarantee that the function will get executed in x seconds, the function will get executed
x seconds + time needed to empty the call stack.
- undefined (represents lack of existence. You shouldn’t set a variable to this, not because you can’t but
because it’s intended to represent lack of existence, the default value set to variables on the creation
phase of execution context)
- null (represents lack of existence. You can set a variable to this)
- Boolean
- Number (it’s a floating point number. unlike other programming languages, in JS there is only one
“number” type)
- string (both “” and ‘’ quotes)
- symbol (used in ES6)
Operator precedence determines which operator (function) gets executed first (for instance * has higher
precedence than +).
Operator associativity comes into play when operators in a statement have the same precedence. It can either
be Left-to-right (left associativity, that is the left operators get executed first), Right-to-left (right associativity,
that is right operators get executed first) or N/A.
var a = 3, b = 4, c = 5;
a = b = c; would result in a, b, c being all three set to 5 (as b = c gets executed before a = b)
Tip : the assignment (=) operator returns the value (the assigned value) ; a = 5 returns 5
Coercion
Coercion = converting a value from one type to another. This happens quite a lot in JS because its dynamically
typed.
For instance : var x = 1 + ‘2’ -> x would be set to ‘12’ because JS coerces (converts) 1 from number primitive
type to string primitive type and then apply the + operator.
Not always operands of operators are coerced, there are some exceptions.
For instance, null == 0 => false, eventhough Number(null) = 0; that is because in equality operator null is not
coerced, whereas null < 1 => true because in < operator, null is coerced (converted to 0).
For instance undefined, null, 0 and “” coerce to false ( Boolean(undefined) = false, Boolean(null) = false,
Boolean(“”) = false).
So we can say : var a; if(!a) {//do something} -> that would mean if a is false, 0, null or undefined -> do
something.
Hence if we want to check if a contains value (that is null, undefined or “”) we should do it like : if(a || a === 0)
Tip : || operator tries to coerce both operands to boolean ( Boolean(x)) and returns the first value coerced to
true. For instance, undefined || “ilir” , null || “ilir” , 0 || “ilir” , “” || “ilir” return “ilir” because “”, null,
undefined and 0 coerce to false (all other values coerce to true).
var myobj = {}; // “{}” is called object literal, JS engine interprets the brackets (when not after if statetement,
switch or loops) as new object creation.
In javascript, statement -> just does work, whereas expression returns a value.
Primitive types (number,Boolean,string, symbol,null,undefined ) are passed by value whereas objects and
arrays are passed by reference.
Example 1)
test(myobj);
Example 2)
var a = {name:”Ilir”};
var d = a;
a.name = “Sokol”;
Not always objects or arrays are passed by reference, there is an exception. If we set an object or an array to
another object or array, this allocates a new space in memory, hence the original memory space will remain
intact.
Example 3)
test(myobj);
Example 4)
var a = {name:”Ilir”,age:30}
var b = a;
a = {city:”Kukes”, population:20000}
b -> {name:”Ilir”,age:30}
If “this” is referenced in global environment, inside an object (or inner objects), or inside an inner function -> it
will reference to window object.
Whereas, if “this” is referenced inside a function that is not an inner function but a property of an object, “this”
will refer to the object the function is property of.
Spread arguments the last list or array of parameter we define in the function param list as : …paramsName
function testSpread( a, b, …others){ } -> if we reference “others” in function body it will be the list of
parameters starting from the third passed parameter. If 0, 1 or 2 parameters are passed to the function call,
“others” would be an empty array.
Javascript syntax parser checks the code syntax and decides where to inject semicolon “;” hence most of the
times is not mandatory adding semicolon at the end of the line (but as a best practice you should always add
“;”). For instance, javascript syntax parser adds semicolon when it finds “newline” character after a return
statement. There is a dangerous scenario of javascript syntax parser automatically adding semicolon :
This would print undefined in the console because javascript syntax parser would add semicolon when finding
“newline” character after the return statement.
Closures
Anytime a function gets executed (even when a function is executed several times) it creates its own execution
context, and any function created inside the called function will point to that execution context (that execution
context variables environment isn’t cleared out when the execution context is cleared from the call stack
(that’s the closure concept).
<html>
<head>
</head>
<body>
<script>
function b()
{
var myVar = 3;
otherVar = 3;
console.log("myVar="+myVar);
console.log("otherVar="+otherVar);
}
function a()
{
var myVar = 2;
var otherVar = 2;
console.log("myVar="+myVar);
console.log("otherVar="+otherVar);
b();
console.log("myVar="+myVar);
console.log("otherVar="+otherVar); //notice: otherVar value doesn't ge
t updated eventhough at function b, we have the line : otherVar = 3. this is because
// function b sits lexically (the code resides in) global scope, not w
ithin function a, hence the outer environment of function b is the global environment
}
var myVar = 1, otherVar = 1;
console.log("myVar="+myVar);
console.log("otherVar="+otherVar);
a();
console.log("myVar="+myVar);
console.log("otherVar="+otherVar);//notice: otherVar value gets updated be
cause at function b, we have the line : otherVar = 3
</script>
</body>
</html>
Scope = where a variable is available in your code
Scope chain – getting reference of a variable by going through execution contexts outer environments till a
variable reference is found or global environment is reached.
Primitive types :
1. Undefined
2. Null
3. String
4. Boolean
5. Number
6. Symbol (introduced in es6)
Coercion
Number(false) = 0
Number("") = 0
Number(undefined) = NaN
Number(null) = 0
Boolean(null) = false
JSON doesn’t support functions as properties values. The supported types are :
Function statement :
greet(); // “hi” is written in console -> function statements are hoisted
function greet ()
{
console.log(“hi”);
}
Function expression :
greet(); // error thrown : undefined isn’t a function -> function expressions aren’t hoisted
var greet = function()
{
console.log(“hi”);
}
(function(global,name){
var name = "ilir";
global.name = "updated name";
console.log("hello "+name);
}(window,"ilir"))
We can use IIFE, to create a new function execution context that would avoid namespace collision.
In the IIFE, we put the function expression within brackets () to trick JS engine so that it considers the
function a function expression and not a function statement (as it would normally do when finding function
keyword initiating a new line)
Closures
Closures is a functionality of JS engine that allows the variables created in the execution context of an
executed function to remain available in the memory even after the function is executed and the execution
context has popped of memory stack. This enables any functions return from the executed function to have
access to the variables declared within the function after it has been executed (and the corresponding
execution context removed from the memory).
For instance :
function greet(whattosay)
{
return function(name)
{
console.log(whattosay+" "+name);
};
}
We could do :
var myfunc = greet(“hello”);
myfunc(“ilir”); // hello ilir
in this case the variable “whattosay” remains in the memory even after execution of greet function.
Hence, when calling the returned function myfunc(“ilir”), a new execution context will be created, it will
look for a variable called “whattosay”, it wont find it within the environment variables and will go in the
scope chain to look for the variable. Due to the closure functionality, the variable “whattosay” will remain
in the memory and be available to the myfunc function.
function buildfunction()
{
var arr = new Array();
for(var i = 0;i<3;i++){
arr.push(
function()
{
console.log(i);
}
);
}
return arr;
}
var myfunctions = buildfunction();
myfunctions[0](); //3
myfunctions[1](); //3
myfunctions[2](); //3
all three returned functions will return 3 when called because when buildfunction completes its execution
and its execution context pops off memory, there will be two variables : 1) arr – an array with three
functions 2) i – 3 , hence each of these three functions will find the same value for the variable i when
looking into scope chain.
If we need these functions to print 0,1,2 to the console, we could make use of immediately invoked function
expressions IIFE, creating them in the loop in order to have a separated new execution context for each of
the functions that will be returned, have the variable set in that context so that each function will make use
of its own variable instance.
function buildfunction()
{
var arr = new Array();
for(var i = 0;i<3;i++){
arr.push(
(function(j){
return function()
{
console.log(j);
};
}(i))
);
}
return arr;
}
var myfunctions = buildfunction();
myfunctions[0](); //0
myfunctions[1](); //1
myfunctions[2](); //2
All functions in javascript are objects, that in addition to “common” objects have a :
- code property (invocable)
- name (optional)
- bind method
- apply method
- call method
Bind, apply and call methods allows us to define what “this” variable refers to within function.
Bind method creates a new function object to which we set the “this” variable and optionally preset some
parameters.
var person = {
firstName : "Ilir",
lastName : "Peposhi",
getFullName : function()
{
var fullName = this.firstName + " "+this.lastName;
return fullName;
}
};
var logName = function()
{
console.log("Logged : "+this.getFullName());
};
logName(); // Uncaught TypeError: this.getFullName is not a function
// if we want to control what "this" keyword in logName function is, we can use bind, apply or call
functions.
var logPersonName = logName.bind(person); // bind returns a new copy of the initial function (logName)
but setting the "this" variable to whatever object passed to the bind method.
// in this case, the "this" keyword would be equal to person object.
logPersonName(); // Logged : Ilir Peposhi
A use case of bind method is function currying = creating a copy of a function but with some preset
parameters.
call method doesn’t create a new function, it executes the initial function but with the variable “this” set,
and the optional parameters.
var person = {
firstName : "Ilir",
lastName : "Peposhi",
getFullName : function()
{
var fullName = this.firstName + " "+this.lastName;
return fullName;
}
};
var logName = function(city,country){
console.log(this.getFullName());
console.log("Other params = "+city+" "+country);
}
logName.call(person,"Kukes","Albania");
apply method is identical to call method, but it passes the other parameters in an array.
logName.apply(person,["Kukes","Albania"]);
function mapForEach(arr,func){
var newArr = new Array();
for(var i = 0;i<arr.length;i++)
{
newArr.push(func(arr[i]));
}
return newArr;
}
Every object in JS has a __proto__ (prototype) property, that is an object with methods and properties that
can be referenced directly from the object as if they were methods/properties of it.
var b = function(){}
b.__proto__ -> ƒ () { [native code] } // empty function object. It has several function methods such as bind,
call, apply etc
b.__proto__.__proto__ -> Object {} // the root object
var c = [];
c.__proto__ -> [constructor: ƒ, concat: ƒ, copyWithin: ƒ, fill: ƒ, find: ƒ, …] // empty array object with
several array helping methods
c.__proto__.___proto__ -> the root object
var d = 2;
d.__proto__ -> Number {0, constructor: ƒ, toExponential: ƒ, toFixed: ƒ, toPrecision: ƒ, …} // Number
Object with functions such as toFixed, toExponential etc
d.__proto__.__proto__ -> Object {} // the root object
var e = “abc”;
e.__proto__ -> String {"", constructor: ƒ, anchor: ƒ, big: ƒ, blink: ƒ, …} // String Object with functions such
as indexOf, concat, include etc.
e.__proto__.__proto__ -> Object {} // the root object
var f = true;
f.__proto__ -> Boolean {false, constructor: ƒ, toString: ƒ, valueOf: ƒ} // Boolean object
f.__proto__.__proto__ --> Object {} // the root object
This means that everything in JS is an object because going down in the prototype chain, the last
prototype in the chain is the root object {constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ,
hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}, hence everything in the end derives from object.
Reflection in Javascript
var person =
{
firstName : "Default",
lastName : "Default",
getFullName : function()
{
return this.firstName + " "+this.lastName;
}
}
var Ilir = {
firstName : "Ilir",
lastName : "Peposhi",
}
Ilir.__proto__ = person;
// list all properties of Ilir object, including those inherited from prototype
for(var prop in Ilir)
{
console.log(prop+" : "+Ilir[prop]);
}
// List all properties of Ilir object, excluding those inherited from the prototype
for(var prop in Ilir)
{
if(Ilir.hasOwnProperty(prop)){
console.log(prop+" : "+Ilir[prop]);
}
}
Building Objects
W3SCHOOLS
Getters and setters allow you to define Object Accessors (Computed Properties).
<!DOCTYPE html>
</script>
<input type="text" id="languageid" />
<input type="submit" value="Set Language" onclick="
var newLanguage = document.getElementById('languageid').value;
person.lang = newLanguage; " />
<input type="submit" value="Get Language" onclick="
alert(person.lang);" />
</body>
</html>
Javascript function
var person = {
firstName: "John",
lastName : "Doe",
fullName : function() {
return this.firstName + " " + this.lastName;
}
};
var person = {
firstName: "John",
lastName : "Doe",
get fullName() {
return this.firstName + " " + this.lastName;
}
};
Object.defineProperty()
The Object.defineProperty() method can also be used to add Getters and Setters:
// Define setters
Object.defineProperty(obj, "reset", {
get: function () { this.counter = 0; }
});
Object.defineProperty(obj, "increment", {
get: function () { this.counter++; }
});
Object.defineProperty(obj, "decrement", {
get: function () { this.counter--; }
});
Object.defineProperty(obj, "add", {
set: function (value) { this.counter += value; }
});
Object.defineProperty(obj, "subtract", {
set: function (value) { this.counter -= value; }
});
Sometimes we need a "blueprint" for creating many objects of the same "type".
Objects of the same type are created by calling the constructor function with the new keyword:
Prototypes
Sometimes you want to add new properties (or methods) to an object constructor.
Person.prototype.nationality = "albanian";
Person.prototype.name = function() {
return this.firstName + " " + this.lastName;
};
Attribute Name
The data attribute name must be at least one character long and must be prefixed with 'data-'.
It should not contain any uppercase letters.
Attribute Value
The attribute value can be any string.
Using this syntax, we can add application data to our markup as shown below:
<ul id="vegetable-seeds">
<li data-spacing="10cm" data-sowing-time="March to June">Carrots</li>
<li data-spacing="30cm" data-sowing-time="February to
March">Celery</li>
<li data-spacing="3cm" data-sowing-time="March to
September">Radishes</li>
</ul>
We can now use this stored data in our site’s JavaScript to create a richer, more engaging user
experience. Imagine that when a user clicks on a vegetable a new layer opens up in the
browser displaying the additional seed spacing and sowing instructions. Thanks to
the data- attributes we’ve added to our <li> elements, we can now display this information
instantly without having to worry about making any Ajax calls and without having to make
any server-side database queries.
Prefixing the custom attributes with data- ensures that they will be completely ignored by
the user agent. As far as the browser and indeed the website’s end user are concerned, this
data does not exist.
The spec says (emphasis ours):
Custom data attributes are intended to store custom data private to the page or application, for
which there are no more appropriate attributes or elements.
These attributes are not intended for use by software that is independent of the site that uses the
attributes.
Every HTML element may have any number of custom data attributes specified, with any value.
W3C Specification
Now that we have a broad understanding of what data attributes are, let's take a look at how
they can be used:
To store the initial height or opacity of an element which might be required in later JavaScript animation
calculations
To store parameters for a Flash movie that’s loaded via JavaScript
To store custom web analytics tagging data as demonstrated by Jason Karns
To store data about the health, ammo, or lives of an element in a JavaScript game
To power accessible JavaScript <video> subtitles as demonstrated by Bruce Lawson
Data attributes should not be used if there is a existing attribute or element which is more appropriate for storing
your data. For example, date/time data should probably be presented semantically in a time element instead
rather than stored in custom data attributes.
Custom data attributes are not intended to compete with microformats. It is clearly stated in the spec that the data
is not intended to be publicly usable. External software should not interact with it. Marking up contact details or
event details using custom data attributes would be wrong, unless of course it is only intended to be used by your
own internal scripts.
The presence/absence of a particular data attribute should not be used as a CSS hook for any styling. Doing so
would suggest that the data you are storing is of immediate importance to the user and should be marked up in a
more semantic and accessible manner.
Using data- attributes with JavaScript
Now that we understand what custom data- attributes are and when we can use them, we
should probably take a look at how we can interact with them using JavaScript.
If we wanted to retrieve or update these attributes using existing, native JavaScript, then we
can do so using the getAttribute and setAttribute methods as shown below:
<div id='strawberry-plant' data-fruit='12'></div>
<script>
// 'Getting' data-attributes using getAttribute
var plant = document.getElementById('strawberry-plant');
var fruitCount = plant.getAttribute('data-fruit'); // fruitCount = '12'
<script>
// 'Getting' data-attributes using dataset
var plant = document.getElementById('sunflower');
var leaves = plant.dataset.leaves; // leaves = 47;
The alt attribute provides alternative information for an image if a user for some
reason cannot view it (because of slow connection, an error in the src attribute, or if
the user uses a screen reader).