JavaScript The Tricky Parts: Part-1

Samayun Miah Chowdhury
21 min readMay 5, 2021

Hey Programmers What are you doing now ?

Did you read my love story relationship with javascript .If no , please read it first & continue from here.

Hey ,I am Samayun Chowdhury speaking here to make your coding life easier , smarter & comfortable. I will talk about most critical parts of javascript in this series . So don’t waste time . Take a glass of coffee & read my blogs .

Here I am covering 10 tricky topics of basic javascript .

* Coercion

Defination : Type coercion is the process of converting value from one type to another (such as string to number, object to boolean, and so on).

Implicit vs. explicit coercion

Type coercion can be explicit and implicit.

When a developer expresses the intention to convert between types by writing the appropriate code, like Number(value), it’s called explicit type coercion (or type casting).

Since JavaScript is a weakly-typed language, values can also be converted between different types automatically, and it is called implicit type coercion. It usually happens when you apply operators to values of different types, like
1 == null, 2/’5', null + new Date(), or it can be triggered by the surrounding context, like with if (value) {…}, where value is coerced to boolean.

One operator that does not trigger implicit type coercion is ===, which is called the strict equality operator. The loose equality operator == on the other hand does both comparison and type coercion if needed.

Three types of conversion

The first rule to know is there are only three types of conversion in JavaScript:

  • to string
  • to boolean
  • to number

Secondly, conversion logic for primitives and objects works differently, but both primitives and objects can only be converted in those three ways.

Let’s start with primitives first.

String conversion

To explicitly convert values to a string apply the String() function. Implicit coercion is triggered by the binary + operator, when any operand is a string:

String(123) // explicit
123 + '' // implicit

All primitive values are converted to strings naturally as you might expect:

String(123)                   // '123'
String(-12.3) // '-12.3'
String(null) // 'null'
String(undefined) // 'undefined'
String(true) // 'true'
String(false) // 'false'

Symbol conversion is a bit tricky, because it can only be converted explicitly, but not implicitly. Read more on Symbol coercion rules.

String(Symbol('my symbol'))   // 'Symbol(my symbol)'
'' + Symbol('my symbol') // TypeError is thrown

Boolean conversion

To explicitly convert a value to a boolean apply the Boolean() function.
Implicit conversion happens in logical context, or is triggered by logical operators ( || && !) .

Boolean(2)          // explicit
if (2) { ... } // implicit due to logical context
!!2 // implicit due to logical operator
2 || 'hello' // implicit due to logical operator

Note: Logical operators such as || and && do boolean conversions internally, but actually return the value of original operands, even if they are not boolean.

// returns number 123, instead of returning true
// 'hello' and 123 are still coerced to boolean internally to calculate the expression
let x = 'hello' && 123; // x === 123

As soon as there are only 2 possible results of boolean conversion: true or false, it’s just easier to remember the list of falsy values.

Boolean('')           // false
Boolean(0) // false
Boolean(-0) // false
Boolean(NaN) // false
Boolean(null) // false
Boolean(undefined) // false
Boolean(false) // false

Any value that is not in the list is converted to true, including object, function, Array, Date, user-defined type, and so on. Symbols are truthy values. Empty object and arrays are truthy values as well:

Boolean({})             // true
Boolean([]) // true
Boolean(Symbol()) // true
!!Symbol() // true
Boolean(function() {}) // true

Numeric conversion

For an explicit conversion just apply the Number() function, same as you did with Boolean() and String() .

Implicit conversion is tricky, because it’s triggered in more cases:

  • comparison operators (>, <, <=,>=)
  • bitwise operators ( | & ^ ~)
  • arithmetic operators (- + * / % ). Note, that binary+ does not trigger numeric conversion, when any operand is a string.
  • unary + operator
  • loose equality operator == (incl. !=).
    Note that == does not trigger numeric conversion when both operands are strings.
Number('123')   // explicit
+'123' // implicit
123 != '456' // implicit
4 > '5' // implicit
5/null // implicit
true | 0 // implicit

