Introduction to JavaScript Fundamentals

Introduction to JavaScript Fundamentals

  • Checking for a Property in an Object: Techniques to verify the presence of properties within objects.
  • Checking if a Number is Finite and Not NaN: Methods to validate the finiteness and non-NaN status of numbers.
  • Concept of Hoisting in JavaScript: Exploring how variable and function declarations are moved to the top of their scope.
  • Deciphering JavaScript Code Output: Skills for understanding and predicting the output of JavaScript code.
  • Declaring an Immutable Variable with ES6: Use of const in ES6 for creating unmodifiable variables.
  • Detecting a User’s Device Type: Techniques for identifying the type of device a user is on for responsive design.
  • Differences Between == and ===: Understanding the comparison operators for type coercion (==) and strict equality (===).
  • Distinguishing Between null and undefined: Grasping the distinct roles of null and undefined in representing absence of value.
  • Interpreting the Result of an Expression: Analyzing and understanding the outcome of JavaScript expressions.
  • Rounding a Number to Two Decimal Places: Techniques for rounding numbers to a specified level of precision.
  • Spreading a Set into an Array: Utilizing the spread operator to convert a Set into an Array.
  • The Return Value of typeof null: Understanding why typeof null returns “object”.
  • The Role of the void Operator: Exploring the use of the void operator for evaluating expressions without returning a value.

Core Principles and Fundamentals of JavaScript

In this section, we delve into the core principles and peculiarities that define JavaScript as a dynamic and versatile programming language. From understanding the intricacies of data type coercion to mastering the modern syntax introduced in ES6, our journey will equip you with the knowledge to write efficient and effective JavaScript code. Each concept is illustrated with practical examples, ensuring that you not only learn the theory but also how to apply it in real-world scenarios.

This section is designed to build a strong foundation in JavaScript, addressing both fundamental concepts and advanced features introduced in ES6. By understanding these principles, you’ll be better equipped to tackle JavaScript’s dynamic and sometimes unpredictable nature, making your journey into web development more informed and confident.

Chrome DevTools

Chrome Developer Tools, commonly known as DevTools, are a set of web developer tools built directly into the Google Chrome browser. They provide developers with deep access to the internals of the browser and their web application. Using DevTools, you can edit pages on-the-fly, diagnose problems quickly, and build better websites faster. Here’s a basic guide on how to use DevTools, particularly focusing on the Console.

Image : Accessing DevTools in Chrome

Accessing DevTools

Open DevTools: There are several ways to open Chrome DevTools.

  • Right-click on any page element and select “Inspect”.
  • Use the keyboard shortcut Ctrl+Shift+I (or Cmd+Opt+I on Mac).
  • From Chrome menu at the top-right, go to More tools > Developer tools.

Navigating to the Console: Once DevTools is open, you can click on the “Console” tab to switch to the console view. The console is a powerful tool that allows developers to interact with the JavaScript context of the current page, run scripts, and log information.

Understanding the Output of a Code Snippet

When analyzing a JavaScript code snippet to predict its output, it’s essential to consider the data types involved and how JavaScript interprets them.  One of the quickest ways to see an output is using the console.log() which allows you to see the results in the DevTools console.  

For example:

console.log(1 + “2” + 3);

This code demonstrates type coercion, where JavaScript converts the numbers 1 and 3 into strings to concatenate with “2”, resulting in the string “123”.

Image : Shows output of the console log from the devTools. 

Understanding console.log(1 + “2” + 3) Output

When you run console.log(1 + “2” + 3); in the console, it performs the following operations:

  • First, it evaluates 1 + “2”, which results in “12”. In JavaScript, when you use the + operator with a number and a string, the number is converted to a string and concatenated.
  • Then, it evaluates “12” + 3, which results in “123” for the same reason.

So, console.log(1 + “2” + 3); outputs “123” to the console.

Regarding the undefined output:

  • After executing a statement, the console also displays the return value of that statement.
  • console.log() itself does not return a value (or, in JavaScript terms, it returns undefined).
  • Therefore, after printing “123” to the console, it also shows undefined to indicate the return value of the console.log() function call.

This behavior is specific to the console. It’s designed to give immediate feedback about the return values of executed statements, which can be particularly useful for debugging and interactive coding sessions.

