Let’s cook some JS core concepts

Rayhan Mahi
7 min readMay 8, 2021

Truthy Vs Falsy values

Along with a kind, each value has an underlying boolean value, which is commonly referred to as truthy or falsy. Due to the peculiar nature of some of the rules, it is beneficial to understand the definitions and their impact on comparison when debugging JavaScript applications.

Falsy Values

Falsy values are those that JavaScript’s built-in form coercion converts to false or that are considered false in a Boolean sense. In simple terms, variables that do not have values or do not exist.

The following is a list of all falsy values.

  • false
  • 0 Both positive and negative
  • 0n BigInt, when used as a boolean, follows the same rule as a Number
  • ''
  • null
  • undefined
  • NaN
let a = false;
let b = 0;
let c = -0;
let d = 0n;
let e = “”;
let f = null;
let g = undefined;
let h = NaN;
console.log(Boolean(a));
console.log(Boolean(b));
console.log(Boolean(c));
console.log(Boolean(d));
console.log(Boolean(e));
console.log(Boolean(f));
console.log(Boolean(g));
console.log(Boolean(h));

The preceding demonstrates that all of the preceding is falsy. If we are testing and using truthy/falsy values in our JavaScript algorithm, ensure that we are not using any of the falsy values in your if algorithm.

Truthy Values

Apart from what has been mentioned previously, all are accurate. Simply put, any variable that contains a value is truthy.
The following are some truthy values.

  • true
  • {} An object (whether empty or not)
  • [] An array (whether empty or not)
  • 25 Numbers (whether positive or negative)
  • 'true' Non-empty strings
  • 'false' Non-empty strings
  • new Date() Date object
  • 12n BigInt, when used as a boolean, follows the same rule as a Number
  • Infinity

As a result, a single value may be used within circumstances, such as

if (value) {
// value is truthy
} else {
// value is falsy
// it could be false, 0, ‘’, null, undefined or NaN
}

Null vs. Undefined

At first glance, null and undefined can appear to be synonymous, but they are not. This article will compare and contrast null and undefined in JavaScript.

Null

There are two characteristics of null that we should be aware of:

  • null is an empty or non-existent value.
  • null must be assigned.

Here’s an example. We assign the value of null to a:

let a = null;
console.log(a);
// null

Undefined

Typically, undefined indicates that a variable has been declared but not specified. For instance:

let b;
console.log(b);
// undefined

Additionally, we can specifically set a variable to be undefined:

let c = undefined;
console.log(c);
// undefined

Finally, when we attempt to look up a property that does not exist in an entity, we will receive undefined:

var d = {};
console.log(d.fake);
// undefined

Double Equals vs. Triple Equals

JavaScript has two visually identical, but fundamentally dissimilar, methods for determining equality. We can check for equality using the operators == or ===. The following are the distinctions:

Double Equals (==)

When we use double equals == to compare two operands of different types, double equals perform the required coercion prior to the comparison.

First, we are comparing the number 1 with the string "1" using a double equals operator.

1 == "1" // true

In the above example, we will get an output true because string 1 is converted into a number 1.

Triple Equals (===)

The triple equals (===) is used to perform strict equality checks, which means that both operands must be of the same type and value ; otherwise, it returns false.

1 === "1" // false

In the preceding example, we are comparing Number 1 to String "1" ; the value 1 is identical on both sides, but the operands’ types are different, resulting in an output of false.

2 === 2 // true

Here, we are comparing Number 2 to Number 2, and both operands have the same value and form, which results in the output being true.

Scope

The scope of a variable or other resource in a section of your code decides its visibility or accessibility.

Global Scope

The JavaScript document contains a single Global scope. The field outside of all functions is referred to as the global scope, and variables specified within it can be accessed and modified from any other scope.

//global scope
var fruit = “apple”;
console.log(fruit); //apple
function getFruit() {
console.log(fruit); //fruit is accessible here
}
getFruit(); //apple

Local Scope

Variables declared within functions become Local to the function and are treated as part of the function’s local scope. Each function has a distinct scope. The same variable can be used in several functions since it is attached to each function and is not accessible to other functions.

//global scope
function foo1() {
//local scope 1
function foo2() {
//local scope 2
}
}//global scope
function foo3() {
//local scope 3
}//global scope