Here is how primitive values are converted to numbers:

Number(null)                   // 0
Number(undefined) // NaN
Number(true) // 1
Number(false) // 0
Number(" 12 ") // 12
Number("-12.34") // -12.34
Number("\n") // 0
Number(" 12s ") // NaN
Number(123) // 123

When converting a string to a number, the engine first trims leading and trailing whitespace, \n, \t characters, returning NaN if the trimmed string does not represent a valid number. If string is empty, it returns 0.

null and undefined are handled differently: null becomes 0, whereas undefined becomes NaN.

Symbols cannot be converted to a number neither explicitly nor implicitly. Moreover, TypeError is thrown, instead of silently converting to NaN, like it happens for undefined. See more on Symbol conversion rules on MDN.

Number(Symbol('my symbol'))    // TypeError is thrown
+Symbol('123') // TypeError is thrown

There are two special rules to remember:

  1. When applying == to null or undefined, numeric conversion does not happen. null equals only to null or undefined, and does not equal to anything else.
null == 0               // false, null is not converted to 0
null == null // true
undefined == undefined // true
null == undefined // true

2. NaN does not equal to anything even itself:

if (value !== value) { console.log("we're dealing with NaN here") }

Type coercion for objects

So far, we’ve looked at type coercion for primitive values. That’s not very exciting.

When it comes to objects and engine encounters expression like [1] + [2,3], first it needs to convert an object to a primitive value, which is then converted to the final type. And still there are only three types of conversion: numeric, string and boolean.

The simplest case is boolean conversion: any non-primitive value is always
coerced to true, no matter if an object or an array is empty or not.

Objects are converted to primitives via the internal [[ToPrimitive]] method, which is responsible for both numeric and string conversion.

Here is a pseudo implementation of [[ToPrimitive]] method:

[[ToPrimitive]] is passed with an input value and preferred type of conversion: Number or String. preferredType is optional.

Both numeric and string conversion make use of two methods of the input object: valueOf and toString . Both methods are declared on Object.prototype and thus available for any derived types, such as Date, Array, etc.

In general the algorithm is as follows:

  1. If input is already a primitive, do nothing and return it.

2. Call input.toString(), if the result is primitive, return it.

3. Call input.valueOf(), if the result is primitive, return it.

4. If neither input.toString() nor input.valueOf() yields primitive, throw TypeError.

Numeric conversion first calls valueOf (3) with a fallback to toString (2). String conversion does the opposite: toString (2) followed by valueOf (3).

Most built-in types do not have valueOf, or have valueOf returning this object itself, so it’s ignored because it’s not a primitive. That’s why numeric and string conversion might work the same — both end up calling toString().

Different operators can trigger either numeric or string conversion with a help of preferredType parameter. But there are two exceptions: loose equality == and binary + operators trigger default conversion modes (preferredType is not specified, or equals to default). In this case, most built-in types assume numeric conversion as a default, except Date that does string conversion.

Here is an example of Date conversion behavior:

You can override the default toString() and valueOf() methods to hook into object-to-primitive conversion logic.

Notice how obj + ‘’ returns ‘101’ as a string. + operator triggers a default conversion mode, and as said before Object assumes numeric conversion as a default, thus using the valueOf() method first instead of toString()

Scope

A scope in JavaScript defines what variables you have access to. There are two kinds of scope — global scope and local scope.

Global scope

If a variable is declared outside all functions or curly braces ({}), it is said to be defined in the global scope.

const hello = 'ami policego nachai, police e toh amar gonda . gonda laage ar?'

function sayHello () {
console.log(hello)
}

console.log(hello) // 'ami policego nachai, police e toh amar v . gonda laage ar'
sayHello() // 'ami policego nachai, police e toh amar gonda . gonda laage ar'

Local Scope

Variables that are usable only in a specific part of your code are considered to be in a local scope. These variables are also called local variables.

In JavaScript, there are two kinds of local scope: function scope and block scope.

Let’s talk about function scopes first.