To understand the output of a code snippet, you need to run it and observe the result. Let’s consider a simple example:

console.log(2 + 2);

Output: 4

Interpreting the Result of an Expression

Evaluating expressions in JavaScript can yield various results based on the operators used. 

For instance:

5 == “5”

This expression evaluates to true because the == operator performs type coercion, allowing value comparison despite different data types.

Evaluating an expression and interpreting its result involves understanding the types of values involved and how operations affect them. 

For example:

console.log(“Hello ” + “World!”);

Output: Hello World!

Deciphering JavaScript Code Output

To predict the output of JavaScript code, understanding the context and operation is crucial. For example:

console.log(typeof NaN);

The output is number, illustrating that NaN (Not-a-Number) is paradoxically classified as a number type in JavaScript.

To decipher code output, consider the data types and operations. 

For example:

console.log(1 + “2”);

Output: 12 (because “2” is a string, the + operator concatenates instead of adds numerically).

The Significance == Operator for Equality

JavaScript’s == operator performs type coercion, allowing comparison of values across different data types, unlike the === operator, which requires both value and type to be the same.

console.log(’10’ == 10); // true because of type coercion

console.log(’10’ === 10); // false because the types are different

The == operator checks for equality after converting both operands to a common type. This feature, known as type coercion, can lead to unexpected results when comparing different data types, emphasizing the importance of understanding type conversion in JavaScript.

The == operator checks for equality after converting both operands to the same type.

console.log(‘1’ == 1);

Output: true (type coercion happens, converting the number 1 to a string “1”).

Differences Between == and ===

The == operator performs type coercion to compare values, potentially leading to non-intuitive results. In contrast, === is the strict equality operator that compares both the value and type without converting them, offering a more accurate equality check.

== performs type coercion, while === checks for strict equality without type conversion.

console.log(‘1’ == 1); // true

console.log(‘1’ === 1); // false

The Return Value of typeof null

In JavaScript, null is an object, which can be confusing. null and undefined are both used to represent absence of value but in slightly different contexts.

The expression typeof null interestingly returns object, a known quirk of JavaScript. This behavior is considered a bug from the early days of JavaScript but has been maintained for compatibility reasons.

The typeof operator returns a string indicating the type of the unevaluated operand.

console.log(typeof null);

Output: object (this is a long-standing JavaScript bug).

let notDefined;

console.log(notDefined); // undefined

console.log(null === undefined); // false

console.log(null == undefined); // true, due to type coercion

Distinguishing Between null and undefined

null and undefined in JavaScript represent the absence of a value, but in different contexts. null is used to intentionally indicate that a variable has no value or object assigned to it, while undefined signifies that a variable has been declared but not yet assigned a value.

null is an assignment value that means “no value”, while undefined means a variable has been declared but not assigned a value.

let a;

console.log(a); // undefined

console.log(null); // null

Spreading a Set into an Array

The spread operator (…) allows an iterable such as a Set to be expanded in places where zero or more arguments (for function calls) or elements (for array literals) are expected.

Using the spread operator to convert a Set into an array illustrates the seamless integration of ES6 features for working with collections. 

This technique provides a concise and effective way to create arrays from Set objects, leveraging the unique properties of Sets.

The spread syntax allows an iterable like a set to be expanded in places where zero or more arguments or elements are expected.

const mySet = new Set([1, 2, 3]);

const myArray = […mySet];

console.log(myArray);

Output: [1, 2, 3]

Spreading a set into an array in JavaScript can be particularly useful when you need to manipulate the data stored in a set with array methods, or when you need to ensure the uniqueness of elements in an array. Here are three examples illustrating how to spread a set into an array:

Example 1: Basic Spreading of a Set

Suppose you have a set of numbers and you want to create an array from this set.

const numberSet = new Set([1, 2, 3, 4, 5]);

const numberArray = […numberSet];

console.log(numberArray); // Output: [1, 2, 3, 4, 5]

Example 2: Combining Two Sets into One Array

If you have two sets and you want to combine them into a single array without duplicates, you can use the spread operator on both sets within an array literal.

const set1 = new Set([1, 2, 3]);

const set2 = new Set([3, 4, 5]);

const combinedArray = […set1, …set2];