Local scope is further subdivided into function scope and block scope. ECMA script 6 (ES6) introduces the definition of block scope, as well as two new methods for declaring variables: const and let.

Function Scope

When a variable is declared within a function, it is observable only within the function. It is not accessible outside of the function. var is the keyword used to describe variables that are accessible within a function’s scope.

function foo() {
var fruit = “apple”;
console.log(“inside function: “, fruit);
}foo(); //inside function: apple
console.log(fruit); //error: fruit is not defined

Block Scope

Block scope is an area within if, switch conditions or for and while loops. Generally speaking, whenever you see {curly brackets}, it is a block. In ES6, const and let keywords allow developers to declare variables in the block scope, which means those variables exist only within the corresponding block.

function foo() {
if (true) {
var fruit1 = “apple”; //exist in function scope
const fruit2 = “banana”; //exist in block scope
let fruit3 = “strawberry”; //exist in block scope
}
console.log(fruit1);
console.log(fruit2);
console.log(fruit3);
}foo();
//result:
//apple
//error: fruit2 is not defined
//error: fruit3 is not defined

Lexical Scope

Additionally, the lexical scope should be considered. Lexical scope implies that the variables specified in the parent scope are accessible to the children scope. The children functions are lexically bound to their parents’ execution sense.

function foo1() {
var fruit1 = “apple”;
const fruit2 = “banana”;
let fruit3 = “strawberry”;
function foo2() {
console.log(fruit1);
console.log(fruit2);
console.log(fruit3);
}
foo2();
}foo1();//result:
//apple
//banana
//strawberry

Closure

A closure is made up of a function and the lexical environment (scope) in which it was declared. Javascript’s basic and efficient property is the closure. The aim of this article is to address the ‘how’ and ‘why’ of closures:

//we have an outer function named walk and an inner function named flyfunction walk() {
var dist = “1780 feet”;function fly() {
console.log(“At “ + dist);
}return fly;
}var flyFunc = walk(); //calling walk returns the fly function which is being assigned to flyFunc
//you would expect that once the walk function above is run
//you would think that JavaScript has gotten rid of the ‘dist’ varflyFunc(); //Logs out ‘At 1780 feet’
//but you still can use the function as above
//this is the power of closures

The closure serves as a reminder of the context in which it was produced. This environment contains some in-scope local variables at the time the closure was made.

Closures are advantageous because they enable us to remember data and then operate on it via returned functions. Javascript can thus imitate the private methods used in other programming languages. Private methods are advantageous for controlling access to code and managing the global namespace.

Private variables and methods

Additionally, closures may be used to encapsulate confidential data/methods. Consider the following example:

const bankAccount = (initialBalance) => {
const balance = initialBalance;return {
getBalance: function () {
return balance;
},
deposit: function (amount) {
balance += amount;
return balance;
},
};
};const account = bankAccount(100);account.getBalance(); // 100
account.deposit(10); // 110

In this example, we will be unable to access the balance of the bankAccount variable from anywhere other than the bankAccount feature, indicating that we have just created a private variable. Where is the conclusion? Consider what bankAccount() returns. It simply returns an Object containing a set of functions, but when account.getBalance() is called, the function is able to “remember” its initial reference to balance. That is the power of the closure, which allows a function to “remember” its lexical scope (compile-time scope) even though it is implemented outside of that lexical scope.

Difference Between call(), apply() and bind()

Since arrow functions are anonymous functions and it don’t create its own functional context, call(), bind(), and apply() methods can’t be called or implemented on them.

Bind()

Bind is discussed first to emphasize its superiority over call and apply methods.

– bind() is called on a function, to pass our custom this variable to it

– In this case, we need the scope of the object obj, so we pass that inside the bind(). With this implementation, the function foo executes in the context of obj. i.e., this keyword inside the foo() function, now point to the property parent of the object obj

function foo(k, l) {
return this.parent + k + l;
}
var obj = {
parent: 2,
};
console.log(foo.bind(obj)(1, 2));
//output : 5

– The bind() method returns a new function, which is then executed with the arguments 1,2 in line 7.

However in the end, bind() is just a method to pass the custom this variable/custom Object to a function, which returns another function with the given context, which can then be executed by us (with or without arguments).

--

--