Function scope

When you declare a variable in a function, you can access this variable only within the function. You can’t get this variable once you get out of it.

In the example below, the variable hello is in the sayHello scope:

function sayHello () {
const hello = 'Hello CSS-Tricks Reader!'
console.log(hello)
}
sayHello() // 'Hello CSS-Tricks Reader!'
console.log(hello) // Error, hello is not defined

Block scope

When you declare a variable with const or let within a curly brace ({}), you can access this variable only within that curly brace.

In the example below, you can see that hello is scoped to the curly brace:

{
const hello = 'Hello CSS-Tricks Reader!'
console.log(hello) // 'Hello CSS-Tricks Reader!'
}
console.log(hello) // Error, hello is not defined

The block scope is a subset of a function scope since functions need to be declared with curly braces (unless you’re using arrow functions with an implicit return).

Function hoisting and scopes

Functions, when declared with a function declaration, are always hoisted to the top of the current scope. So, these two are equivalent:

// This is the same as the one below
sayHello()
function sayHello () {
console.log('Hello CSS-Tricks Reader!')
}
// This is the same as the code above
function sayHello () {
console.log('Hello CSS-Tricks Reader!')
}
sayHello()

When declared with a function expression, functions are not hoisted to the top of the current scope.

sayHello() // Error, sayHello is not defined
const sayHello = function () {
console.log(aFunction)
}

Because of these two variations, function hoisting can potentially be confusing, and should not be used. Always declare your functions before you use them.

Functions do not have access to each other’s scopes

Functions do not have access to each other’s scopes when you define them separately, even though one function may be used in another.

In this example below, second does not have access to firstFunctionVariable.

function first () {
const firstFunctionVariable = `I'm part of first`
}
function second () {
first()
console.log(firstFunctionVariable) // Error, firstFunctionVariable is not defined
}

Nested scopes

When a function is defined in another function, the inner function has access to the outer function’s variables. This behavior is called lexical scoping.

However, the outer function does not have access to the inner function’s variables.

function outerFunction () {
const outer = `I'm the outer function!`
function innerFunction() {
const inner = `I'm the inner function!`
console.log(outer) // I'm the outer function!
}
console.log(inner) // Error, inner is not defined
}

To visualize how scopes work, you can imagine one-way glass. You can see the outside, but people from the outside cannot see you.

If you have scopes within scopes, visualize multiple layers of one-way glass.

After understanding everything about scopes so far, you’re well primed to figure out what closures are.

Closures

Whenever you create a function within another function, you have created a closure. The inner function is the closure. This closure is usually returned so you can use the outer function’s variables at a later time.

function outerFunction () {
const outer = `I see the outer variable!`
function innerFunction() {
console.log(outer)
}
return innerFunction
}
outerFunction()() // I see the outer variable!

Since the inner function is returned, you can also shorten the code a little by writing a return statement while declaring the function.

function outerFunction () {
const outer = `I see the outer variable!`
return function innerFunction() {
console.log(outer)
}
}
outerFunction()() // I see the outer variable!

Since closures have access to the variables in the outer function, they are usually used for two things:

  1. To control side effects
  2. To create private variables

Controlling side effects with closures

Side effects happen when you do something in aside from returning a value from a function. Many things can be side effects, like an Ajax request, a timeout or even a console.log statement:

function (x) {
console.log('A console.log is a side effect!')
}

When you use closures to control side effects, you’re usually concerned with ones that can mess up your code flow like Ajax or timeouts.

Let’s go through this with an example to make things clearer.

Let’s say you want to make a cake for your friend’s birthday. This cake would take a second to make, so you wrote a function that logs made a cake after one second.

I’m using ES6 arrow functions here to make the example shorter, and easier to understand.

function makeCake() {
setTimeout(_ => console.log(`Made a cake`), 1000)
}

As you can see, this cake making function has a side effect: a timeout.

Let’s further say you want your friend to choose a flavor for the cake. To do so, you can write add a flavor to your makeCake function.