console.log(combinedArray); // Output: [1, 2, 3, 4, 5]

This example combines set1 and set2, and because sets automatically remove duplicates, spreading them into an array combines them without duplicates.

Example 3: Using Set to Remove Duplicates from an Array then Spreading into a New Array

Sometimes, you might start with an array that has duplicates and you want to remove these duplicates. You can convert the array to a set (which removes duplicates) and then spread it back into an array.

const arrayWithDuplicates = [1, 2, 2, 3, 4, 4, 5];

const uniqueArray = […new Set(arrayWithDuplicates)];

console.log(uniqueArray); // Output: [1, 2, 3, 4, 5]

This example first converts arrayWithDuplicates into a set to remove duplicates, then spreads this set into a new array, resulting in an array of unique values.

These examples demonstrate the versatility of the spread operator with sets, allowing for unique combinations, deduplication, and conversion between sets and arrays.

Concept of Hoisting in JavaScript

Hoisting is JavaScript’s behavior of moving variable and function declarations to the top of their containing scope during the compile phase.

Hoisting is a JavaScript mechanism where variable and function declarations are moved to the top of their containing scope during the compilation phase. This allows variables and functions to be used before they are declared in the code.

Hoisting is JavaScript’s default behavior of moving declarations to the top.

console.log(x);

var x = 5;

Output: undefined (not a ReferenceError, because the declaration of x is hoisted).

The concept of hoisting in JavaScript refers to the behavior where variable and function declarations are moved to the top of their containing scope before code execution. This means that variables and functions can be referenced before they are declared in the code. It’s important to note that only declarations are hoisted, not initializations. 

Here are three examples illustrating hoisting in JavaScript:

Example 1: Function Hoisting

Function declarations are hoisted, allowing them to be called before they are defined in the code.

// Calling the function before its declaration

greet();

// Function declaration

function greet() {

  console.log(‘Hello, world!’);

}

// Output: “Hello, world!”

In this example, the greet function is called before it is declared. Due to function hoisting, JavaScript moves the declaration to the top during the compilation phase, making this call valid.

Example 2: Variable Hoisting with var

Variable declarations (but not initializations) using var are hoisted to the top of their scope, which can lead to unexpected results.

console.log(message); // Output: undefined

var message = ‘Hoisting is here!’;

// The above code behaves as if it was written like this:

// var message;

// console.log(message);

// message = ‘Hoisting is here!’;

In this example, accessing message before its declaration outputs undefined because only the declaration (var message;) is hoisted to the top, not the initialization (message = ‘Hoisting is here!’;).

Example 3: Hoisting Limitations with let and const

Variables declared with let and const are also hoisted, but they do not get initialized with a value. Accessing them before the declaration results in a ReferenceError due to the Temporal Dead Zone (TDZ).

console.log(name); // ReferenceError: Cannot access ‘name’ before initialization

let name = ‘JavaScript’;

Even though let and const declarations are hoisted, trying to access name before its declaration throws a ReferenceError because let and const variables are in a TDZ until their declaration is evaluated.

These examples demonstrate how hoisting works in JavaScript with functions and variables, and how the behavior differs depending on the type of declaration (var, let, const). Understanding hoisting is crucial for avoiding common pitfalls and writing predictable JavaScript code.

The Role of the void Operator

The void operator evaluates an expression and then returns undefined. It’s useful for hyperlinks that don’t actually navigate anywhere.

The void operator evaluates an expression and then returns undefined. This can be useful in scenarios where you need to ensure no value is returned:

void function() {

 console.log(“This will run, but return undefined”);

}();

The void operator evaluates the given expression and then returns undefined.

console.log(void(0));

Output: undefined

Rounding a Number to Two Decimal Places

JavaScript provides methods for working with numbers, including rounding and checking finiteness.

To round a number to two decimal places, you can use the toFixed() method, which converts a number into a string, rounding to a specified number of decimal places.

Use the toFixed() method, which returns a string representation of a number rounded to a specified number of decimal places.

Rounding a number to two decimal places is a common requirement in various programming tasks, especially when dealing with financial calculations or when you need to present data in a more readable format. Here are three examples demonstrating how to round a number to two decimal places in JavaScript:

Example 1: Using toFixed()

