From e8652aa7e5f6080efc402893845c8dbeb4f3fba8 Mon Sep 17 00:00:00 2001 From: allworkdone Date: Wed, 8 Oct 2025 00:13:46 +0530 Subject: [PATCH] Add code examples for JavaScript concepts 1-4 --- code-examples/README.md | 42 ++++ code-examples/call-stack-example.js | 57 +++++ .../implicit-explicit-typing-example.js | 210 ++++++++++++++++++ code-examples/primitive-types-example.js | 75 +++++++ .../value-reference-types-example.js | 138 ++++++++++++ 5 files changed, 522 insertions(+) create mode 100644 code-examples/README.md create mode 100644 code-examples/call-stack-example.js create mode 100644 code-examples/implicit-explicit-typing-example.js create mode 100644 code-examples/primitive-types-example.js create mode 100644 code-examples/value-reference-types-example.js diff --git a/code-examples/README.md b/code-examples/README.md new file mode 100644 index 00000000..da766c4e --- /dev/null +++ b/code-examples/README.md @@ -0,0 +1,42 @@ +# JavaScript Concept Code Examples + +This directory contains practical code examples for the 33 JavaScript concepts every developer should know. These examples are designed to help you understand and practice each concept with hands-on code. + +## Purpose + +The main repository provides comprehensive explanations of JavaScript concepts with articles and videos. This directory supplements that content by providing: + +- Practical code examples for each concept +- Interactive demonstrations of JavaScript behavior +- Clear explanations of complex concepts through code +- Reference implementations for learning + +## Available Examples + +- `call-stack-example.js` - Demonstrates how the JavaScript call stack works +- `primitive-types-example.js` - Shows examples of JavaScript's primitive data types +- `value-reference-types-example.js` - Illustrates the difference between value and reference types +- `implicit-explicit-typing-example.js` - Shows implicit and explicit type coercion in JavaScript + +## How to Use + +Run any example file with Node.js: + +```bash +node code-examples/call-stack-example.js +``` + +Each file is self-contained and includes detailed comments explaining the concepts being demonstrated. + +## Contributing + +Feel free to add more examples for the remaining concepts: + +1. Create a new file following the naming pattern: `{concept-name}-example.js` +2. Include detailed comments explaining the concept +3. Provide practical examples that demonstrate the concept in action +4. Test your example with Node.js before submitting a PR + +## License + +This project is licensed under the MIT License - see the LICENSE file for details. diff --git a/code-examples/call-stack-example.js b/code-examples/call-stack-example.js new file mode 100644 index 00000000..b15b3b96 --- /dev/null +++ b/code-examples/call-stack-example.js @@ -0,0 +1,57 @@ +/** + * Call Stack Example + * + * The call stack is a mechanism that the JavaScript interpreter uses to keep track of function execution within a program. + * It follows the Last In, First Out (LIFO) principle. + */ + +console.log('1. Script execution starts'); + +function firstFunction() { + console.log('3. Inside firstFunction'); + secondFunction(); + console.log('5. Back to firstFunction'); +} + +function secondFunction() { + console.log('4. Inside secondFunction'); +} + +// Execution starts here +firstFunction(); +console.log('6. Script execution ends'); + +/* + * Call Stack Visualization: + * + * At each step, the call stack looks like this: + * + * Step 1: console.log('1. Script execution starts') -> [] + * Step 2: firstFunction() -> [firstFunction] + * Step 3: console.log('3. Inside firstFunction') -> [firstFunction] + * Step 4: secondFunction() -> [firstFunction, secondFunction] + * Step 5: console.log('4. Inside secondFunction') -> [firstFunction, secondFunction] + * Step 6: secondFunction() returns -> [firstFunction] + * Step 7: console.log('5. Back to firstFunction') -> [firstFunction] + * Step 8: firstFunction() returns -> [] + * Step 9: console.log('6. Script execution ends') -> [] + */ + +// Example of call stack with recursion +function factorial(n) { + if (n <= 1) { + return 1; + } + return n * factorial(n - 1); // This creates multiple stack frames +} + +console.log('Factorial of 5:', factorial(5)); + +// Example of call stack overflow +function stackOverflow() { + console.log('This will cause a stack overflow'); + stackOverflow(); // Recursive call without termination condition +} + +// Uncomment the next line to see the stack overflow error +// stackOverflow(); diff --git a/code-examples/implicit-explicit-typing-example.js b/code-examples/implicit-explicit-typing-example.js new file mode 100644 index 00000000..9512d44b --- /dev/null +++ b/code-examples/implicit-explicit-typing-example.js @@ -0,0 +1,210 @@ +/** + * Implicit, Explicit, Nominal, Structuring and Duck Typing Example + * + * JavaScript is dynamically typed with various typing approaches: + * - Implicit Typing (Type Coercion): JavaScript automatically converts types + * - Explicit Typing: Manual conversion using functions like Number(), String(), Boolean() + * - Duck Typing: If it walks like a duck and quacks like a duck, it's a duck + */ + +// Implicit Typing (Type Coercion) examples +console.log("=== Implicit Typing (Type Coercion) ==="); + +// String concatenation with number +let result1 = "5" + 3; // "53" (number 3 is converted to string) +console.log('"5" + 3 =', result1, typeof result1); // "53" string + +// Arithmetic operation with string +let result2 = "10" - 5; // 5 (string "10" is converted to number) +console.log('"10" - 5 =', result2, typeof result2); // 5 number + +// Boolean conversion in conditionals +let result3 = "hello" && 42; // 42 (non-empty string is truthy) +console.log('"hello" && 42 =', result3); // 42 + +let result4 = "" && 42; // "" (empty string is falsy) +console.log('"" && 42 =', result4); // "" + +// Loose equality comparison +console.log('5 == "5":', 5 == "5"); // true (values are converted before comparison) +console.log('0 == false:', 0 == false); // true (both convert to 0) +console.log('null == undefined:', null == undefined); // true (special case) + +// Strict equality comparison +console.log('5 === "5":', 5 === "5"); // false (no type conversion) +console.log('0 === false:', 0 === false); // false (different types) + +// Explicit Typing examples +console.log("\n=== Explicit Typing ==="); + +// Converting to number +let strNum = "42"; +let num = Number(strNum); +console.log('Number("42"):', num, typeof num); // 42 number + +let parsedNum = parseInt("42.7"); +console.log('parseInt("42.7"):', parsedNum, typeof parsedNum); // 42 number + +let floatNum = parseFloat("42.7"); +console.log('parseFloat("42.7"):', floatNum, typeof floatNum); // 42.7 number + +// Converting to string +let numToConvert = 123; +let str = String(numToConvert); +console.log('String(123):', str, typeof str); // "123" string + +let boolToConvert = true; +let strBool = boolToConvert.toString(); +console.log('true.toString():', strBool, typeof strBool); // "true" string + +// Converting to boolean +let truthyValue = Boolean("hello"); +console.log('Boolean("hello"):', truthyValue, typeof truthyValue); // true boolean + +let falsyValue = Boolean(0); +console.log('Boolean(0):', falsyValue, typeof falsyValue); // false boolean + +// Duck Typing examples +console.log("\n=== Duck Typing ==="); + +// Objects with similar interfaces can be used interchangeably +function makeSound(animal) { + // Duck typing: if it has a makeSound method, treat it as an animal + if (typeof animal.makeSound === 'function') { + animal.makeSound(); + } else { + console.log("This animal doesn't know how to make a sound"); + } +} + +// Different objects with the same interface (duck typing) +let dog = { + name: "Rex", + makeSound: function() { + console.log("Woof!"); + } +}; + +let cat = { + name: "Whiskers", + makeSound: function() { + console.log("Meow!"); + } +}; + +let robot = { + name: "Robo", + makeSound: function() { + console.log("Beep!"); + } +}; + +// All can be used with the same function due to duck typing +makeSound(dog); // Woof! +makeSound(cat); // Meow! +makeSound(robot); // Beep! + +// Array-like object (duck typing) +let arrayLike = { + 0: 'a', + 1: 'b', + 2: 'c', + length: 3, + // Add a method that works with array-like objects + forEach: function(callback) { + for (let i = 0; i < this.length; i++) { + callback(this[i], i, this); + } + } +}; + +console.log("Array-like object:"); +arrayLike.forEach(item => console.log(item)); // 'a', 'b', 'c' + +// Structural Typing (objects are compatible if they share the same structure) +console.log("\n=== Structural Typing ==="); + +// Functions that expect objects with specific structure +function printName(person) { + console.log(`Name: ${person.name}`); +} + +// Objects with the same structure can be used interchangeably +let person1 = { + name: "Alice", + age: 30 +}; + +let person2 = { + name: "Bob", + occupation: "Developer" +}; + +let person3 = { + name: "Charlie", + height: 180 +}; + +// All of these work because they have the 'name' property +printName(person1); // Name: Alice +printName(person2); // Name: Bob +printName(person3); // Name: Charlie + +// Falsy and truthy values conversion +console.log("\n=== Falsy and Truthy Values ==="); + +let values = [0, -0, "", "hello", null, undefined, NaN, [], [1, 2], {}, {a: 1}, false, true]; + +values.forEach(value => { + console.log(`${JSON.stringify(value)} is ${Boolean(value) ? 'truthy' : 'falsy'} (type: ${typeof value})`); +}); + +// Complex coercion examples +console.log("\n=== Complex Coercion Examples ==="); + +// Comparing arrays +console.log('[1, 2, 3] == [1, 2, 3]:', [1, 2, 3] == [1, 2, 3]); // false (different objects) +console.log('[1, 2, 3] === [1, 2, 3]:', [1, 2, 3] === [1, 2, 3]); // false (different objects) + +// Comparing objects +let obj1 = { a: 1 }; +let obj2 = { a: 1 }; +console.log('obj1 == obj2:', obj1 == obj2); // false (different objects in memory) +console.log('obj1 === obj2:', obj1 === obj2); // false (different objects in memory) + +// Comparing same object reference +let obj3 = obj1; +console.log('obj1 == obj3:', obj1 == obj3); // true (same object in memory) +console.log('obj1 === obj3:', obj1 === obj3); // true (same object in memory) + +// Comparing with valueOf and toString +let objA = { + valueOf: function() { return 42; }, + toString: function() { return "forty-two"; } +}; + +let objB = { + valueOf: function() { return 42; }, + toString: function() { return "forty-two"; } +}; + +console.log('objA == 42:', objA == 42); // true (objA.valueOf() is called) +console.log('objA == "forty-two":', objA == "forty-two"); // true (objA.toString() is called in some contexts) + +// Demonstration of truthiness in conditional contexts +console.log("\n=== Truthiness in Conditionals ==="); + +let valueToCheck = "hello"; +if (valueToCheck) { + console.log("String 'hello' is truthy, so this runs"); +} + +let emptyString = ""; +if (!emptyString) { + console.log("Empty string is falsy, so this runs"); +} + +let zero = 0; +if (!zero) { + console.log("Zero is falsy, so this runs"); +} diff --git a/code-examples/primitive-types-example.js b/code-examples/primitive-types-example.js new file mode 100644 index 00000000..c45e4441 --- /dev/null +++ b/code-examples/primitive-types-example.js @@ -0,0 +1,75 @@ +/** + * Primitive Types Example + * + * JavaScript has six primitive data types: string, number, bigint, boolean, undefined, and symbol. + * There's also a special primitive type called null, which represents the intentional absence of any object value. + * These types are immutable, meaning their values cannot be altered. + */ + +// String primitive type +let name = "JavaScript"; +console.log("String:", name, "Type:", typeof name); + +// Number primitive type +let age = 25; +console.log("Number:", age, "Type:", typeof age); + +// BigInt primitive type +let bigNumber = 123456789012345678901234567890n; +console.log("BigInt:", bigNumber, "Type:", typeof bigNumber); + +// Boolean primitive type +let isLearning = true; +console.log("Boolean:", isLearning, "Type:", typeof isLearning); + +// Undefined primitive type +let notDefined; +console.log("Undefined:", notDefined, "Type:", typeof notDefined); + +// Symbol primitive type +let symbol1 = Symbol('description'); +let symbol2 = Symbol('description'); +console.log("Symbol 1:", symbol1, "Type:", typeof symbol1); +console.log("Symbol 2:", symbol2, "Are they equal?", symbol1 === symbol2); // false, symbols are always unique + +// Null primitive type +let emptyValue = null; +console.log("Null:", emptyValue, "Type:", typeof emptyValue); // Note: typeof null returns "object" (this is a historical bug in JavaScript) + +// Demonstrating immutability of primitives +let originalString = "Hello"; +let modifiedString = originalString.toUpperCase(); // Creates a new string + +console.log("Original:", originalString); // Still "Hello" +console.log("Modified:", modifiedString); // "HELLO" + +// Primitive values are copied by value, not by reference +let a = 10; +let b = a; // b gets a copy of the value +b = 20; // Changing b doesn't affect a + +console.log("a:", a); // Still 10 +console.log("b:", b); // 20 + +// Primitive types don't have properties or methods, but JavaScript temporarily wraps them with objects when needed +console.log("Length of string:", name.length); // JavaScript temporarily wraps the string primitive in a String object to access the length property + +// Example of how primitives are immutable +let greeting = "Hello"; +greeting[0] = "h"; // This operation has no effect on the original string +console.log("Greeting after trying to modify:", greeting); // Still "Hello", not "hello" + +// Demonstrating automatic wrapping with String object when calling methods +let upperGreeting = greeting.toUpperCase(); // JavaScript wraps greeting in String object to call toUpperCase() +console.log("Uppercase greeting:", upperGreeting); // "HELLO" + +// Different ways to create primitives vs objects +let primitiveStr = "Hello"; // String primitive +let objectStr = new String("Hello"); // String object + +console.log("Primitive:", primitiveStr, "Type:", typeof primitiveStr); // "Hello", "string" +console.log("Object:", objectStr, "Type:", typeof objectStr); // String object, "object" + +// Equality comparison +console.log("Are they equal?", primitiveStr == objectStr); // true (loose equality) +console.log("Are they strictly equal?", primitiveStr === objectStr); // false (strict equality) diff --git a/code-examples/value-reference-types-example.js b/code-examples/value-reference-types-example.js new file mode 100644 index 00000000..cc791074 --- /dev/null +++ b/code-examples/value-reference-types-example.js @@ -0,0 +1,138 @@ +/** + * Value Types and Reference Types Example + * + * Value types (primitives) are stored directly in the location that the variable accesses. + * These include types like number, string, boolean, undefined, bigint, symbol, and null. + * + * Reference types (objects) are stored in the heap. Variables assigned to reference types + * actually store references (pointers) to the objects, not the objects themselves. + */ + +// Value types (primitives) - stored by value +let num1 = 10; +let num2 = num1; // num2 gets a copy of the value + +console.log("Before modification:"); +console.log("num1:", num1); // 10 +console.log("num2:", num2); // 10 + +num2 = 20; // Changing num2 doesn't affect num1 + +console.log("After modifying num2:"); +console.log("num1:", num1); // Still 10 +console.log("num2:", num2); // Now 20 + +// String example +let str1 = "Hello"; +let str2 = str1; // str2 gets a copy of the value + +str2 = "World"; // Changing str2 doesn't affect str1 + +console.log("str1:", str1); // Still "Hello" +console.log("str2:", str2); // Now "World" + +// Boolean example +let bool1 = true; +let bool2 = bool1; // bool2 gets a copy of the value + +bool2 = false; // Changing bool2 doesn't affect bool1 + +console.log("bool1:", bool1); // Still true +console.log("bool2:", bool2); // Now false + +// Reference types (objects) - stored by reference +let obj1 = { name: "John", age: 30 }; +let obj2 = obj1; // obj2 gets a reference to the same object + +console.log("Before modification:"); +console.log("obj1:", obj1); // { name: "John", age: 30 } +console.log("obj2:", obj2); // { name: "John", age: 30 } + +obj2.age = 35; // Changing obj2 affects obj1 since they reference the same object + +console.log("After modifying obj2.age:"); +console.log("obj1:", obj1); // { name: "John", age: 35 } - obj1 is also changed! +console.log("obj2:", obj2); // { name: "John", age: 35 } + +// Array example (arrays are objects in JavaScript) +let arr1 = [1, 2, 3]; +let arr2 = arr1; // arr2 gets a reference to the same array + +console.log("Before modification:"); +console.log("arr1:", arr1); // [1, 2, 3] +console.log("arr2:", arr2); // [1, 2, 3] + +arr2.push(4); // Changing arr2 affects arr1 since they reference the same array + +console.log("After pushing to arr2:"); +console.log("arr1:", arr1); // [1, 2, 3, 4] - arr1 is also changed! +console.log("arr2:", arr2); // [1, 2, 3, 4] + +// Function example (functions are objects in JavaScript) +function originalFunction() { + return "Original function"; +} + +let func1 = originalFunction; +let func2 = func1; // func2 gets a reference to the same function + +console.log("func1 === func2:", func1 === func2); // true - they reference the same function + +// Demonstrating how to copy objects instead of referencing them +let originalObj = { name: "Alice", details: { age: 25, city: "New York" } }; + +// Shallow copy using Object.assign +let shallowCopy = Object.assign({}, originalObj); + +// Shallow copy using spread operator +let shallowCopy2 = { ...originalObj }; + +// Deep copy using JSON methods (has limitations with functions, dates, etc.) +let deepCopy = JSON.parse(JSON.stringify(originalObj)); + +console.log("Original object:", originalObj); +console.log("Shallow copy:", shallowCopy); +console.log("Deep copy:", deepCopy); + +// Modifying the original object +originalObj.name = "Bob"; +originalObj.details.age = 30; + +console.log("After modifying original object:"); +console.log("Original object:", originalObj); // { name: "Bob", details: { age: 30, city: "New York" } } +console.log("Shallow copy:", shallowCopy); // { name: "Alice", details: { age: 30, city: "New York" } } - nested object is still referenced +console.log("Deep copy:", deepCopy); // { name: "Alice", details: { age: 25, city: "New York" } } - completely independent + +// Demonstrating the difference with arrays +let originalArray = [1, [2, 3], 4]; +let arrayCopy = [...originalArray]; // Shallow copy + +originalArray[1][0] = 99; // Modifying nested array affects both arrays + +console.log("Original array:", originalArray); // [1, [999, 3], 4] +console.log("Array copy:", arrayCopy); // [1, [999, 3], 4] - nested array is still referenced + +// Pass by value vs pass by reference in functions +function changePrimitive(primitive) { + primitive = 100; + console.log("Inside function (primitive):", primitive); // 100 +} + +function changeObject(obj) { + obj.name = "Changed inside function"; + console.log("Inside function (object):", obj); // { name: "Changed inside function" } +} + +let primitiveValue = 50; +let objectValue = { name: "Original" }; + +console.log("Before function calls:"); +console.log("primitiveValue:", primitiveValue); // 50 +console.log("objectValue:", objectValue); // { name: "Original" } + +changePrimitive(primitiveValue); +changeObject(objectValue); + +console.log("After function calls:"); +console.log("primitiveValue:", primitiveValue); // Still 50 - unchanged +console.log("objectValue:", objectValue); // { name: "Changed inside function" } - changed!