function makeCake(flavor) {
setTimeout(_ => console.log(`Made a ${flavor} cake!`), 1000)
}

When you run the function, notice the cake gets made immediately after one second.

makeCake('banana')
// Made a banana cake!

The problem here is that you don’t want to make the cake immediately after knowing the flavor. You want to make it later when the time is right.

To solve this problem, you can write a prepareCake function that stores your flavor. Then, return the makeCake closure within prepareCake.

From this point on, you can call the returned function whenever you want to, and the cake will be made within a second.

function prepareCake (flavor) {
return function () {
setTimeout(_ => console.log(`Made a ${flavor} cake!`), 1000)
}
}
const makeCakeLater = prepareCake('banana')// And later in your code...
makeCakeLater()
// Made a banana cake!

That’s how closures are used to reduce side effects — you create a function that activates the inner closure at your whim.

Private variables with closures

As you know by now, variables created in a function cannot be accessed outside the function. Since they can’t be accessed, they are also called private variables.

However, sometimes you need to access such a private variable. You can do so with the help of closures.

function secret (secretCode) {
return {
saySecretCode () {
console.log(secretCode)
}
}
}
const theSecret = secret('JavaScript is cool!')
theSecret.saySecretCode()
// 'JavaScript is cool!'

saySecretCode in this example above is the only function (a closure) that exposes the secretCode outside the original secret function. As such, it is also called a privileged function.

Hoisting

Definition : Hoisting in JavaScript is a behavior in which a function or a variable can be used before declaration.

Although JavaScript is an interpreted language, implementation in a web development setting involves a step immediately prior to execution called lexical scoping (tokenizing), in which the interpreter skims through your code and identifies all the variables you’ve declared, makes a note of when they’re reassigned, and delineates chunks of code into scopes in three levels: block, function, and global.

// Example 1 (credit MDN)function exampleFunction() { 
var x = "declared inside function"; // x can only be used in exampleFunction
console.log("Inside function");
console.log(x);
}
console.log(x); // Causes Reference Error

The function’s scope includes the variable x, so that variable is only known within that function. Trying to access it out in the global scope will throw an error because x is not a declared variable (it’s not even undefined).

If we move that var declaration outside the function, it’ll be in the global scope, everyone knows about it, and we can access it within and outside of the function:

// Example 2 (credit MDN)var x = "declared outside function";exampleFunction();function exampleFunction() { 
console.log("Inside function");
console.log(x);
}
console.log("Outside function");
console.log(x);

With the advent of ECMAScript2015 (aka “ES6”), two new ways to declare variables were introduced: let and const, which are significant because they enable more granular control over the scope in which a variable is available. Both let and const define local variables which are available only in the level in which they’re defined (whether a code block or function, and any contained sub-blocks).

In the following example, x is declared with var, and that same variable called x is known throughout the function (even on lines which precede it!) and in sub-blocks. If x is declared with the newer let or const, then outer scopes don’t have access to it, and if we “let x;” again in a sub-block, it’s effectively a different variable (like how human twins separated at birth, but given the same name, are not the same person).

// Example 3 (credit MDN) 
function varTest() {
var x = 1;
if (true) {
var x = 2; // same variable!
console.log(x); // 2
}
console.log(x); // 2
}
function letTest() {
let x = 1;
if (true) {
let x = 2; // different variable
console.log(x); // 2
}
console.log(x); // 1
}

This is relevant because of the lexing step that happens immediately prior to executing the code, and the fact that this:

var x = 5;

is two steps listed on one line: the declaration of the variable x, and the assignment of the integer 5 to that variable. We could also write it like this:

var x;  // declaration
x = 5; // assignment

When the variable is declared with var, its value is undefined, but it is known to be a variable. Then the next line makes x’s value equal to 5. But, this isn’t the case with let and const. Welcome to the Temporal Dead Zone.

// Example 4 (credit MDN)
function doSomething() {
console.log(bar); // undefined
console.log(foo); // ReferenceError
var bar = 1;
let foo = 2;
}