The toFixed() method formats a number using fixed-point notation, rounding the number to a specified number of decimal places.

const number = 2.34567;

const rounded = number.toFixed(2);

console.log(rounded); // Output: “2.35”

It’s important to note that toFixed() returns a string. If you need the result as a number, you can wrap the toFixed() call with parseFloat() or Number().

const roundedNumber = parseFloat(number.toFixed(2));

// Or

// const roundedNumber = Number(number.toFixed(2));

console.log(roundedNumber); // Output: 2.35

Example 2: Using Math.round()

If you want to round a number to two decimal places using mathematical rounding, you can use Math.round() in combination with a multiplier.

const number = 2.34567;

const rounded = Math.round(number * 100) / 100;

console.log(rounded); // Output: 2.35

This approach multiplies the number by 100 to shift the decimal two places to the right, rounds it, and then divides it by 100 to shift the decimal back to its original position.

Example 3: Using a Custom Rounding Function

For more complex rounding scenarios or for environments where you might not want to rely on toFixed() due to its return type, you can create a custom rounding function.

function roundToTwo(num) {

    return +(Math.round(num + “e+2”) + “e-2”);

}

const number = 2.34567;

const rounded = roundToTwo(number);

console.log(rounded); // Output: 2.35

This function uses the scientific notation (e-notation) to round the number. It adds “e+2” to the number to move the decimal point two places to the right before rounding, then subtracts “e-2” to move it back, effectively rounding the number to two decimal places. The unary plus (+) at the beginning converts the string result back into a number.

These examples provide various ways to round numbers to two decimal places in JavaScript, each with its own use case depending on the specific requirements of your project.

Checking if a Number is Finite and Not NaN

To verify that a value is a finite number and not NaN, you can use the isFinite() function, which returns false for Infinity, -Infinity, and NaN, and true for finite numbers.

const num = 1 / 0;

console.log(isFinite(num)); // false

The isFinite() function determines whether a number is a finite, legal number.

console.log(isFinite(2/0)); // false

console.log(isFinite(20/5)); // true

console.log(isFinite(NaN)); // false

Detecting a User’s Device Type

Detecting a user’s device type can be useful for responsive design. While JavaScript can offer some insights, it’s generally recommended to use CSS media queries or libraries for accuracy.

Detecting a user’s device type in JavaScript typically involves examining the navigator.userAgent string, which contains information about the browser and operating system. However, for more reliable results, especially for distinguishing between mobile and desktop devices, consider using a library or CSS-based approaches.

You can use the navigator.userAgent property, but for more accurate results, use a library like Modernizr.

if(/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {

 console.log(“Mobile device detected.”);

} else {

 console.log(“Desktop device detected.”);

}

Declaring an Immutable Variable with ES6

In ES6, the const keyword is used to declare variables that cannot be reassigned. This is ideal for values that should remain constant throughout the execution of the program.

The const keyword allows you to declare variables whose values cannot be reassigned.

In ES6 (ECMAScript 2015), the const keyword is used to declare variables that are not supposed to be reassigned. Declaring a variable with const makes it immutable in the sense that you cannot reassign it to a different value. However, it’s important to note that if the variable holds an object or an array, the contents of the object or array can still be modified unless you use other means to make them immutable. Here are three examples demonstrating the use of const to declare immutable variables in JavaScript:

const allows you to declare variables whose values cannot be reassigned, enhancing code stability and readability.

const PI = 3.14159;

// PI = 22/7; // TypeError: Assignment to constant variable.

console.log(PI);

Example 1: Declaring a Primitive Value

const pi = 3.14159;

console.log(pi); // Output: 3.14159

// Trying to reassign the value of pi will result in an error

// pi = 3.14; // TypeError: Assignment to constant variable.

This example shows the basic use of const for a primitive value. Since pi is a constant, trying to change its value after the initial declaration will result in a runtime error.

Example 2: Immutable Array (Sort of)

const colors = [‘red’, ‘green’, ‘blue’];

console.log(colors); // Output: [‘red’, ‘green’, ‘blue’]

// You can modify the contents of the array

colors.push(‘yellow’);

console.log(colors); // Output: [‘red’, ‘green’, ‘blue’, ‘yellow’]

// But you cannot reassign the array

// colors = [‘purple’, ‘orange’]; // TypeError: Assignment to constant variable.

In this example, colors are declared with const, making the variable itself immutable. However, the contents of the array can still be modified (e.g., items can be added, removed, or changed). The immutability enforced by const only applies to the binding between colors and its array, not the contents of the array.

Example 3: Immutable Object (Sort of)

const car = {

  make: ‘Toyota’,

  model: ‘Camry’

};

console.log(car); // Output: { make: ‘Toyota’, model: ‘Camry’ }

// You can modify the properties of the object

car.year = 2020;

console.log(car); // Output: { make: ‘Toyota’, model: ‘Camry’, year: 2020 }

// But you cannot reassign the object

// car = { make: ‘Honda’, model: ‘Accord’ }; // TypeError: Assignment to constant variable.

Similarly to arrays, declaring an object with const prevents reassigning the variable to a different object. However, the properties of the object can still be modified, added, or deleted. The immutability provided by const is limited to the binding of the variable to its initial value (in this case, the object itself).

For true immutability of objects or arrays (preventing any changes to the contents), you would need to use features such as Object.freeze() or libraries that provide immutable data structures.

Checking for a Property in an Object

To check if an object has a specific property, you can use the hasOwnProperty() method or the in operator.

These JavaScript fundamentals cover a broad range of topics, from data types and operators to ES6 features, providing a solid foundation for understanding and effectively working with JavaScript.

Use the hasOwnProperty() method or the in operator to check for the presence of a property in an object.

const obj = { key: ‘value’ };

console.log(obj.hasOwnProperty(‘key’)); // true

console.log(‘key’ in obj); // true

Each of these examples illustrates fundamental concepts in JavaScript, helping you understand how to work with data types, operators, variables, and more in your programming tasks.

Checking for the presence of a property in an object is a common task in JavaScript programming. There are several ways to perform this check, depending on the specific requirements of your task. Here are three examples demonstrating different methods to check for a property in an object:

Example 1: Using the in Operator

The in operator checks if a property exists in an object or its prototype chain.

const car = {

  make: ‘Toyota’,

  model: ‘Camry’

};

console.log(‘make’ in car); // Output: true

console.log(‘year’ in car); // Output: false

This example checks whether a car has a make property, which it does, so it returns true. It also checks for a year property, which does not exist in car, so it returns false.

Example 2: Using hasOwnProperty()

The hasOwnProperty() method checks if an object has a property as a direct property of that object and not inherited through the prototype chain.

const car = {

  make: ‘Toyota’,

  model: ‘Camry’

};

console.log(car.hasOwnProperty(‘make’)); // Output: true

console.log(car.hasOwnProperty(‘toString’)); // Output: false

In this example, car.hasOwnProperty(‘make’) returns true because make is a direct property of car. However, car.hasOwnProperty(‘toString’) returns false because toString is inherited from Object.prototype and is not a direct property of car.

Example 3: Using the Optional Chaining Operator (?.) and undefined Check

While not a direct check for the existence of a property, the optional chaining operator (?.) allows you to safely access nested object properties without having to check each level of nesting. You can combine this with an undefined check to infer the presence of a property.

const car = {

  specs: {

    engine: ‘V6’,

    horsepower: 268

  }

};

console.log(car.specs?.engine !== undefined); // Output: true

console.log(car.specs?.mileage !== undefined); // Output: false

This example checks for the engine property within specs, which exists, hence the output is true. It also checks for a mileage property within specs, which does not exist, so the output is false.

These examples showcase different approaches to determining whether an object contains a specific property, each useful in various scenarios depending on the requirements for checking property existence and inheritance.

Exercise Answers the following Questions

  • What is the significance of using the == operator for equality in JavaScript?
  • What does the typeof null expression return in JavaScript?
  • What is the result of trying to spread a Set into an array in JavaScript?
  • What is the main difference between == and === in JavaScript?
  • What is “hoisting” in JavaScript?
  • What does the void operator do in JavaScript?
  • How do you round a number to two decimal places in JavaScript?
  • How do you check if a number is finite and not NaN?
  • How can you detect a user’s device type in JavaScript?
  • In ES6, which keyword is used to declare a variable that cannot be reassigned?
  • How do you check if a JavaScript object obj has a property key?