Within this function, the declaration of bar is hoisted to the top of the scope, in this case, the code contained within the function doSomething(). So, effectively, it’s executed like this:

// Example 5 
function doSomething() {
var bar;
console.log(bar); // undefined
console.log(foo); // ReferenceError
bar = 1;
let foo = 2;
}

which is why trying to console.log(bar) yields undefined (we know it’s a variable, it just has no value), while console.log(foo) throws a reference error (“a variable called ‘foo’? what are you even talking about, human?”)

This makes things like this possible:

// Example 6 (credit MDN)
num = 6;
console.log(num); // returns 6
var num;

and:

// Example 7 (credit MDN) 
dogName("Watson");
function dogName(name) {
console.log("My dog's name is " + name);
}
// "My dog's name is Watson"

In the first example, even though it looks like var num is declared after we assign it, from the computer’s perspective, it noticed that we’ve declared it in the relevant scope (global), pins that to the top, and then proceeds with executing the rest of the code. In the second example, even though we invoke/call the function before we’ve defined it, that definition is hoisted to the top of the scope, so by the time we actually start executing the code, the interpreter already knows what dogName() is.

For var variables, note that only the declaration gets hoisted, not the assignment. So, in Example 6, writing it like this:

console.log(num); // returns undefined 
var num = 6;

returns undefined. For this reason, it’s often suggested to always declare variables at the top of the scope they’re in, so you remember the order in which the interpreter will execute your code. Alternatively, using let and const offer some protection against this behavior, since variables declared this way are not initialized with a value of undefined. So even though they’re hoisted, you’ll still get a reference error because they won’t be initialized until they’re assigned. It’s almost like they’re not being hoisted at all. const has an added advantage of protecting against unexpected reassignment (although an object declared this way may still have its properties modified), like so:

// Example 8 (credit Digital Ocean)
// Create a CAR object with two properties
const CAR = {
color: "blue",
price: 15000
}
// Modify a property of CAR
CAR.price = 20000;
console.log(CAR);// Output
// { color: 'blue', price: 20000 }

Similarly, functions follow similar rules. Function declarations are hoisted:

// Example 9 (credit Elizabeth Mabishi at Scotch.io)hoisted(); // Output: "This function has been hoisted."function hoisted() {
console.log('This function has been hoisted.');
};

… while function expressions are not:

// Example 10 (credit Elizabeth Mabishi at Scotch.io)expression(); //Output: "TypeError: expression is not a functionvar expression = function() {
console.log('Will this work?');
};

How this fits into this

A related topic, which I will discuss as it relates to scope and hoisting, is this. Gordon Zhu created a nice cheatsheet which summarizes the corresponding lesson in his life-changing curriculum on Watch & Code. Essentially this is scope dependent (context). If it’s called within a regular function or just out in the wild, this points to window. If you’re in a function being called as a method, this points to the object being acted upon (whatever’s just to the left of the dot).

// Example 11 (credit Gordon Zhu)
var myObject = {
myMethod: function() {
console.log(this);
}
};
myObject.myMethod(); // --\> myObject

An extension of this is the case where this is used in a constructor as in Example 12, in which this refers to the instance of the class Person:

// Example 12 (credit MDN) 
function Person(name, age) {
this.name = name;
this.age = age;
}

Explicitly setting the value of this using call, bind, and apply is outside the scope (haha!) of this blog post.

And in a callback function, it depends on where (what scope) this is being called in, in accordance with the previous examples.

Closure

Defination : A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function’s scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time.

To use a closure, define a function inside another function and expose it. To expose a function, return it or pass it to another function.

The inner function will have access to the variables in the outer function scope, even after the outer function has returned.

Error Handling

An error in JavaScript is an object, which is later thrown to halt the program.

To create a new error in JavaScript we call the appropriate constructor function. For example, to create a new, generic error we can do:

const err = new Error("Something bad happened!");

When creating an error object it’s also possible to omit the new keyword:

const err = Error("Something bad happened!");

Once created, the error object presents three properties:

  • message: a string with the error message.
  • name: the error's type.
  • stack: a stack trace of functions execution.

For example, if we create a new TypeError object with the appropriate message, the message will carry the actual error string, while name will be "TypeError":

const wrongType = TypeError("Wrong type given, expected number");wrongType.message; // "Wrong type given, expected number"
wrongType.name; // "TypeError"

Firefox also implements a bunch on non-standard property like columnNumber, filename, and lineNumber.

Many types of errors in JavaScript

There are many types of errors in JavaScript, namely:

  • Error
  • EvalError
  • InternalError
  • RangeError
  • ReferenceError
  • SyntaxError
  • TypeError
  • URIError

Remember, all these error types are actual constructor functions meant to return a new error object.

In your code you’ll mostly use Error and TypeError, two of the most common types, to create your own error object.

Most of the times, the majority of errors will come directly from the JavaScript engine, like InternalError or SyntaxError.

An example of TypeError occurs when you try to reassign const:

const name = "Jules";
name = "Caty";
// TypeError: Assignment to constant variable.

An example of SyntaxError is when you misspell language keywords:

va x = '33';
// SyntaxError: Unexpected identifier

Or when you use reserved keywords in wrong places, like await outside of an async function:

function wrong(){
await 99;
}
wrong();// SyntaxError: await is only valid in async function

Another example of TypeError occurs when we select non-existent HTML elements in the page:

Uncaught TypeError: button is null

In addition to these traditional error objects, an AggregateError object is going to land soon in JavaScript. AggregateError is convenient for wrapping multiple errors together, as we'll see later.

Besides these built-in errors, in the browser we can find also:

  • DOMException.
  • DOMError, deprecated and no longer used today.

DOMException is a family of errors related to Web APIs. They are thrown when we do silly things in the browser, like:

document.body.appendChild(document.cloneNode(true));

The result:

Uncaught DOMException: Node.appendChild: May not add a Document as a child

When we throw from an async function the exception becomes cause of rejection for the underlying Promise.

Any error can be intercepted with catch from the outside.

Most important, in addition to this style we can use try/catch/finally, much as we would do with a synchronous function.

In the following example we call toUppercase from another function, consumer, which conveniently wraps the function call with try/catch/finally:

async function toUppercase(string) {
if (typeof string !== "string") {
throw TypeError("Wrong type given, expected a string");
}
return string.toUpperCase();
}
async function consumer() {
try {
await toUppercase(98);
} catch (error) {
console.error(error.message);
} finally {
console.log("Always runs!");
}
}
consumer(); // Returning Promise ignored

The output is:

Wrong type given, expected a string
Always runs!

* Callback Functions

Definiton : A function is a block of code that performs a certain task when called

In JavaScript, functions are objects. Can we pass objects to functions as parameters? Yes.

So, we can also pass functions as parameters to other functions and call them inside the outer functions. Sounds complicated? Let me show that in an example below:

function print(callback) {  
callback();
}

The print( ) function takes another function as a parameter and calls it inside. This is valid in JavaScript and we call it a “callback”. So a function that is passed to another function as a parameter is a callback function. But that’s not all.

You can also watch the video version of callback functions below:

Why do we need Callback Functions?

JavaScript runs code sequentially in top-down order. However, there are some cases that code runs (or must run) after something else happens and also not sequentially. This is called asynchronous programming.

Callbacks make sure that a function is not going to run before a task is completed but will run right after the task has completed. It helps us develop asynchronous JavaScript code and keeps us safe from problems and errors.

In JavaScript, the way to create a callback function is to pass it as a parameter to another function, and then to call it back right after something has happened or some task is completed. Let’s see how…

How to create a Callback

To understand what I’ve explained above, let me start with a simple example. We want to log a message to the console but it should be there after 3 seconds.

const message = function() {  
console.log("This message is shown after 3 seconds");
}

setTimeout(message, 3000);

There is a built-in method in JavaScript called “setTimeout”, which calls a function or evaluates an expression after a given period of time (in milliseconds). So here, the “message” function is being called after 3 seconds have passed. (1 second = 1000 milliseconds)

In other words, the message function is being called after something happened (after 3 seconds passed for this example), but not before. So the message function is an example of a callback function.

What is an Anonymous Function?

Alternatively, we can define a function directly inside another function, instead of calling it. It will look like this:

setTimeout(function() {  
console.log("This message is shown after 3 seconds");
}, 3000);

As we can see, the callback function here has no name and a function definition without a name in JavaScript is called as an “anonymous function”. This does exactly the same task as the example above.

Callback as an Arrow Function

If you prefer, you can also write the same callback function as an ES6 arrow function, which is a newer type of function in JavaScript:

setTimeout(() => { 
console.log("This message is shown after 3 seconds");
}, 3000);

Asynchronous Code

“I will finish later!”

Functions running in parallel with other functions are called asynchronous

A good example is JavaScript setTimeout()

In the real world, callbacks are most often used with asynchronous functions.

It’s big topic. I suggest you read these articles

https://blog.bitsrc.io/understanding-asynchronous-javascript-the-event-loop-74cd408419ff

Danger THIS Keyword

this keyword refers to an object, that object which is executing the current bit of javascript code.

The JavaScript this keyword refers to the object it belongs to.

It has different values depending on where it is used:

  • In a method, this refers to the owner object.
  • Alone, this refers to the global object.
  • In a function, this refers to the global object.
  • In a function, in strict mode, this is undefined.
  • In an event, this refers to the element that received the event.
  • Methods like call(), and apply() can refer this to any object
const person = {
firstName: "John",
lastName : "Doe",
id : 5566,
fullName : function() {
return this.firstName + " " + this.lastName;
}
};
console.log(person.fullName());

* Prototype Inheritance

All JavaScript objects inherit properties and methods from a prototype:

  • Date objects inherit from Date.prototype
  • Array objects inherit from Array.prototype
  • Person objects inherit from Person.prototype

The Object.prototype is on the top of the prototype inheritance chain:

Date objects, Array objects, and Person objects inherit from Object.prototype.

Adding Properties and Methods to Objects

Sometimes you want to add new properties (or methods) to all existing objects of a given type.

Sometimes you want to add new properties (or methods) to an object constructor.

function Person(first, last, age, eye) {
this.firstName = first;
this.lastName = last;
this.age = age;
this.eyeColor = eye;
}
Person.prototype.nationality = "English";
const myFather = new Person("John", "Doe", 50, "blue");
console.log(myFather.nationality);

To know more check these

https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes

* Immediately Invoked Function Expression — IIFE

Immediately Invoked Function Expression (IIFE) is one of the most popular design patterns in JavaScript. It pronounces like iify. IIFE has been used since long by JavaScript community but it had misleading term “self-executing anonymous function”. Ben Alman gave it appropriate name “Immediately Invoked Function Expression”

const makeWithdraw = balance => (function(copyBalance) {
let balance = copyBalance; // This variable is private
let doBadThings = function() {
console.log("I will do bad things with your money");
};
doBadThings();
return {
withdraw: function(amount) {
if (balance >= amount) {
balance -= amount;
return balance;
} else {
return "Insufficient money";
}
},
}
})(balance);

const firstAccount = makeWithdraw(100); // "I will do bad things with your money"
console.log(firstAccount.balance); // undefined
console.log(firstAccount.withdraw(20)); // 80
console.log(firstAccount.withdraw(30)); // 50
console.log(firstAccount.doBadThings); // undefined, this method is private
const secondAccount = makeWithdraw(20);
secondAccount.withdraw(30); // "Insufficient money"
secondAccount.withdraw(20); // 0

Thank You for reading this

--

--

Samayun Miah Chowdhury

Fan of JavaScript & Python lover Feels good to introduced as a realtime web application developer sunglasses PWA is my crushwink I do 2 times teeth brush