├── 1.implement-curry.md ├── 11.what-is-Composition-create-a-pipe.md ├── 12.implement-Immutability-helper.md ├── 13.Implement-a-Queue-by-using-Stack.md ├── 14.Implement-a-general-memoization-function.md ├── 151.implement-Array-prototype-map.md ├── 16.create-an-Event-Emitter.md ├── 17.create-a-simple-store-for-DOM-element.md ├── 19.find-corresponding-node-in-two-identical-DOM-tree.md ├── 20.detect-data-type-in-JavaScript.md ├── 21.implement-JSON-stringify.md ├── 22.implement-JSON-parse.md ├── 26.implement-Object-assign.md ├── 28.implement-clearAllTimeout.md ├── 3.implement-Array.prototype.flat.md ├── 32.implement-Promise.all.md ├── 33.implement-Promise.allSettled.md ├── 34.implement-Promise.any.md ├── 35.implement-Promise.race.md ├── 37.implement-Binary-Search-unique.md ├── 4.implement-basic-throttle.md ├── 40.implement-Bubble-Sort.md ├── 41.implement-Merge-Sort.md ├── 42.implement-Insertion-Sort.md ├── 44.implement-Selection-Sort.md ├── 58.get-DOM-tree-height.md ├── 6.implement-basic-debounce.md ├── 63.create-cloneDeep.md ├── 64.auto-retry-Promise-on-rejection.md ├── 68.get-DOM-tags.md ├── 79.convert-snake_case-to-camelCase.md ├── 8.can-you-shuffle-an-array.md ├── 81.merge-sorted-arrays.md ├── Questions-Answers ├── 1.Promise-order.md ├── 10.equal.md ├── 11.Implicit-Coercion-II.md ├── 12.arguments.md ├── 13.Operator-precedence.md ├── 14.Addition-vs-Unary-Plus.md ├── 15.instanceOf.md ├── 16.parseInt.md ├── 17.reduce.md ├── 18.Promise-executor-II.md ├── 19.this.md ├── 2.Promise-executor.md ├── 20.name-for-Function-expression.md ├── 21.Array-I.md ├── 22.min-max.md ├── 23.Promise-all.md ├── 24.Equality-Sameness.md ├── 25.zero.md ├── 26.true-or-false.md ├── 27.Hoisting-I.md ├── 28.Hoisting-II.md ├── 29.Hoisting-III.md ├── 3.Promise-then-callbacks.md ├── 30.Equal-II.md ├── 31.Math.md ├── 32.Hoisting-IIII.md ├── 33.this-II.md ├── 34.precedence.md ├── 35.Implicit-Coercion-III.md ├── 36.Promise-prototype-finally.md ├── 37.push-unshift.md ├── 38.Hoisting-IV.md ├── 39.var.md ├── 4.Promise-then-callbacks-II.md ├── 40.RegExp-prototype-test.md ├── 41.this-III.md ├── 42.Hoisting-V.md ├── 43.JSON.stringify.md ├── 44.Function-call.md ├── 45.Hoisting-VI.md ├── 46.Implicit-Coercion-IV.md ├── 47.Promise-Order-II.md ├── 48.Prototype.md ├── 49.this-IV.md ├── 5.block-scope.md ├── 50.async-await.md ├── 51.method.md ├── 52.requestAnimationFrame.md ├── 53.Prototype-2.md ├── 54.setTimeout-0ms.md ├── 55.sparse-array.md ├── 56.to-primitive.md ├── 57.non-writable.md ├── 58.inherit-getter-setter.md ├── 59.override-setter.md ├── 6.Arrow-Function.md ├── 60.postMessage.md ├── 61.onClick.md ├── 62.MessageChannel.md ├── 64.reference-type.md ├── 65.Function-name.md ├── 67.if.md ├── 68.if-II.md ├── 69.undefined.md ├── 7.Increment-Operator.md ├── 70.function.md ├── 71.two-way-generator.md ├── 72.Array-length.md ├── 73.window-name.md ├── 74.Typed-Array-length.md ├── 75.meaningless-calculation.md ├── 76.const.md ├── 77.parseInt-2.md ├── 8.Implicit-Coercion-I.md └── 9.null-and-undefined.md ├── README.md ├── implement-String.prototype.slice.md ├── implement-memory-internal.md └── v8-performance-metrics ├── .gitignore ├── README.md ├── data └── performance_metrics.csv ├── index.html ├── package-lock.json ├── package.json ├── samples ├── complexCalculation.js ├── functionCalls.js └── simpleLoop.js ├── scripts └── benchmark.js └── server.js /1.implement-curry.md: -------------------------------------------------------------------------------- 1 | # 1. implement curry() 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/problem/implement-curry 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | Currying is a useful technique used in JavaScript applications. 12 | 13 | Please implement a curry() function, which accepts a function and return a curried one. 14 | 15 | Here is an example 16 | 17 | ```js 18 | # Example 1 19 | 20 | const join = (a, b, c) => { 21 | return `${a}_${b}_${c}`; 22 | }; 23 | 24 | const curriedJoin = curry(join); 25 | 26 | curriedJoin(1, 2, 3); // '1_2_3' 27 | 28 | curriedJoin(1)(2, 3); // '1_2_3' 29 | 30 | curriedJoin(1, 2)(3); // '1_2_3' 31 | 32 | 33 | 34 | # Example 2 35 | 36 | function sum(a, b, c) { 37 | return a + b + c; 38 | } 39 | 40 | let curriedSum = curry(sum); 41 | 42 | console.log(curriedSum(1)(2)(3)); // Outputs: 6 43 | console.log(curriedSum(1, 2)(3)); // Outputs: 6 44 | console.log(curriedSum(1, 2, 3)); // Outputs: 6 45 | 46 | ``` 47 | 48 | more to read 49 | 50 | https://javascript.info/currying-partials 51 | https://lodash.com/docs/4.17.15#curry 52 | 53 | # 54 | 55 | ### Solution 56 | 57 | ```js 58 | /** 59 | * @param { Function } func 60 | */ 61 | function curry(func) { 62 | // Return a wrapper function to make it curry-able. 63 | return function curried(...args) { 64 | // If passed arguments count is greater than or equal to original function 'func' 65 | // parameters count, directly call 'func' with passed arguments. 66 | if (args.length >= func.length) { 67 | return func.apply(this, args); 68 | } else { 69 | // Otherwise return another wrapper function to gather new argument 70 | // and pass it to `curried` function. This will continue until 71 | // arguments count >= parameters count. 72 | return function (...args2) { 73 | return curried.apply(this, args.concat(args2)); 74 | }; 75 | } 76 | }; 77 | } 78 | ``` 79 | 80 | # 81 | 82 | ### Explanation 83 | 84 | the function curry in the provided JavaScript code is a higher-order function that transforms a given function into a curried function. 85 | 86 | A curried function is a function that takes multiple arguments one at a time. Given a function with 3 parameters, the curried version will take one argument and return a function that takes the next argument, which returns a function that takes the third argument. The last function returns the result of applying the function to all of its arguments. 87 | 88 | Here's a step-by-step explanation of the code: 89 | 90 | 1. The curry function takes a function func as an argument. 91 | 2. It returns a new function curried that can be called with some arguments (...args). 92 | 3. When curried is invoked, it checks if the number of arguments provided is enough to invoke the original function func. This is done by comparing args.length with func.length, where func.length is the number of expected parameters of func. 93 | 4. If enough arguments are provided, it calls func with the provided arguments using func.apply(this, args). 94 | 5. If not enough arguments are provided, it returns a new function that expects the remaining arguments. This function, when called, will call curried with the old and new argument. 95 | 96 | Here's an example: 97 | 98 | ```js 99 | function sum(a, b, c) { 100 | return a + b + c; 101 | } 102 | 103 | let curriedSum = curry(sum); 104 | 105 | console.log(curriedSum(1)(2)(3)); // Outputs: 6 106 | ``` 107 | In this example, curriedSum is a curried version of sum. When we call curriedSum(1)(2)(3), it's equivalent to calling sum(1, 2, 3). Each call to curriedSum returns a new function expecting the next argument until all arguments are provided. 108 | 109 | 110 | let's break down how the curry function works with sum under the hood: 111 | 112 | ```js 113 | let curriedSum = curry(sum); 114 | ``` 115 | 116 | Here, curry is called with sum as an argument. curry returns a new function curried that can be called with some arguments. This returned function is stored in curriedSum. 117 | 118 | ```js 119 | console.log(curriedSum(1)(2)(3)) 120 | ``` 121 | 122 | Here's what happens step by step: 123 | 124 | - curriedSum(1) is called. Inside curried, args is an array with one element [1]. Since args.length (1) is less than func.length (3, because sum takes 3 arguments), curried returns a new function that takes the remaining arguments. 125 | 126 | - This returned function is immediately called with (2). Now args is [1, 2]. Again, args.length (2) is less than func.length (3), so curried returns another function. 127 | 128 | - This returned function is immediately called with (3). Now args is [1, 2, 3]. This time, args.length (3) is equal to func.length (3), so curried calls sum with these arguments using func.apply(this, args), which is equivalent to sum(1, 2, 3). This returns 6, which is then logged to the console. 129 | 130 | The other calls 131 | ```js 132 | console.log(curriedSum(1, 2)(3)) 133 | console.log(curriedSum(1, 2, 3)) 134 | ``` 135 | work in a similar way. The difference is that more arguments are provided at once, so the curried function returns a function that takes the remaining arguments fewer times before it has enough arguments to call sum. 136 | 137 | 138 | 139 | -------------------------------------------------------------------------------- /11.what-is-Composition-create-a-pipe.md: -------------------------------------------------------------------------------- 1 | # 11. what is Composition? create a pipe() 2 | 3 | The concept of "pipes" or "pipelining" in JavaScript is a functional programming concept where you pass the output of one function as the input to the next function, forming a pipeline of functions. Here are some real-world examples: 4 | 5 | 1. **Data Transformation**: Suppose you have an array of objects representing users, and you want to transform this data in several steps (e.g., filter out inactive users, sort by last name, and then extract just the email addresses). Each of these steps could be a function, and you could use `pipes` to create a single function that performs all these transformations in order. 6 | 7 | 2. **Middleware in Express.js**: In Express.js, middleware functions are used to handle requests and responses. These middleware functions are essentially a pipeline where each function receives a request and response object, does something with them (like checking if a user is authenticated), and then passes them on to the next middleware function. 8 | 9 | 3. **Redux Middleware**: In Redux, middleware is used to handle side effects and asynchronous actions. Middleware functions in Redux form a pipeline where each function can inspect and modify actions before they reach the reducer. 10 | 11 | 4. **Data Validation**: Suppose you have a form and you want to validate the input in several steps (e.g., trim whitespace, check if the input is empty, validate against a regex). Each of these steps could be a function, and you could use `pipes` to create a single validation function. 12 | 13 | 5. **Mathematical Computations**: If you have a sequence of mathematical operations that need to be performed in a specific order, you can create a function for each operation and use `pipes` to combine them into a single function. 14 | 15 | In all these examples, the `pipes` function allows you to create modular, reusable functions and combine them in flexible ways. 16 | 17 | ### Problem 18 | 19 | https://bigfrontend.dev/problem/what-is-composition-create-a-pipe 20 | 21 | # 22 | 23 | ### Problem Description 24 | 25 | what is Composition? It is actually not that difficult to understand, see [@dan_abramov 's explanation](https://whatthefuck.is/composition). 26 | 27 | Here you are asked to create a `pipe()` function, which chains multiple functions together to create a new function. 28 | 29 | Suppose we have some simple functions like this 30 | 31 | ```js 32 | const times = (y) => (x) => x * y; 33 | const plus = (y) => (x) => x + y; 34 | const subtract = (y) => (x) => x - y; 35 | const divide = (y) => (x) => x / y; 36 | ``` 37 | 38 | Your `pipe()` would be used to generate new functions 39 | 40 | ```js 41 | pipe([times(2), times(3)]); 42 | // x _ 2 _ 3 43 | 44 | pipe([times(2), plus(3), times(4)]); 45 | // (x _ 2 + 3) _ 4 46 | 47 | pipe([times(2), subtract(3), divide(4)]); 48 | // (x \* 2 - 3) / 4 49 | ``` 50 | 51 | **notes** 52 | 53 | 1. to make things simple, functions passed to `pipe()` will all accept 1 argument 54 | 55 | # 56 | 57 | ### Solution 58 | 59 | ```js 60 | /** 61 | * @param {Array<(arg: any) => any>} funcs 62 | * @return {(arg: any) => any} 63 | */ 64 | function pipe(funcs) { 65 | return function (n) { 66 | let result = n; 67 | for (let func of funcs) { 68 | result = func(result); 69 | } 70 | return result; 71 | }; 72 | } 73 | ``` 74 | 75 | # 76 | 77 | ### Usage 78 | 79 | ```js 80 | const addTwo = (n) => n + 2; 81 | const divideByFive = (n) => n / 5; 82 | const multiplyByTwo = (n) => n * 2; 83 | const multiplyByThree = (n) => n * 3; 84 | 85 | const addTwoMultiplyByThree = pipe([addTwo, multiplyByThree]); 86 | console.log(addTwoMultiplyByThree(5)); // 21 87 | 88 | const addTwoDivideByFive = pipe([addTwo, divideByFive]); 89 | console.log(addTwoDivideByFive(5)); // 1.4 90 | 91 | const addTwoMultiplyByThreeDivideByFive = pipe([ 92 | addTwo, 93 | multiplyByThree, 94 | divideByFive, 95 | ]); 96 | console.log(addTwoMultiplyByThreeDivideByFive(5)); // 6 97 | ``` -------------------------------------------------------------------------------- /13.Implement-a-Queue-by-using-Stack.md: -------------------------------------------------------------------------------- 1 | # 13. Implement a Queue by using Stack 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/problem/implement-a-queue-by-using-stack 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | In JavaScript, we could use array to work as both a Stack or a queue. 12 | 13 | ```js 14 | const arr = [1, 2, 3, 4]; 15 | 16 | arr.push(5); // now array is [1, 2, 3, 4, 5] 17 | arr.pop(); // 5, now the array is [1, 2, 3, 4] 18 | ``` 19 | 20 | Above code is a Stack, while below is a Queue 21 | 22 | ```js 23 | const arr = [1, 2, 3, 4]; 24 | 25 | arr.push(5); // now the array is [1, 2, 3, 4, 5] 26 | arr.shift(); // 1, now the array is [2, 3, 4, 5] 27 | ``` 28 | 29 | now suppose you have a stack, which has only follow interface: 30 | 31 | ```js 32 | class Stack { 33 | push(element) { 34 | /* add element to stack */ 35 | } 36 | peek() { 37 | /* get the top element */ 38 | } 39 | pop() { 40 | /* remove the top element */ 41 | } 42 | size() { 43 | /* count of elements */ 44 | } 45 | } 46 | ``` 47 | 48 | Could you implement a Queue by using only above Stack? A Queue must have following interface 49 | 50 | ```js 51 | class Queue { 52 | enqueue(element) { 53 | /* add element to queue, similar to Array.prototype.push */ 54 | } 55 | peek() { 56 | /* get the head element */ 57 | } 58 | dequeue() { 59 | /* remove the head element, similar to Array.prototype.pop */ 60 | } 61 | size() { 62 | /* count of elements */ 63 | } 64 | } 65 | ``` 66 | 67 | **notes** 68 | 69 | you can only use Stack as provided, Array should be avoided for the purpose of practicing. 70 | 71 | # 72 | 73 | ### Solution 1 (O(1) enqueue, O(n) dequeue and peek) 74 | 75 | ```js 76 | /* you can use this Class which is bundled together with your code 77 | 78 | class Stack { 79 | push(element) { // add element to stack } 80 | peek() { // get the top element } 81 | pop() { // remove the top element} 82 | size() { // count of element } 83 | } 84 | */ 85 | 86 | /* Array is disabled in your code */ 87 | 88 | // you need to complete the following Class 89 | class Queue { 90 | constructor() { 91 | this.content = new Stack(); 92 | } 93 | 94 | enqueue(element) { 95 | this.content.push(element); 96 | } 97 | peek() { 98 | const reversedQueue = this._reverse(this.content); 99 | return reversedQueue.peek(); 100 | } 101 | size() { 102 | return this.content.size(); 103 | } 104 | dequeue() { 105 | const reversedQueue = this._reverse(this.content); 106 | const poppedItem = reversedQueue.pop(); 107 | this.content = this._reverse(reversedQueue); 108 | return poppedItem; 109 | } 110 | _reverse(queue) { 111 | const reversedQueue = new Stack(); 112 | while (queue.size() > 0) { 113 | const lastItem = queue.pop(); 114 | reversedQueue.push(lastItem); 115 | } 116 | 117 | return reversedQueue; 118 | } 119 | } 120 | ``` 121 | 122 | # 123 | 124 | ### Solution 2 (O(n) enqueue, O(1) dequeue and peek) 125 | 126 | ```js 127 | /* you can use this Class which is bundled together with your code 128 | 129 | class Stack { 130 | push(element) { // add element to stack } 131 | peek() { // get the top element } 132 | pop() { // remove the top element} 133 | size() { // count of element } 134 | } 135 | */ 136 | 137 | /* Array is disabled in your code */ 138 | 139 | // you need to complete the following Class 140 | class Queue { 141 | constructor() { 142 | this.content = new Stack(); 143 | this.reversedContent = new Stack(); 144 | } 145 | 146 | enqueue(element) { 147 | while (this.content.size() > 0) { 148 | const poppedItem = this.content.pop(); 149 | this.reversedContent.push(poppedItem); 150 | } 151 | 152 | this.reversedContent.push(element); 153 | 154 | while (this.reversedContent.size() > 0) { 155 | const poppedItem = this.reversedContent.pop(); 156 | this.content.push(poppedItem); 157 | } 158 | } 159 | peek() { 160 | return this.content.peek(); 161 | } 162 | size() { 163 | return this.content.size(); 164 | } 165 | dequeue() { 166 | return this.content.pop(); 167 | } 168 | } 169 | ``` 170 | -------------------------------------------------------------------------------- /151.implement-Array-prototype-map.md: -------------------------------------------------------------------------------- 1 | # 151. implement Array.prototype.map() 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/problem/implement-Array-prototype-map 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | Please implement your own [Array.prototype.map()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map). 12 | 13 | ```js 14 | [1, 2, 3].myMap((num) => num * 2); 15 | // [2,4,6] 16 | ``` 17 | 18 | # 19 | 20 | ### Understanding the problem 21 | 22 | Write a prototype method for `Array` that returns a new array populated with the result of calling a provided function on every element in the calling array. 23 | 24 | # 25 | 26 | ### Approach 27 | 28 | Create an empty array to store the result. Iterate through every items in the calling array. At each item, call the provided callback and pass the item, its index and the calling array as arguments to the callback; store the return value in the result array. 29 | 30 | 🙋‍♀️🙋‍♂️ In the initial attempt, I didn't handle the following cases: 31 | 32 | 1. Besides the callback function, our function can also take in a second argument, the optional `thisArg`, when it is provided, the callback function should be executed with the provided context. 33 | 2. The callback might alter the length of the calling array, resulting in an infinite loop. 34 | 3. The calling array is a sparse array. A sparse array is an array in which indices are not contiguous. For instance, `[1, 3]` is a sparse array and the indices are `0, 2`, index `1` is not in the array. Our function should ignore indices that are not present in the calling array. 35 | 36 | ### Solution 37 | 38 | ```js 39 | Array.prototype.myMap = function (callback, thisArg) { 40 | // Store the length of the original array to avoid potential infinity loop 41 | // when the length of the calling array is altered on the fly. 42 | const length = this.length; 43 | // Initialize the resulting array to be the same size as the calling array. 44 | const result = new Array(length); 45 | 46 | for (let i = 0; i < length; i++) { 47 | // Ensure index is in the array. myMap should ignore 48 | // indices that are not in the array. 49 | if (i in this) { 50 | // Execute the callback with proper context and store its return value in the 51 | // result array. 52 | result[i] = callback.call(thisArg || this, this[i], i, this); 53 | } 54 | } 55 | 56 | return result; 57 | }; 58 | 59 | // Usage 60 | const arr = [1, 2, 3, 4, 5]; 61 | const mappedArr = arr.myMap((el) => el * 2); 62 | console.log(mappedArr); // [2, 4, 6, 8, 10] 63 | ``` 64 | 65 | # 66 | 67 | ### Explanation 68 | 69 | This JavaScript code is a custom implementation of the `Array.prototype.map()`function, which is a built-in method in JavaScript that creates a new array with the results of calling a provided function on every element in the calling array. 70 | 71 | Here's a breakdown of the code: 72 | 73 | 1. `Array.prototype.myMap = function (callback, thisArg) {...}` This line is extending the Array prototype with a new method called `myMap`. This method takes two arguments: a `callback` function and an optional `thisArg` object that will be used as `this` when executing the callback. 74 | 75 | 2. `const length = this.length;`: This line is storing the length of the array on which `myMap` was called. This is done to avoid potential infinite loops if the array's length is changed during the execution of `myMap`. 76 | 77 | 3. `const result = new Array(length);`: This line is initializing a new array with the same length as the original array. This will be the array that gets returned at the end. 78 | 79 | 4. The `for` loop: This loop iterates over each element in the original array. 80 | 81 | 5. `if (i in this) {...}`: This line checks if the current index exists in the original array. This is done because in JavaScript, arrays can have "holes" (i.e., indices that have never been assigned a value). 82 | 83 | 6. `result[i] = callback.call(thisArg || this, this[i], i, this);`: This line is calling the `callback` function with the current element, its index, and the original array as arguments. The result is stored in the corresponding index of the `result`array. 84 | 85 | - `result[i]`: This is the assignment statement that assigns the return value of the callback function to the `i`-th index of the `result` array. It ensures that the return value is stored at the correct position in the resulting array. 86 | 87 | - `callback`: This is the function that is passed as an argument to the `myMap` function. It is the function that will be executed on each element of the array. `(el) => el * 2` 88 | 89 | - `call()`: `call()` is a method available on JavaScript functions. It allows you to invoke a function and specify the value of `this` inside that function. In this case, `callback.call(...)` is used to execute the `callback` function. 90 | 91 | - `thisArg || this`: This is the value that will be used as the `this` value inside the `callback` function. The `thisArg` argument is optional, so if it is not provided, `this` (referring to the calling array) will be used as the `this` value. 92 | 93 | - `this[i]`: This is the current element of the array that is being processed by the `callback` function. It is passed as the first argument to the `callback` function. 94 | 95 | - `i`: This is the index of the current element in the array. It is passed as the second argument to the `callback` function. 96 | 97 | - `this`: This refers to the calling array itself. It is passed as the third ar gument to the `callback` function.`[ 1, 2, 3, 4, 5 ]` 98 | 99 | 7. `return result;`: This line returns the new array after the `for` loop has finished executing. `[ 2, 4, 6, 8, 10 ]` 100 | 101 | -------------------------------------------------------------------------------- /17.create-a-simple-store-for-DOM-element.md: -------------------------------------------------------------------------------- 1 | # 17. create a simple store for DOM element 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/problem/create-a-simple-store-for-DOM-node 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | We have `Map` in es6, so we could use any data as key, such as DOM element. 12 | 13 | ```js 14 | const map = new Map(); 15 | map.set(domNode, somedata); 16 | ``` 17 | 18 | What if we need to support old JavaScript env like es5, how would you create your own Node Store as above? 19 | 20 | You are asked to implement a Node Store, which supports DOM element as key. 21 | 22 | ```js 23 | class NodeStore { 24 | set(node, value) {} 25 | 26 | get(node) {} 27 | 28 | has(node) {} 29 | } 30 | ``` 31 | 32 | **note** 33 | 34 | `Map` is disabled when judging your code, it is against the goal of practicing. 35 | 36 | You can create a simple general `Map` polyfill. Or since you are asked to support specially for DOM element, what is special about DOM element? 37 | 38 | What is the Time / Space cost of your solution? 39 | 40 | # 41 | 42 | ### Solution 43 | 44 | ```js 45 | class NodeStore { 46 | constructor() { 47 | this.nodes = {}; 48 | } 49 | /** 50 | * @param {Node} node 51 | * @param {any} value 52 | */ 53 | set(node, value) { 54 | node.__id__ = Symbol(); 55 | this.nodes[node.__id__] = value; 56 | } 57 | /** 58 | * @param {Node} node 59 | * @return {any} 60 | */ 61 | get(node) { 62 | return this.nodes[node.__id__]; 63 | } 64 | 65 | /** 66 | * @param {Node} node 67 | * @return {Boolean} 68 | */ 69 | has(node) { 70 | // coerce to boolean value 71 | return !!this.nodes[node.__id__]; 72 | } 73 | } 74 | ``` 75 | 76 | 77 | # 78 | 79 | ### Usage 80 | 81 | ```js 82 | const store = new NodeStore(); 83 | 84 | const Node = function () {}; 85 | const node1 = new Node(); 86 | const node2 = new Node(); 87 | 88 | store.set(node1, "foo"); 89 | store.set(node2, "bar"); 90 | 91 | console.log(store.get(node1)); // 'foo' 92 | console.log(store.get(node2)); // 'bar' 93 | 94 | console.log(store.has(node1)); // true 95 | console.log(store.has(node2)); // true 96 | console.log(store.has(new Node())); // false 97 | ``` 98 | 99 | # 100 | 101 | ### Explanation 102 | 103 | Let's break down the `NodeStore` class and its usage: 104 | 105 | 1. **Class Definition**: The `NodeStore` class is defined with a constructor and three methods: `set`, `get`, and `has`. 106 | 107 | 2. **Constructor**: The constructor initializes an empty object `this.nodes` that will be used to store nodes. 108 | 109 | 3. **`set` Method**: This method takes a `node` and a `value` as parameters. It assigns a unique identifier to the `node` using `Symbol()` and then stores the `value` in `this.nodes` using the unique identifier as the key. 110 | 111 | 4. **`get` Method**: This method takes a `node` as a parameter and returns the value associated with the `node` from `this.nodes`. 112 | 113 | 5. **`has` Method**: This method takes a `node` as a parameter and checks if `this.nodes` has a value for the `node`. It returns a boolean value. 114 | 115 | 6. **Usage**: The usage example shows how to use the `NodeStore` class. It creates a new `NodeStore` instance and two new `Node` instances. It uses the `set` method to store values for the nodes, the `get` method to retrieve the stored values, and the `has` method to check if values are stored for the nodes. 116 | 117 | This `NodeStore` class provides a way to associate values with nodes in a way that doesn't mutate the nodes themselves (except for adding a unique identifier). This can be useful in situations where you need to store metadata about nodes, for example in a graph or tree data structure. 118 | 119 | -------------------------------------------------------------------------------- /19.find-corresponding-node-in-two-identical-DOM-tree.md: -------------------------------------------------------------------------------- 1 | # 19. find corresponding node in two identical DOM tree 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/problem/find-corresponding-node-in-two-identical-DOM-tree 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | Given two same DOM tree **A**, **B**, and an Element **a** in **A**, find the corresponding Element **b** in **B**. 12 | 13 | By **corresponding**, we mean **a** and **b** have the same relative position to their DOM tree root. 14 | 15 | _follow up_ 16 | 17 | This could a problem on general Tree structure with only `children`. 18 | 19 | Could you solve it recursively and iteratively? 20 | 21 | Could you solve this problem both with special DOM api for better performance? 22 | 23 | What are the time cost for each solution? 24 | 25 | # 26 | 27 | ### Recursive Solution 28 | 29 | ```js 30 | /** 31 | * @param {HTMLElement} rootA 32 | * @param {HTMLElement} rootB - rootA and rootB are clone of each other 33 | * @param {HTMLElement} nodeA 34 | */ 35 | const findCorrespondingNode = (rootA, rootB, targetNode) => { 36 | if (rootA === targetNode) { 37 | return rootB; 38 | } 39 | 40 | for (let i = 0; i < rootA.childNodes.length; i++) { 41 | const result = findCorrespondingNode( 42 | rootA.childNodes[i], 43 | rootB.childNodes[i], 44 | targetNode 45 | ); 46 | if (result) { 47 | return result; 48 | } 49 | } 50 | return null; 51 | }; 52 | ``` 53 | 54 | # 55 | 56 | ### Iterative Solution 57 | 58 | ```js 59 | /** 60 | * @param {HTMLElement} rootA 61 | * @param {HTMLElement} rootB - rootA and rootB are clone of each other 62 | * @param {HTMLElement} nodeA 63 | */ 64 | const findCorrespondingNode = (rootA, rootB, target) => { 65 | let stackA = [rootA]; 66 | let stackB = [rootB]; 67 | 68 | while (stackA.length > 0) { 69 | const nodeA = stackA.pop(); 70 | const nodeB = stackB.pop(); 71 | 72 | if (nodeA === target) { 73 | return nodeB; 74 | } 75 | 76 | stackA.push(...nodeA.childNodes); 77 | stackB.push(...nodeB.childNodes); 78 | } 79 | 80 | return; 81 | }; 82 | ``` 83 | 84 | # 85 | 86 | ### Solution with DOM API `parentNode` 87 | 88 | ```js 89 | /** 90 | * @param {HTMLElement} rootA 91 | * @param {HTMLElement} rootB - rootA and rootB are clone of each other 92 | * @param {HTMLElement} nodeA 93 | */ 94 | const findCorrespondingNode = (rootA, rootB, target) => { 95 | const path = []; 96 | let node = target; 97 | while (node !== rootA) { 98 | const parentNode = node.parentNode; 99 | const childNodes = Array.from(parentNode.childNodes); 100 | path.push(childNodes.indexOf(node)); 101 | node = parentNode; 102 | } 103 | 104 | return path.reduceRight((node, index) => node.childNodes[index], rootB); 105 | }; 106 | ``` 107 | # 108 | 109 | ### Usage 110 | 111 | ```js 112 | const rootA = { 113 | value: "A", 114 | childNodes: [ 115 | { 116 | value: "B", 117 | childNodes: [ 118 | { 119 | value: "C", 120 | childNodes: [], 121 | }, 122 | ], 123 | }, 124 | ], 125 | }; 126 | 127 | const rootB = { 128 | value: "A", 129 | childNodes: [ 130 | { 131 | value: "B", 132 | childNodes: [ 133 | { 134 | value: "C", 135 | childNodes: [], 136 | }, 137 | ], 138 | }, 139 | ], 140 | }; 141 | 142 | const targetNode = rootA.childNodes[0].childNodes[0]; 143 | 144 | console.log(findCorrespondingNode(rootA, rootB, targetNode)); 145 | ``` 146 | 147 | 148 | # 149 | 150 | ### Explanation 151 | 152 | Let's break down the `findCorrespondingNode` function and its usage: 153 | 154 | 1. **Function Definition**: The `findCorrespondingNode` function takes three arguments: `nodeA`, `nodeB`, and `targetNode`. It's designed to find a node in `nodeB` that corresponds to `targetNode` in `nodeA`, assuming `nodeA` and `nodeB` have the same structure. 155 | 156 | 2. **Base Cases**: If `nodeA` is the `targetNode`, it returns `nodeB`. If `nodeA` has no child nodes, it returns `null` because there's no corresponding node in `nodeB`. 157 | 158 | 3. **Recursion**: If `nodeA` is not the `targetNode` and it has child nodes, it recursively calls `findCorrespondingNode` for each pair of child nodes in `nodeA` and `nodeB`. If a recursive call returns a non-null result, it returns that result. 159 | 160 | 4. **Usage**: The usage example creates two identical tree structures `nodeA` and `nodeB`, each with a root node and a single child node that also has a single child node. It then calls `findCorrespondingNode` with `nodeA`, `nodeB`, and the first child node of `nodeA` as the `targetNode`. 161 | 162 | 5. **Output**: The output of the function call is the first child node of `nodeB`, which corresponds to the `targetNode` in `nodeA`. This is logged to the console. 163 | 164 | This `findCorrespondingNode` function can be used to find corresponding nodes in two tree structures that have the same structure. It uses a depth-first search strategy, checking the current node before checking the child nodes. 165 | 166 | # 167 | 168 | ### Reference 169 | 170 | [Problem Discuss](https://bigfrontend.dev/problem/find-corresponding-node-in-two-identical-DOM-tree/discuss) 171 | -------------------------------------------------------------------------------- /20.detect-data-type-in-JavaScript.md: -------------------------------------------------------------------------------- 1 | # 20. Detect data type in JavaScript 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/problem/detect-data-type-in-JavaScript 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | This is an easy problem. 12 | 13 | For [all the basic data types](https://javascript.info/types) in JavaScript, how could you write a function to detect the type of arbitrary data? 14 | 15 | Besides basic types, you need to also handle also commonly used complex data type including `Array`, `ArrayBuffer`, `Map`, `Set`, `Date` and `Function` 16 | 17 | The goal is not to list up all the data types but to show us how to solve the problem when we need to. 18 | 19 | The type should be lowercase 20 | 21 | ```js 22 | detectType(1); // 'number' 23 | detectType(new Map()); // 'map' 24 | detectType([]); // 'array' 25 | detectType(null); // 'null' 26 | 27 | // more in judging step 28 | ``` 29 | 30 | # 31 | 32 | ### Solution 33 | 34 | ```js 35 | const dataTypes = new Map([ 36 | [Number, 'number'], 37 | [String, 'string'], 38 | [Boolean, 'boolean'], 39 | [Array, 'array'], 40 | [ArrayBuffer, 'arraybuffer'], 41 | [Date, 'date'], 42 | [Map, 'map'], 43 | [Set, 'set'], 44 | ]); 45 | 46 | /** 47 | * @param {any} data 48 | * @return {string} 49 | */ 50 | function detectType(data) { 51 | if (typeof data !== 'object') { 52 | return typeof data; 53 | } 54 | 55 | if (data === null) { 56 | return 'null'; 57 | } 58 | 59 | for (const [type, name] of dataTypes.entries()) { 60 | if (data instanceof type) { 61 | return name; 62 | } 63 | } 64 | 65 | return 'object'; 66 | } 67 | ``` 68 | 69 | # 70 | 71 | ### Usage 72 | 73 | ```js 74 | console.log(detectType("hello")); // string 75 | console.log(detectType(1)); // number 76 | console.log(detectType(true)); // boolean 77 | console.log(detectType({})); // object 78 | console.log(detectType([])); // array 79 | console.log(detectType(null)); // null 80 | console.log(detectType(undefined)); // undefined 81 | console.log(detectType(() => {})); // function 82 | console.log(detectType(new Date())); // date 83 | console.log(detectType(new Map())); // map 84 | console.log(detectType(new Set())); // set 85 | ``` 86 | 87 | 88 | # 89 | 90 | ### Explanation 91 | 92 | Let's break down the `detectType` function and its usage: 93 | 94 | 1. **Map Definition**: The `dataTypes` map is defined with JavaScript built-in types as keys and their corresponding string names as values. 95 | 96 | 2. **Function Definition**: The `detectType` function is defined to take one argument, `data`, and return a string representing its type. 97 | 98 | 3. **Non-object Types**: If `data` is not an object (i.e., it's a number, string, boolean, undefined, or function), it returns the result of `typeof data`, which will be a string representing its type. 99 | 100 | 4. **Null Type**: If `data` is `null`, it returns the string "null". This is necessary because `typeof null` incorrectly returns "object" in JavaScript. 101 | 102 | 5. **Object Types**: If `data` is an object, it iterates over the entries of `dataTypes`. If `data` is an instance of the current type, it returns the corresponding name. This covers array, arraybuffer, date, map, and set types. 103 | 104 | 6. **Default Type**: If `data` is an object but not an instance of any type in `dataTypes`, it returns the string "object". This covers plain objects and any other kinds of objects not covered by `dataTypes`. 105 | 106 | 7. **Usage**: The function is then called with various types of data, and the results are logged to the console. The output matches the comments after each call, demonstrating that the function correctly identifies the type of each piece of data. 107 | 108 | This `detectType` function provides a more accurate way to determine the type of a piece of data in JavaScript than the built-in `typeof` operator, especially for different kinds of objects. -------------------------------------------------------------------------------- /28.implement-clearAllTimeout.md: -------------------------------------------------------------------------------- 1 | # 28. implement clearAllTimeout() 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/problem/implement-clearAllTimeout 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | `window.setTimeout()` could be used to schedule some task in the future. 12 | 13 | Could you implement `clearAllTimeout()` to clear all the timers? This might be useful when we want to clear things up before page transition. 14 | 15 | For example 16 | 17 | ```js 18 | setTimeout(func1, 10000); 19 | setTimeout(func2, 10000); 20 | setTimeout(func3, 10000); 21 | // all 3 functions are scheduled 10 seconds later 22 | 23 | clearAllTimeout(); 24 | // all scheduled tasks are cancelled. 25 | ``` 26 | 27 | **note** 28 | 29 | You need to keep the interface of `window.setTimeout` and `window.clearTimeout` the same, but you could replace them with new logic 30 | 31 | # 32 | 33 | ### Solution 34 | 35 | ```js 36 | const timerCache = new Set(); 37 | const originalSetTimeout = window.setTimeout; 38 | 39 | window.setTimeout = (cb, delay) => { 40 | const timer = originalSetTimeout(cb, delay); 41 | timerCache.add(timer); 42 | return timer; 43 | }; 44 | 45 | /** 46 | * cancel all timer from window.setTimeout 47 | */ 48 | function clearAllTimeout() { 49 | for (const timer of timerCache) { 50 | clearTimeout(timer); 51 | } 52 | } 53 | ``` 54 | -------------------------------------------------------------------------------- /3.implement-Array.prototype.flat.md: -------------------------------------------------------------------------------- 1 | # 3. implement Array.prototype.flat() 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/problem/implement-Array-prototype.flat 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | There is already `Array.prototype.flat()` in JavaScript (ES2019), which reduces the nesting of Array. 12 | 13 | Could you manage to implement your own one? 14 | 15 | Here is an example to illustrate 16 | 17 | ```js 18 | console.log(flat([1, [2, [3, [4, [5]]]]], 1)); // [1, 2, [3, [4, [5]]] 19 | console.log(flat([1, [2, [3, [4, [5]]]]], 2)); // [1, 2, 3, [4, [5]] 20 | console.log(flat([1, [2, [3, [4, [5]]]]], 3)); // [1, 2, 3, 4, [5] 21 | console.log(flat([1, [2, [3, [4, [5]]]]], 4)); // [1, 2, 3, 4, 5] 22 | console.log(flat([1, 2, 3, [4, 5, [6, 7, 8, [9, 10]]]], Infinity)) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 23 | ``` 24 | 25 | follow up 26 | 27 | Are you able to solve it both recursively and iteratively? 28 | 29 | # 30 | 31 | ### Recursive Solution 32 | 33 | ```js 34 | /** 35 | * @param { Array } arr 36 | * @param { number } depth 37 | */ 38 | const flat = (array, depth = 1) => { 39 | let flatArray = []; 40 | array.forEach((element) => { 41 | if (Array.isArray(element) && depth > 0) { 42 | flatArray.push(...flat(element, depth - 1)); 43 | } else { 44 | flatArray.push(element); 45 | } 46 | }); 47 | return flatArray; 48 | }; 49 | ``` 50 | 51 | # 52 | 53 | ### Recursive Solution with Reduce 54 | 55 | ```js 56 | /** 57 | * @param { Array } arr 58 | * @param { number } depth 59 | */ 60 | function flat(arr, depth = 1) { 61 | return arr.reduce( 62 | (acc, item) => 63 | Array.isArray(item) && depth > 0 64 | ? acc.concat(flat(item, depth - 1)) 65 | : [...acc, item], 66 | [] 67 | ); 68 | } 69 | ``` 70 | 71 | # 72 | 73 | ### Iterative Solution with Stack 74 | 75 | ```js 76 | /** 77 | * @param { Array } arr 78 | * @param { number } depth 79 | */ 80 | function flat(arr, depth = 1) { 81 | const flatArray = []; 82 | let stack = [...arr.map((item) => [item, depth])]; 83 | 84 | while (stack.length > 0) { 85 | const [item, depth] = stack.pop(); 86 | if (Array.isArray(item) && depth > 0) { 87 | stack.push(...item.map((el) => [el, depth - 1])); 88 | } else { 89 | flatArray.push(item); 90 | } 91 | } 92 | 93 | return flatArray.reverse(); 94 | } 95 | ``` 96 | 97 | # 98 | 99 | ### Reference 100 | 101 | [Problem Discuss](https://bigfrontend.dev/problem/implement-Array-prototype.flat/discuss) 102 | -------------------------------------------------------------------------------- /32.implement-Promise.all.md: -------------------------------------------------------------------------------- 1 | # 32. implement `Promise.all()` 2 | Promise.all is a method in JavaScript used to handle multiple promises concurrently. It takes an iterable (such as an array) of promises and returns a single promise. This returned promise resolves when all the promises in the iterable have resolved, or rejects if any of the promises in the iterable reject. 3 | 4 | ### Key Features of `Promise.all` 5 | 6 | 1. **Concurrent Execution**: 7 | 8 | * `Promise.all` runs multiple promises in parallel. 9 | * It waits for all the promises to settle (either resolved or rejected). 10 | 2. **Resolved Value**: 11 | 12 | * When all promises resolve, `Promise.all` resolves with an array of their results, maintaining the order of the original promises. 13 | * Example: `Promise.all([promise1, promise2]).then((values) => { console.log(values); });` 14 | * If `promise1` resolves to `value1` and `promise2` resolves to `value2`, the output will be `[value1, value2]`. 15 | 3. **Rejection Handling**: 16 | 17 | * If any promise in the iterable rejects, `Promise.all` immediately rejects with the reason of the first promise that rejected. 18 | * Example: `Promise.all([promise1, promise2]).catch((error) => { console.log(error); });` 19 | * If `promise1` rejects with an `error1`, `Promise.all` will reject with `error1`. 20 | 21 | 22 | ### Problem 23 | 24 | https://bigfrontend.dev/problem/implement-Promise-all 25 | 26 | # 27 | 28 | ### Problem Description 29 | 30 | > The Promise.all() method takes an iterable of promises as an input, and returns a single Promise that resolves to an array of the results of the input promises 31 | 32 | source - [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all) 33 | 34 | Could you write your own `all()` ? which should works the same as `Promise.all()` 35 | 36 | # 37 | 38 | ### Solution 39 | 40 | ```js 41 | /** 42 | * @param {Array} promises - notice input might have non-Promises 43 | * @return {Promise} 44 | */ 45 | function all(promises) { 46 | if (promises.length === 0) { 47 | return Promise.resolve([]); 48 | } 49 | 50 | const results = Array(promises.length); 51 | let count = 0; 52 | 53 | return new Promise((resolve, reject) => { 54 | promises.forEach((promise, i) => { 55 | if (!(promise instanceof Promise)) { 56 | promise = Promise.resolve(promise); 57 | } 58 | 59 | promise 60 | .then((res) => { 61 | results[i] = res; 62 | count++; 63 | 64 | if (count === promises.length) { 65 | resolve(results); 66 | } 67 | }) 68 | .catch((err) => { 69 | reject(err); 70 | }); 71 | }); 72 | }); 73 | } 74 | ``` 75 | 76 | ### Example Usage 77 | 78 | ```javascript 79 | const promise1 = Promise.resolve(3); 80 | const promise2 = new Promise((resolve, reject) => setTimeout(resolve, 100, 'foo')); 81 | const promise3 = fetch('https://api.example.com/data'); 82 | 83 | Promise.all([promise1, promise2, promise3]) 84 | .then((values) => { 85 | console.log(values); // [3, 'foo', Response object from fetch] 86 | }) 87 | .catch((error) => { 88 | console.error('One of the promises failed:', error); 89 | }); 90 | ``` 91 | 92 | ### Use Cases 93 | 94 | * **Aggregating Results**: When you need to wait for multiple asynchronous operations to complete before proceeding, such as fetching data from multiple sources. 95 | * **Parallel Execution**: When operations do not depend on each other and can be executed in parallel for efficiency. 96 | 97 | ### Important Notes 98 | 99 | * If the iterable passed to `Promise.all` is empty, it returns a promise that resolves to an empty array. 100 | * The order of results in the resolved array corresponds to the order of the promises passed to `Promise.all`. 101 | 102 | By leveraging `Promise.all`, developers can handle multiple asynchronous operations efficiently, ensuring that subsequent code execution waits until all specified promises have been settled. -------------------------------------------------------------------------------- /33.implement-Promise.allSettled.md: -------------------------------------------------------------------------------- 1 | # 33. implement `Promise.allSettled()` 2 | `Promise.allSettled` is a method in JavaScript that takes an iterable (such as an array) of promises and returns a single promise. This returned promise resolves when all the promises in the iterable have settled, meaning each promise has either resolved or rejected. It does not reject if any of the promises reject; instead, it provides the outcome of each promise. 3 | 4 | ### Key Features of `Promise.allSettled` 5 | 6 | 1. **Settling of All Promises**: 7 | 8 | * `Promise.allSettled` waits for all promises in the iterable to settle (either resolved or rejected). 9 | * It returns a promise that resolves with an array of objects describing the outcome of each promise. 10 | 2. **Resolved Value**: 11 | 12 | * The array contains objects with two properties: `status` and either `value` (if resolved) or `reason` (if rejected). 13 | * Example: 14 | 15 | ```javascript 16 | [ 17 | { status: "fulfilled", value: result1 }, 18 | { status: "rejected", reason: error } 19 | ] 20 | ``` 21 | 22 | 3. **No Immediate Rejection**: 23 | 24 | * Unlike `Promise.all`, it does not reject immediately if any promise rejects. Instead, it waits for all promises to settle and provides their outcomes. 25 | 26 | 27 | ### Problem 28 | 29 | https://bigfrontend.dev/problem/implement-Promise-allSettled 30 | 31 | # 32 | 33 | ### Problem Description 34 | 35 | > The Promise.allSettled() method returns a promise that resolves after all of the given promises have either fulfilled or rejected, with an array of objects that each describes the outcome of each promise. 36 | 37 | from [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled) 38 | 39 | Different from `Promise.all()` which rejects right away once an error occurs, `Promise.allSettled()` waits for all promises to settle. 40 | 41 | Now can you implement your own `allSettled()`? 42 | 43 | # 44 | 45 | ### Solution 46 | 47 | ```js 48 | /** 49 | * @param {Array} promises - notice that input might contains non-promises 50 | * @return {Promise>} 51 | */ 52 | function allSettled(promises) { 53 | if (promises.length === 0) { 54 | return Promise.resolve([]); 55 | } 56 | 57 | const results = Array(promises.length); 58 | let numOfSettledPromise = 0; 59 | 60 | return new Promise((resolve, reject) => { 61 | promises.forEach((promise, i) => { 62 | if (!(promise instanceof Promise)) { 63 | promise = Promise.resolve(promise); 64 | } 65 | 66 | promise.then( 67 | (value) => { 68 | results[i] = { 69 | status: 'fulfilled', 70 | value, 71 | }; 72 | 73 | numOfSettledPromise++; 74 | if (numOfSettledPromise === promises.length) { 75 | resolve(results); 76 | } 77 | }, 78 | (reason) => { 79 | results[i] = { 80 | status: 'rejected', 81 | reason, 82 | }; 83 | 84 | numOfSettledPromise++; 85 | if (numOfSettledPromise === promises.length) { 86 | resolve(results); 87 | } 88 | } 89 | ); 90 | }); 91 | }); 92 | } 93 | ``` 94 | 95 | 96 | ### Example Usage 97 | 98 | ```javascript 99 | const promise1 = new Promise((resolve, reject) => { 100 | setTimeout(() => { 101 | resolve("Promise 1 resolved"); 102 | }, 1000); 103 | }); 104 | 105 | const promise2 = new Promise((resolve, reject) => { 106 | setTimeout(() => { 107 | reject("Promise 2 rejected"); 108 | }, 2000); 109 | }); 110 | 111 | const promise3 = new Promise((resolve, reject) => { 112 | setTimeout(() => { 113 | resolve("Promise 3 resolved"); 114 | }, 3000); 115 | }); 116 | 117 | PromiseAllSettled([promise1, promise2, promise3]).then((results) => { 118 | console.log(results); 119 | }) 120 | 121 | // output 122 | [ 123 | { status: 'fulfilled', value: 'Promise 1 resolved' }, 124 | { status: 'rejected', reason: 'Promise 2 rejected' }, 125 | { status: 'fulfilled', value: 'Promise 3 resolved' } 126 | ] 127 | ``` 128 | 129 | ### Use Cases 130 | 131 | 1. **Handling Multiple Outcomes**: 132 | 133 | * When you need to perform multiple asynchronous operations and handle each result individually, regardless of whether they succeed or fail. 134 | 2. **Ensuring All Promises Settle**: 135 | 136 | * When you want to ensure that all promises have settled before proceeding with further logic, useful in scenarios like cleaning up resources or aggregating results. 137 | 138 | By using `Promise.allSettled`, developers can manage multiple asynchronous operations and handle each outcome in a comprehensive manner, ensuring that all results are processed, whether the promises are fulfilled or rejected. -------------------------------------------------------------------------------- /34.implement-Promise.any.md: -------------------------------------------------------------------------------- 1 | # 34. implement `Promise.any()` 2 | Promise.any is a method in JavaScript used to handle multiple promises concurrently, but with a different behavior compared to Promise.all. It returns a single promise that resolves as soon as any of the promises in the iterable fulfills, or rejects if all the promises reject. 3 | 4 | ### Key Features of `Promise.any` 5 | 6 | 1. **Concurrent Execution**: 7 | 8 | * `Promise.any` runs multiple promises in parallel. 9 | * It resolves as soon as one of the promises fulfills. 10 | 2. **Resolved Value**: 11 | 12 | * When the first promise fulfills, `Promise.any` resolves with the value of that promise. 13 | * Example: `Promise.any([promise1, promise2]).then((value) => { console.log(value); });` 14 | * If `promise1` fulfills with `value1`, the output will be `value1`. 15 | 3. **Rejection Handling**: 16 | 17 | * If all promises in the iterable reject, `Promise.any` rejects with an `AggregateError`, which is a new error type that groups multiple individual errors. 18 | * Example: `Promise.any([promise1, promise2]).catch((error) => { console.log(error); });` 19 | * If both `promise1` and `promise2` reject, `Promise.any` will reject with an `AggregateError` containing all the rejection reasons. 20 | 21 | 22 | ### Problem 23 | 24 | https://bigfrontend.dev/problem/implement-Promise-any 25 | 26 | # 27 | 28 | ### Problem Description 29 | 30 | > Promise.any() takes an iterable of Promise objects and, as soon as one of the promises in the iterable fulfils, returns a single promise that resolves with the value from that promise 31 | 32 | from [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/any) 33 | 34 | Can you implement a `any()` to work the same as `Promise.any()`? 35 | 36 | **note** 37 | 38 | `AggregateError` is not supported in Chrome yet, but you can still use it in your code since we will add the Class into your code. Do something like following: 39 | 40 | ```js 41 | new AggregateError('No Promise in Promise.any was resolved', errors); 42 | ``` 43 | 44 | # 45 | 46 | ### Solution 47 | 48 | ```js 49 | /** 50 | * @param {Array} promises 51 | * @return {Promise} 52 | */ 53 | function any(promises) { 54 | if (promises.length === 0) { 55 | return Promise.resolve(); 56 | } 57 | 58 | let isFulfilled = false; 59 | const errors = Array(promises.length); 60 | let numOfErrors = 0; 61 | 62 | return new Promise((resolve, reject) => { 63 | promises.forEach((promise, i) => { 64 | if (!(promise instanceof Promise)) { 65 | promise = Promise.resolve(promise); 66 | } 67 | 68 | promise.then( 69 | (value) => { 70 | if (isFulfilled) { 71 | return; 72 | } 73 | 74 | resolve(value); 75 | isFulfilled = true; 76 | }, 77 | (reason) => { 78 | errors[i] = reason; 79 | numOfErrors++; 80 | 81 | if (numOfErrors === promises.length) { 82 | reject( 83 | new AggregateError( 84 | 'No Promise in Promise.any was resolved', 85 | errors 86 | ) 87 | ); 88 | } 89 | } 90 | ); 91 | }); 92 | }); 93 | } 94 | ``` 95 | 96 | ### Example Usage 97 | 98 | ```javascript 99 | const promise1 = new Promise((resolve, reject) => setTimeout(reject, 100, 'Error1')); 100 | const promise2 = new Promise((resolve, reject) => setTimeout(resolve, 200, 'Success!')); 101 | const promise3 = new Promise((resolve, reject) => setTimeout(reject, 300, 'Error3')); 102 | 103 | Promise.any([promise1, promise2, promise3]) 104 | .then((value) => { 105 | console.log(value); // 'Success!' 106 | }) 107 | .catch((error) => { 108 | console.error('All promises were rejected:', error); 109 | }); 110 | ``` 111 | 112 | ### Use Cases 113 | 114 | * **Race to Success**: When you want to proceed as soon as any one of several asynchronous operations succeeds, such as loading the fastest resource among several mirrors. 115 | * **Fault Tolerance**: When you want to use the first available data and ignore the rest, improving fault tolerance in case some promises fail. 116 | 117 | ### Important Notes 118 | 119 | * If the iterable passed to `Promise.any` is empty, it returns a promise that will be rejected with an `AggregateError`. 120 | * If all promises reject, the rejection reason is an `AggregateError` containing an array of all rejection reasons. 121 | 122 | By using `Promise.any`, developers can efficiently handle scenarios where the first successful completion of any among several asynchronous tasks is sufficient, thereby enhancing performance and reliability in cases where multiple potential sources or paths are available. -------------------------------------------------------------------------------- /35.implement-Promise.race.md: -------------------------------------------------------------------------------- 1 | # 35. implement `Promise.race()` 2 | Promise.race is used to handle multiple promises concurrently, but it resolves or rejects as soon as the first promise settles (either resolves or rejects). It takes an iterable (such as an array) of promises and returns a single promise. This returned promise settles with the value or reason of the first promise that settles. 3 | 4 | ### Key Features of Promise.race 5 | 6 | 1. **First Settled Promise Wins**: 7 | 8 | * `Promise.race` returns a promise that resolves or rejects as soon as the first promise in the iterable settles. 9 | * This means the outcome (resolved value or rejection reason) is based on the earliest settling promise. 10 | 2. **Concurrent Execution**: 11 | 12 | * All promises in the iterable are executed concurrently. 13 | * The returned promise does not wait for the rest of the promises to settle once the first one settles. 14 | 3. **Flexible Handling**: 15 | 16 | * It can be used to manage both success and error scenarios quickly, depending on which promise settles first. 17 | 4. **Simplifying Timeouts**: 18 | 19 | * `Promise.race` is often used to implement timeouts for async operations by racing the main promise against a timeout promise that rejects after a certain period. 20 | 21 | ### Problem 22 | 23 | https://bigfrontend.dev/problem/implement-Promise-race 24 | 25 | # 26 | 27 | ### Problem Description 28 | 29 | This problem is similar to [31. implement async helper - race()](https://bigfrontend.dev/problem/implement-async-helper-race), but with Promise. 30 | 31 | > The Promise.race() method returns a promise that fulfills or rejects as soon as one of the promises in an iterable fulfills or rejects, with the value or reason from that promise. [source: MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/race) 32 | 33 | Can you create a `race()` which works the same as `Promise.race()`? 34 | 35 | # 36 | 37 | ### Solution 38 | 39 | ```js 40 | /** 41 | * @param {Array} promises 42 | * @return {Promise} 43 | */ 44 | function race(promises) { 45 | return new Promise((resolve, reject) => { 46 | promises.forEach((promise) => { 47 | promise.then(resolve).catch(reject); 48 | }); 49 | }); 50 | } 51 | ``` 52 | 53 | 54 | ### Use Cases 55 | 56 | 1. **Fastest Response Wins** 57 | When you want to proceed with the result of the fastest asynchronous operation, such as fetching data from multiple sources and using the quickest response. 58 | 59 | 2. **Timeouts** 60 | When you need to enforce a timeout on an asynchronous operation, combining the original promise with a timeout promise that rejects after a certain period. 61 | 62 | 63 | ### Example Usage 64 | 65 | ```javascript 66 | const promise1 = new Promise((resolve, reject) => setTimeout(resolve, 500, 'First!')); 67 | const promise2 = new Promise((resolve, reject) => setTimeout(resolve, 100, 'Second!')); 68 | const promise3 = new Promise((resolve, reject) => setTimeout(reject, 300, 'Error!')); 69 | 70 | Promise.race([promise1, promise2, promise3]) 71 | .then((value) => { 72 | console.log(value); // 'Second!' (the fastest one to settle) 73 | }) 74 | .catch((error) => { 75 | console.error('The first settled promise rejected:', error); 76 | }); 77 | ``` 78 | 79 | By leveraging `Promise.race`, developers can efficiently handle scenarios where the earliest completion (either resolve or reject) of any among several asynchronous tasks is needed, optimizing performance and responsiveness in cases where speed is crucial. -------------------------------------------------------------------------------- /40.implement-Bubble-Sort.md: -------------------------------------------------------------------------------- 1 | # 40. implement Bubble Sort 2 | Bubble Sort is a simple comparison-based sorting algorithm. It repeatedly steps through the list, compares adjacent elements, and swaps them if they are in the wrong order. This process continues until the list is sorted. 3 | 4 | 5 | ### Problem 6 | 7 | https://bigfrontend.dev/problem/implement-Bubble-Sort 8 | 9 | # 10 | 11 | ### Problem Description 12 | 13 | Even for Front-End Engineer, it is a must to understand how basic sorting algorithms work. 14 | 15 | Now you are asked to implement [Bubble Sort](https://en.wikipedia.org/wiki/Bubble_sort), which sorts an integer array in ascending order. 16 | 17 | Do it **in-place**, no need to return anything. 18 | 19 | **Follow-up** 20 | 21 | What is time cost for average / worst case ? Is it stable? 22 | 23 | # 24 | 25 | ### Solution 26 | 27 | ```js 28 | /** 29 | * @param {number[]} arr 30 | */ 31 | function bubbleSort(arr) { 32 | let hasNoSwaps; 33 | for (let i = arr.length; i >= 0; i--) { 34 | hasNoSwaps = true; 35 | for (let j = 0; j < i - 1; j++) { 36 | if (arr[j] > arr[j + 1]) { 37 | [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]; 38 | hasNoSwaps = false; 39 | } 40 | } 41 | if (hasNoSwaps) { 42 | break; 43 | } 44 | } 45 | } 46 | 47 | // Usage 48 | console.log(bubbleSort([37, 45, 29, 8, 12, 88, -3])); // [-3, 8, 12, 29, 37, 45, 88] 49 | console.log(bubbleSort([8, 1, 2, 3, 4, 5, 6, 7])); // [1, 2, 3, 4, 5, 6, 7, 8] 50 | console.log(bubbleSort([1, 2, 3, 4, 5, 6, 7, 8])); // [1, 2, 3, 4, 5, 6, 7, 8] 51 | ``` 52 | 53 | #### Use Cases: 54 | 55 | 1. **Small Data Sets**: It can be useful for small datasets or when the simplicity of the implementation is more critical than performance. 56 | 2. **Nearly Sorted Data**: If the data is nearly sorted or has only a few elements out of order, Bubble Sort can be efficient. 57 | -------------------------------------------------------------------------------- /41.implement-Merge-Sort.md: -------------------------------------------------------------------------------- 1 | # 41. implement Merge Sort 2 | Merge Sort is a divide-and-conquer algorithm that splits the input list into smaller sublists, sorts those sublists, and then merges them back together to produce a sorted list. 3 | 4 | 5 | ### Problem 6 | 7 | https://bigfrontend.dev/problem/implement-Merge-Sort 8 | 9 | # 10 | 11 | ### Problem Description 12 | 13 | Even for Front-End Engineer, it is a must to understand how basic sorting algorithms work. 14 | 15 | Now you are asked to implement [Merge Sort](https://en.wikipedia.org/wiki/Merge_sort), which sorts an integer array in ascending order. 16 | 17 | Do it **in-place**, no need to return anything. 18 | 19 | **Follow-up** 20 | 21 | What is time cost for average / worst case ? Is it stable? 22 | 23 | # 24 | 25 | ### Solution 26 | 27 | ```js 28 | /** 29 | * @param {number[]} arr 30 | */ 31 | function mergeSort(arr) { 32 | if (arr.length <= 1) return arr; 33 | const middle = Math.floor(arr.length / 2); 34 | const left = mergeSort(arr.slice(0, middle)); 35 | const right = mergeSort(arr.slice(middle)); 36 | return merge(left, right); 37 | } 38 | 39 | function merge(left, right) { 40 | let result = []; 41 | let leftIndex = 0; 42 | let rightIndex = 0; 43 | 44 | while (leftIndex < left.length && rightIndex < right.length) { 45 | if (left[leftIndex] < right[rightIndex]) { 46 | result.push(left[leftIndex]); 47 | leftIndex++; 48 | } else { 49 | result.push(right[rightIndex]); 50 | rightIndex++; 51 | } 52 | } 53 | 54 | return result.concat(left.slice(leftIndex)).concat(right.slice(rightIndex)); 55 | } 56 | 57 | // Usage 58 | console.log(mergeSort([1, 5, 3, 8, 2, 6, 4, 7])); // [1, 2, 3, 4, 5, 6, 7, 8] 59 | console.log(mergeSort([1, 5, 3, 8, 2, 6, 4])); // [1, 2, 3, 4, 5, 6, 8] 60 | console.log(mergeSort([1, 5, 3, 8, 2, 6])); // [1, 2, 3, 5, 6, 8] 61 | console.log(mergeSort([1, 5, 3, 8, 2])); // [1, 2, 3, 5, 8] 62 | console.log(mergeSort([1, 5, 3, 8])); // [1, 3, 5, 8] 63 | console.log(mergeSort([1, 5, 3])); // [1, 3, 5] 64 | console.log(mergeSort([1, 5])); // [1, 5] 65 | console.log(mergeSort([1])); // [1] 66 | console.log(mergeSort([])); // [] 67 | ``` 68 | 69 | #### Use Cases: 70 | 71 | 1. **Large Data Sets**: Efficient for large datasets due to its O(nlog⁡n)O(n \log n)O(nlogn) complexity. 72 | 2. **Linked Lists**: Works well with linked lists where random access is not required. 73 | 3. **External Sorting**: Useful for sorting large amounts of data that do not fit into memory. 74 | -------------------------------------------------------------------------------- /42.implement-Insertion-Sort.md: -------------------------------------------------------------------------------- 1 | # 42. implement Insertion Sort 2 | Insertion Sort is a simple and intuitive comparison-based sorting algorithm. It builds the final sorted array one element at a time by repeatedly picking the next element and inserting it into its correct position among the previously sorted elements. 3 | 4 | ### Problem 5 | 6 | https://bigfrontend.dev/problem/implement-Insertion-Sort 7 | 8 | # 9 | 10 | ### Problem Description 11 | 12 | Even for Front-End Engineer, it is a must to understand how basic sorting algorithms work. 13 | 14 | Now you are asked to implement [Insertion Sort](https://en.wikipedia.org/wiki/Insertion_sort), which sorts an integer array in ascending order. 15 | 16 | Do it **in-place**, no need to return anything. 17 | 18 | **Follow-up** 19 | 20 | What is time cost for average / worst case ? Is it stable? 21 | 22 | # 23 | 24 | ### Solution 25 | 26 | ```js 27 | /** 28 | * @param {number[]} arr 29 | */ 30 | function insertionSort(arr) { 31 | for (let i = 1; i < arr.length; i++) { 32 | let currentVal = arr[i]; 33 | let j = i - 1; 34 | while (j >= 0 && currentVal < arr[j]) { 35 | arr[j + 1] = arr[j]; 36 | j--; 37 | } 38 | arr[j + 1] = currentVal; 39 | } 40 | } 41 | ``` 42 | 43 | #### Use Cases: 44 | 45 | 1. **Small Data Sets**: Efficient for small datasets due to its simplicity and low overhead. 46 | 2. **Nearly Sorted Data**: Performs very well on nearly sorted data or when the data is already sorted. 47 | 3. **Online Sorting**: Suitable for scenarios where the list is being received in a streaming fashion, as it can sort the list as elements arrive. -------------------------------------------------------------------------------- /44.implement-Selection-Sort.md: -------------------------------------------------------------------------------- 1 | # 44. implement Selection Sort 2 | Selection Sort is a simple comparison-based sorting algorithm. It divides the input list into two parts: a sorted sublist of items which is built up from left to right at the front (left) of the list, and a sublist of the remaining unsorted items that occupy the rest of the list. The algorithm repeatedly selects the smallest (or largest, depending on sorting order) element from the unsorted sublist, swaps it with the leftmost unsorted element, and moves the sublist boundaries one element to the right. 3 | 4 | 5 | ### Problem 6 | 7 | https://bigfrontend.dev/problem/implement-Selection-Sort 8 | 9 | # 10 | 11 | ### Problem Description 12 | 13 | Even for Front-End Engineer, it is a must to understand how basic sorting algorithms work. 14 | 15 | Now you are asked to implement [Selection sort](https://en.wikipedia.org/wiki/Selection_sort), which sorts an integer array in ascending order. 16 | 17 | Do it **in-place**, no need to return anything. 18 | 19 | **Follow-up** 20 | 21 | What is time cost for average / worst case ? Is it stable? 22 | 23 | # 24 | 25 | ### Solution 26 | 27 | ```js 28 | /** 29 | * @param {number[]} arr 30 | */ 31 | function selectionSort(arr) { 32 | for (let i = 0; i < arr.length; i++) { 33 | let smallestIndex = i; 34 | for (let j = i + 1; j < arr.length; j++) { 35 | if (arr[j] < arr[smallestIndex]) { 36 | smallestIndex = j; 37 | } 38 | } 39 | if (smallestIndex !== i) { 40 | [arr[smallestIndex], arr[i]] = [arr[i], arr[smallestIndex]]; 41 | } 42 | } 43 | } 44 | ``` 45 | 46 | #### Use Cases: 47 | 48 | 1. **Small Data Sets**: Suitable for small datasets where the overhead of more complex algorithms is not justified. 49 | 2. **Memory-Constrained Environments**: Due to its in-place nature, it is useful when memory space is at a premium. 50 | 3. **Simple Requirements**: When the simplicity of implementation is more important than performance. -------------------------------------------------------------------------------- /58.get-DOM-tree-height.md: -------------------------------------------------------------------------------- 1 | # 58. get DOM tree height 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/problem/get-DOM-tree-height 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | Height of a tree is the maximum depth from root node. Empty root node have a height of 0. 12 | 13 | If given DOM tree, can you create a function to get the height of it? 14 | 15 | For the DOM tree below, we have a height of 4. 16 | 17 | ```html 18 |
19 |
20 |

21 | 22 |

23 |
24 |

25 | World! 26 |

27 |
28 | ``` 29 | 30 | Can you solve this both recursively and iteratively? 31 | 32 | # 33 | 34 | ### Recursive Solution with DFS 35 | 36 | ```js 37 | /** 38 | * @param {HTMLElement | null} tree 39 | * @return {number} 40 | */ 41 | function getHeight(tree) { 42 | if (tree === null) { 43 | return 0; 44 | } 45 | return 1 + Math.max(getTreeHeight(tree.left), getTreeHeight(tree.right)); 46 | } 47 | ``` 48 | 49 | # 50 | 51 | ### Iterative Solution using Stack 52 | 53 | ```js 54 | /** 55 | * @param {HTMLElement | null} tree 56 | * @return {number} 57 | */ 58 | function getHeight(tree) { 59 | if (tree === null) { 60 | return 0; 61 | } 62 | 63 | let maxHeight = 0; 64 | const stack = [[tree, 1]]; 65 | 66 | while (stack.length > 0) { 67 | const [el, height] = stack.pop(); 68 | maxHeight = Math.max(height, maxHeight); 69 | 70 | for (const child of el.children) { 71 | stack.push([child, height + 1]); 72 | } 73 | } 74 | 75 | return maxHeight; 76 | } 77 | ``` 78 | 79 | # 80 | 81 | ### Iterative Solution with BFS 82 | 83 | ```js 84 | /** 85 | * @param {HTMLElement | null} tree 86 | * @return {number} 87 | */ 88 | function getHeight(tree) { 89 | if (tree === null) { 90 | return 0; 91 | } 92 | 93 | let maxHeight = 0; 94 | const queue = [[tree, 1]]; 95 | 96 | while (queue.length > 0) { 97 | const [el, height] = queue.shift(); 98 | maxHeight = Math.max(height, maxHeight); 99 | 100 | for (const child of el.children) { 101 | queue.push([child, height + 1]); 102 | } 103 | } 104 | 105 | return maxHeight; 106 | } 107 | ``` 108 | -------------------------------------------------------------------------------- /64.auto-retry-Promise-on-rejection.md: -------------------------------------------------------------------------------- 1 | # 64. auto-retry Promise on rejection 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/problem/retry-promise-on-rejection 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | For a web application, fetching API data is a common task. 12 | 13 | But the API calls might fail because of Network problems. Usually we could show a screen for Network Error and ask users to retry. 14 | 15 | One approach to handle this is **auto retry when network error occurs**. 16 | 17 | You are asked to create a `fetchWithAutoRetry(fetcher, count)`, which automatically fetch again when error happens, until the maximum count is met. 18 | 19 | For the problem here, there is no need to detect network error, you can just retry on all promise rejections. 20 | 21 | # 22 | 23 | ### Understanding the problem 24 | 25 | Write a function that retries fetch upon failure up to N times. The function takes two inputs, a callback function that fetches API data and returns a promise, and an integer representing maximum retry count. 26 | 27 | # 28 | 29 | ### Approach 30 | 31 | Fetching data is always asynchronous, so the function needs to return a promise. Within the promise, we can use a `try...catch` block to implement the auto retry. Call the `fetcher` function in the `try` block and then `resolve` the result. If an error is thrown in the `try` block, the statement in the `catch` block will be executed. So in the `catch` block, we can try to fetch the data again if the maximum count is not reached. We can use the variable `maximumRetryCount` to keep track of how many tries we have left. Every time we retry, we decrease the `maximumRetryCount` by 1. If `maximumRetryCount` is equal to 0, the returned promise gets rejected with the thrown error as its value. 32 | 33 | ### Solution 34 | 35 | ```js 36 | /** 37 | * @param {() => Promise} fetcher 38 | * @param {number} maximumRetryCount 39 | * @return {Promise} 40 | */ 41 | function fetchWithAutoRetry(fetcher, maximumRetryCount) { 42 | return new Promise((resolve, reject) => { 43 | const retry = async (retriesLeft) => { 44 | try { 45 | const data = await fetcher(); 46 | resolve(data); 47 | } catch (err) { 48 | if (retriesLeft === 0) { 49 | reject(err); 50 | return; 51 | } 52 | retry(retriesLeft - 1); 53 | } 54 | }; 55 | retry(maximumRetryCount); 56 | }); 57 | } 58 | ``` 59 | 60 | # 61 | 62 | ### Usage 63 | ```js 64 | const fetcher = () => { 65 | return new Promise((resolve, reject) => { 66 | setTimeout(() => { 67 | fetch("https://jsonplaceholder.typicode.com/posts") 68 | .then((response) => response.json()) 69 | .then((data) => resolve(data)) 70 | .catch((err) => reject(err)); 71 | }, 1000); 72 | }); 73 | }; 74 | 75 | console.log("Start"); 76 | fetchWithAutoRetry(fetcher, 5) 77 | .then((data) => console.log(data)) 78 | .catch((err) => console.log(err)); 79 | console.log("End"); 80 | 81 | ``` 82 | -------------------------------------------------------------------------------- /68.get-DOM-tags.md: -------------------------------------------------------------------------------- 1 | # 68. get DOM tags 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/problem/get-DOM-tags 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | Given a DOM tree, please return all the tag names it has. 12 | 13 | Your function should return a unique array of tags names in lowercase, order doesn't matter. 14 | 15 | # 16 | 17 | ### Understanding the problem 18 | 19 | We are given a DOM tree and we are asked to write a function that returns all the unique **tag names** in it in an array. The tag names should be returned in lowercase, and we can return them in any order. 20 | 21 | # 22 | 23 | ### Approach 24 | 25 | We could traverse the DOM tree using either DFS or BFS to get all of the tag names. To store only the unique tag names, we could make use of a `Set`, since a `Set` cannot have duplicate values. 26 | 27 | Because only an `Element` has the tag, as we traverse the DOM tree, we need to use `Element.children` rather than `Node.childNodes` to get only the child `Element`s. 28 | 29 | ### Implementation 30 | 31 | Recursive DFS: 32 | 33 | ```js 34 | /** 35 | * @param {HTMLElement} tree 36 | * @return {string[]} 37 | */ 38 | function getTags(tree) { 39 | const tagNames = new Set(); 40 | 41 | dfs(tree, tagNames); 42 | return [...tagNames]; 43 | } 44 | 45 | function dfs(el, tagNames) { 46 | const tagName = el.tagName.toLowerCase(); 47 | tagNames.add(tagName); 48 | 49 | for (const child of el.children) { 50 | dfs(child, tagNames); 51 | } 52 | } 53 | ``` 54 | 55 | Iterative DFS: 56 | 57 | ```js 58 | /** 59 | * @param {HTMLElement} tree 60 | * @return {string[]} 61 | */ 62 | function getTags(tree) { 63 | const tagNames = new Set(); 64 | const stack = [tree]; 65 | 66 | while (stack.length > 0) { 67 | const el = stack.pop(); 68 | const tagName = el.tagName.toLowerCase(); 69 | tagNames.add(tagName); 70 | 71 | stack.push(...el.children); 72 | } 73 | 74 | return [...tagNames]; 75 | } 76 | ``` 77 | 78 | Iterative BFS: 79 | 80 | ```js 81 | /** 82 | * @param {HTMLElement} tree 83 | * @return {string[]} 84 | */ 85 | function getTags(tree) { 86 | const tagNames = new Set(); 87 | // Assume we have a Queue data structure implemented. 88 | const queue = [tree]; 89 | 90 | while (queue.length > 0) { 91 | const el = queue.shift(); 92 | const tagName = el.tagName.toLowerCase(); 93 | tagNames.add(tagName); 94 | 95 | queue.push(...el.children); 96 | } 97 | 98 | return [...tagNames]; 99 | } 100 | ``` 101 | 102 | # 103 | 104 | ### Usage 105 | 106 | ```js 107 | const DOM = { 108 | tagName: "div", 109 | children: [ 110 | { 111 | tagName: "h1", 112 | children: [ 113 | { 114 | tagName: "span", 115 | children: [ 116 | { 117 | tagName: "a", 118 | children: [ 119 | { 120 | tagName: "span", 121 | children: [], 122 | }, 123 | ], 124 | }, 125 | ], 126 | }, 127 | ], 128 | }, 129 | 130 | { 131 | tagName: "p", 132 | children: [ 133 | { 134 | tagName: "span", 135 | children: [], 136 | }, 137 | { 138 | tagName: "a", 139 | children: [ 140 | { 141 | tagName: "span", 142 | children: [], 143 | }, 144 | ], 145 | }, 146 | ], 147 | }, 148 | ], 149 | }; 150 | 151 | console.log(getTags(DOM)); // ["div", "h1", "span", "a", "p"] 152 | ``` 153 | -------------------------------------------------------------------------------- /79.convert-snake_case-to-camelCase.md: -------------------------------------------------------------------------------- 1 | # 79. convert snake_case to camelCase 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/problem/convert-snake_case-to-camelCase 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | Do you prefer [snake_case](https://en.wikipedia.org/wiki/Snake_case) or [camelCase](https://en.wikipedia.org/wiki/Camel_case) ? 12 | 13 | Anyway, please create a function to convert snake_case to camcelCase. 14 | 15 | ```js 16 | snakeToCamel('snake_case'); 17 | // 'snakeCase' 18 | snakeToCamel('is_flag_on'); 19 | // 'isFlagOn' 20 | snakeToCamel('is_IOS_or_Android'); 21 | // 'isIOSOrAndroid' 22 | snakeToCamel('_first_underscore'); 23 | // '_firstUnderscore' 24 | snakeToCamel('last_underscore_'); 25 | // 'lastUnderscore_' 26 | snakeToCamel('_double__underscore_'); 27 | // '_double__underscore_' 28 | ``` 29 | 30 | contiguous underscore `__`, leading underscore `_a`, and trailing underscore `a_` should be kept untouched. 31 | 32 | # 33 | 34 | ### Solution 35 | 36 | ```js 37 | /** 38 | * @param {string} str 39 | * @return {string} 40 | */ 41 | function snakeToCamel(str) { 42 | return str.replace(/[a-z]_[a-z]/gi, (match) => { 43 | return match[0] + match[2].toUpperCase(); 44 | }); 45 | } 46 | ``` 47 | 48 | # 49 | 50 | ### Refactored Solution 51 | 52 | ```js 53 | /** 54 | * @param {string} str 55 | * @return {string} 56 | */ 57 | function snakeToCamel(str) { 58 | return str.replace(/([^_])_([^_])/g, (_, before, after) => { 59 | return before + after.toUpperCase(); 60 | }); 61 | } 62 | ``` 63 | 64 | # 65 | 66 | ### Solution with Lookbehind 67 | 68 | ```js 69 | /** 70 | * @param {string} str 71 | * @return {string} 72 | */ 73 | function snakeToCamel(str) { 74 | return str.replace(/(?<=[a-z])_[a-z]/gi, (match) => { 75 | return match[1].toUpperCase(); 76 | }); 77 | } 78 | ``` 79 | 80 | # 81 | 82 | ### Reference 83 | 84 | [Problem Discuss](https://bigfrontend.dev/problem/convert-snake_case-to-camelCase/discuss) 85 | -------------------------------------------------------------------------------- /81.merge-sorted-arrays.md: -------------------------------------------------------------------------------- 1 | # 81. merge sorted arrays 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/problem/merge-sorted-arrays 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | You are given a list of sorted non-descending integer arrays, write a function to merge them into one sorted non-descending array. 12 | 13 | ```js 14 | merge([ 15 | [1, 1, 1, 100, 1000, 10000], 16 | [1, 2, 2, 2, 200, 200, 1000], 17 | [1000000, 10000001], 18 | [2, 3, 3], 19 | ]); 20 | // [1,1,1,1,2,2,2,2,3,3,100,200,200,1000,1000,10000,1000000,10000001] 21 | ``` 22 | 23 | What is time complexity of your solution? 24 | 25 | # 26 | 27 | ### Understanding the problem 28 | 29 | Given a list of sorted arrays of integers, which are all in non-descending order, I am asked to write a function that is going to merge them into one array sorted in the same order. 30 | 31 | # 32 | 33 | ### Approach 34 | 35 | I can solve the problem by using divide-and-conquer approach. Divide the list of sorted arrays in half, then keep dividing the two sub-lists of sorted arrays in half, until the sub-list contains only one array, cause if there is only one sorted array in the list, I can simply return that array. Then I can merge the two sorted arrays from the previous step into one and return the merged array. Keep merging the two arrays from the previous step until all arrays are merged. 36 | 37 | To merge two sorted array I can use two pointers approach. Initially, point the first pointer to the start of the first array and the second pointer to the start of the second array, loop until both pointers point to the ends of the arrays. At each iteration, compare the elements in the two arrays the two pointers point to, if the element in the first array is smaller than the element in the second array, push the element from the first array into the empty array and move the pointer of that element to right by 1; otherwise push the element from the second array and move its pointer to right. If one of these two elements is `undefined`, set it to `Infinity`. 38 | 39 | ### Solution 40 | 41 | ```js 42 | /** 43 | * @param {number[][]} arrList 44 | * non-descending integer array 45 | * @return {number[]} 46 | */ 47 | function merge(arrList) { 48 | return mergeImpl(arrList, 0, arrList.length - 1); 49 | } 50 | 51 | function mergeImpl(arrList, start, end) { 52 | if (start >= end) return arrList[end] || []; 53 | 54 | const mid = Math.floor((start + end) / 2); 55 | 56 | const left = mergeImpl(arrList, start, mid); 57 | const right = mergeImpl(arrList, mid + 1, end); 58 | return mergeSort(left, right); 59 | } 60 | 61 | function mergeSort(arrOne, arrTwo) { 62 | const mergedArr = []; 63 | let idxOne = 0; 64 | let idxTwo = 0; 65 | 66 | while (idxOne !== arrOne.length || idxTwo !== arrTwo.length) { 67 | const firstElement = arrOne[idxOne] || Infinity; 68 | const secondElement = arrTwo[idxTwo] || Infinity; 69 | 70 | if (firstElement < secondElement) { 71 | mergedArr.push(firstElement); 72 | idxOne++; 73 | } else { 74 | mergedArr.push(secondElement); 75 | idxTwo++; 76 | } 77 | } 78 | 79 | return mergedArr; 80 | } 81 | ``` 82 | -------------------------------------------------------------------------------- /Questions-Answers/1.Promise-order.md: -------------------------------------------------------------------------------- 1 | # 1. Promise order 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/1-promise-order 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | console.log(1); 15 | const promise = new Promise((resolve) => { 16 | console.log(2); 17 | resolve(); 18 | console.log(3); 19 | }); 20 | 21 | console.log(4); 22 | 23 | promise 24 | .then(() => { 25 | console.log(5); 26 | }) 27 | .then(() => { 28 | console.log(6); 29 | }); 30 | 31 | console.log(7); 32 | 33 | setTimeout(() => { 34 | console.log(8); 35 | }, 10); 36 | 37 | setTimeout(() => { 38 | console.log(9); 39 | }, 0); 40 | ``` 41 | 42 | # 43 | 44 | ### Answer 45 | 46 | ``` 47 | 1 48 | 2 49 | 3 50 | 4 51 | 7 52 | 5 53 | 6 54 | 9 55 | 8 56 | ``` 57 | 58 | ### Explanation 59 | 60 | - The console logs `2` right after `1`, because the function passed to the `Promise` constructor is executed immediately when a new `Promise` is created. 61 | 62 | - Although a promise can only be resolved or rejected once, codes that come after `resolve()` or `reject()` will still get executed: 63 | 64 | ```js 65 | const promise = new Promise((resolve, reject) => { 66 | console.log(2); 67 | reject(); 68 | console.log(3); 69 | }); 70 | 71 | // Logs: 72 | // 2 73 | // 3 74 | ``` 75 | 76 | - The [then handlers](<(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then)>) of a promise are enqueued onto microtask queue. Immediately after every macrotask, JavaScript engine executes all tasks from the microtask queue, prior to running any other macrotasks. Since `setTimeout()` handlers are macrotasks, the console logs `5` and `6` before `9` and `8`. 77 | -------------------------------------------------------------------------------- /Questions-Answers/10.equal.md: -------------------------------------------------------------------------------- 1 | # 10. Equal 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/Equal-1 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | console.log(0 == false); 15 | console.log('' == false); 16 | console.log([] == false); 17 | console.log(undefined == false); 18 | console.log(null == false); 19 | console.log('1' == true); 20 | console.log(1n == true); 21 | console.log(' 1 ' == true); 22 | ``` 23 | 24 | # 25 | 26 | ### Answer 27 | 28 | ```js 29 | console.log(0 == false); // true 30 | console.log('' == false); // true 31 | console.log([] == false); // true 32 | console.log(undefined == false); // false 33 | console.log(null == false); // false 34 | console.log('1' == true); // true 35 | console.log(1n == true); // true 36 | console.log(' 1 ' == true); // true 37 | ``` 38 | 39 | ### Explanation 40 | 41 | When two values are compared with `==` (and `!=`), the [Abstract Equality Comparison Algorithm](http://www.ecma-international.org/ecma-262/5.1/#sec-11.9.3) is used. 42 | 43 | If the two values are of different types, JavaScript converts them to the same type before comparing: 44 | 45 | - If one of the operands is `Boolean`, the Boolean is converted to 1 if it is `true` and +0 if it is `false`. 46 | - When comparing a number to a string, JavaScript tries to convert the string to a numeric value. 47 | - If one of the operands is an object or an array, JavaScript tries to convert it to a primitive value using the `valueOf()` or `toString()` method. 48 | 49 | `[]` is converted to `''` using `toString()`, so `[] == false` returns `true`. 50 | 51 | `null` is only comparable to `undefined` in the [Abstract Equality Comparison Algorithm](http://www.ecma-international.org/ecma-262/5.1/#sec-11.9.3), therefore `undefined == false` and `null == false` both return `false`. 52 | 53 | Since `true` is converted to `1`, `2 == true` returns `false`. 54 | 55 | # 56 | 57 | ### Reference 58 | 59 | [Equality (==)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Equality) 60 | -------------------------------------------------------------------------------- /Questions-Answers/11.Implicit-Coercion-II.md: -------------------------------------------------------------------------------- 1 | # 11. Implicit Coercion II 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/Implicit-Conversion-II 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | console.log([] + []); 15 | console.log([] + 1); 16 | console.log([[]] + 1); 17 | console.log([[1]] + 1); 18 | console.log([[[[2]]]] + 1); 19 | console.log([] - 1); 20 | console.log([[]] - 1); 21 | console.log([[1]] - 1); 22 | console.log([[[[2]]]] - 1); 23 | console.log([] + {}); 24 | console.log({} + {}); 25 | console.log({} - {}); 26 | ``` 27 | 28 | # 29 | 30 | ### Answer 31 | 32 | ```js 33 | console.log([] + []); // "" 34 | console.log([] + 1); // "1" 35 | console.log([[]] + 1); // "1" 36 | console.log([[1]] + 1); // "11" 37 | console.log([[[[2]]]] + 1); // "21" 38 | console.log([] - 1); // -1 39 | console.log([[]] - 1); // -1 40 | console.log([[1]] - 1); // 0 41 | console.log([[[[2]]]] - 1); // 1 42 | console.log([] + {}); // "[object Object]" 43 | console.log({} + {}); // "[object Object][object Object]" 44 | console.log({} - {}); // NaN 45 | ``` 46 | 47 | ### Explanation 48 | 49 | - `[] + []` returns `""`, because `[]` is coerced to an empty string using `Array`'s `toString()` method. First, `+` operator tries to convert `[]` into a primitive value with `Array`'s `valueOf()` method, but it returns the array itself, so the `valueOf()` method is ignored. Then `+` uses `Array`'s `toString()` as fallback and it returns an empty string. 50 | 51 | - `[] + 1` returns `"1"`, because **`+` operator tries string concatenation before numeric addition, if one of the operands is a string.**. The same logic also applies to `[[]] + 1`, `[[1]] + 1` and `[[[[2]]]] + 1`. 52 | 53 | - `[] - 1` returns `-1`, because `-` operator triggers numeric conversion for `[]`: first, `[]` is converted to an empty string using the `toString()` method; then the empty string is converted to `0`. The same logic applies to `[[]] - 1`, `[[1]] - 1` and `[[[[2]]]] - 1`. 54 | 55 | - `[] + {}` returns `"[object Object]"`, because `+` operator tries to convert both `[]` and `{}` to primitive values. Since `Object`'s `valueOf()` method returns the object itself, `{}` is converted to `"[object Object]"` using the `toString()` method. The same logic applies to `{} + {}`. 56 | 57 | - `{} - {}` returns `NaN`, because `-` operator triggers numeric conversion for `{}`: first, `{}` is coerced to `"[object Object]"` using the `toString()` method; then `"[object Object]"` is converted to `NaN`. 58 | 59 | # 60 | 61 | ### Reference 62 | 63 | [JavaScript type coercion explained](https://www.freecodecamp.org/news/js-type-coercion-explained-27ba3d9a2839/) 64 | -------------------------------------------------------------------------------- /Questions-Answers/12.arguments.md: -------------------------------------------------------------------------------- 1 | # 12. arguments 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/arguments 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | function log(a, b, c, d) { 15 | console.log(a, b, c, d); 16 | arguments[0] = 'bfe'; 17 | arguments[3] = 'dev'; 18 | 19 | console.log(a, b, c, d); 20 | } 21 | 22 | log(1, 2, 3); 23 | ``` 24 | 25 | # 26 | 27 | ### Answer 28 | 29 | ```js 30 | function log(a, b, c, d) { 31 | console.log(a, b, c, d); // 1,2,3,undefined 32 | arguments[0] = 'bfe'; 33 | arguments[3] = 'dev'; 34 | 35 | console.log(a, b, c, d); // "bfe",2,3,undefined 36 | } 37 | 38 | log(1, 2, 3); 39 | ``` 40 | 41 | ### Explanation 42 | 43 | Even though `arguments[3] = 'dev'` does add a fourth item to the `arguments` object, it doesn't reassign the new value to `d`, because the function call `log(1, 2, 3)` doesn't supply an argument for the parameter `d` and therefore `d` is not bound to the `arguments` object, which means its value cannot be updated by modifying the arguments object. 44 | 45 | # 46 | 47 | ### Reference 48 | 49 | [The JavaScript arguments object…and beyond](https://javascriptweblog.wordpress.com/2011/01/18/javascripts-arguments-object-and-beyond/) 50 | -------------------------------------------------------------------------------- /Questions-Answers/13.Operator-precedence.md: -------------------------------------------------------------------------------- 1 | # 13. Operator precedence 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/operator-precedence 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | 14 | ```js 15 | console.log(0 == 1 == 2); 16 | console.log(2 == 1 == 0); 17 | console.log(0 < 1 < 2); 18 | console.log(1 < 2 < 3); 19 | console.log(2 > 1 > 0); 20 | console.log(3 > 2 > 1); 21 | ``` 22 | 23 | # 24 | 25 | ### Answer 26 | 27 | 28 | ```js 29 | console.log(0 == 1 == 2); // false 30 | console.log(2 == 1 == 0); // true 31 | console.log(0 < 1 < 2); // true 32 | console.log(1 < 2 < 3); // true 33 | console.log(2 > 1 > 0); // true 34 | console.log(3 > 2 > 1); // false 35 | ``` 36 | 37 | ### Explanation 38 | 39 | `0 == 1 == 2` returns `false`, because JavaScript first evaluates `0 == 1` and the result is `false`, then `false` is converted to `0` by `==` operator and compared to `2`. The same logic applies to all the other cases. 40 | 41 | # 42 | 43 | ### Reference 44 | 45 | [Operator precedence: Example](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#examples) 46 | -------------------------------------------------------------------------------- /Questions-Answers/14.Addition-vs-Unary-Plus.md: -------------------------------------------------------------------------------- 1 | # 14. Addition vs Unary Plus 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/Addition-vs-Unary-Plus 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | There is a difference between [Addition Operator(+)](https://tc39.es/ecma262/#sec-addition-operator-plus) and [Unary plus operator(+)](https://tc39.es/ecma262/#sec-unary-plus-operator), even though they use the same '+'. 14 | 15 | 16 | ```js 17 | console.log(1 + 2) 18 | console.log(1 + + 2) 19 | console.log(1 + + + 2) 20 | console.log(1 + '2') 21 | console.log(1 + + '2') 22 | console.log('1' + 2) 23 | console.log('1' + + 2) 24 | console.log(1 + true) 25 | console.log(1 + + true) 26 | console.log('1' + true) 27 | console.log('1' + + true) 28 | console.log(1 + null) 29 | console.log(1 + + null) 30 | console.log('1' + null) 31 | console.log('1' + + null) 32 | console.log(1 + undefined) 33 | console.log(1 + + undefined) 34 | console.log('1' + undefined) 35 | console.log('1' + + undefined) 36 | console.log('1' + + + undefined) 37 | ``` 38 | 39 | # 40 | 41 | ### Answer 42 | 43 | 44 | ```js 45 | console.log(1 + 2) // 3 46 | console.log(1 + + 2) // 3 47 | console.log(1 + + + 2) // 3 48 | 49 | console.log(1 + '2') 50 | // "12". When one of the operands is a string, `+` operator performs 51 | // string concatenation. 52 | 53 | console.log(1 + + '2') // 3 54 | console.log('1' + 2) // "12" 55 | console.log('1' + + 2) // "12" 56 | console.log(1 + true) // 2 57 | console.log(1 + + true) // 2 58 | 59 | console.log('1' + true) 60 | // "1true". When one of the operands is a string, `+` operator performs 61 | // string concatenation. Thus `true` is converted to `"true"`. 62 | 63 | console.log('1' + + true) // "11" 64 | console.log(1 + null) // 1 65 | console.log(1 + + null) // 1 66 | 67 | console.log('1' + null) 68 | // "1null". When one of the operands is a string, `+` operator performs 69 | // string concatenation. Thus `null` is converted to `"null"`. 70 | 71 | 72 | console.log('1' + + null) // "10" 73 | console.log(1 + undefined) // NaN 74 | console.log(1 + + undefined) // NaN 75 | 76 | console.log('1' + undefined) 77 | // "1undefined". When one of the operands is a string, `+` operator performs 78 | // string concatenation. Thus `undefined` is converted to `"undefined"`. 79 | 80 | 81 | console.log('1' + + undefined) // "1NaN" 82 | console.log('1' + + + undefined) // "1NaN" 83 | ``` 84 | -------------------------------------------------------------------------------- /Questions-Answers/15.instanceOf.md: -------------------------------------------------------------------------------- 1 | # 15. instanceOf 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/instanceOf 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | console.log(typeof null); 15 | console.log(null instanceof Object); 16 | console.log(typeof 1); 17 | console.log(1 instanceof Number); 18 | console.log(1 instanceof Object); 19 | console.log(Number(1) instanceof Object); 20 | console.log(new Number(1) instanceof Object); 21 | console.log(typeof true); 22 | console.log(true instanceof Boolean); 23 | console.log(true instanceof Object); 24 | console.log(Boolean(true) instanceof Object); 25 | console.log(new Boolean(true) instanceof Object); 26 | console.log([] instanceof Array); 27 | console.log([] instanceof Object); 28 | console.log((() => {}) instanceof Object); 29 | ``` 30 | 31 | # 32 | 33 | ### Answer 34 | 35 | ```js 36 | console.log(typeof null); // "object" 37 | 38 | console.log(null instanceof Object); 39 | // false. Primitive values are not objects. 40 | 41 | console.log(typeof 1); // "number" 42 | console.log(1 instanceof Number); // false 43 | console.log(1 instanceof Object); // false 44 | 45 | console.log(Number(1) instanceof Object); 46 | // false. When used as a function, `Number(value)` converts 47 | // `value` to the Number type. 48 | 49 | console.log(new Number(1) instanceof Object); // true 50 | console.log(typeof true); // "boolean" 51 | console.log(true instanceof Boolean); // false 52 | console.log(true instanceof Object); // false 53 | 54 | console.log(Boolean(true) instanceof Object); 55 | // false. When used as a function, `Boolean(value)` converts 56 | // `value` to the Boolean type. 57 | 58 | console.log(new Boolean(true) instanceof Object); // true 59 | console.log([] instanceof Array); // true 60 | 61 | console.log([] instanceof Object); 62 | // true. Since `Array` prototypically inherits from `Object`, 63 | // `Array` also belongs to `Object` class. 64 | 65 | console.log((() => {}) instanceof Object); 66 | // true. Every JavaScript function is a `Function` object. 67 | ``` 68 | 69 | # 70 | 71 | ### Reference 72 | 73 | - [The instanceof operator](https://javascript.info/instanceof#ref-instanceof) 74 | - [Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function) 75 | -------------------------------------------------------------------------------- /Questions-Answers/16.parseInt.md: -------------------------------------------------------------------------------- 1 | # 16. parseInt 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/parseInt 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | console.log(['0'].map(parseInt)); 15 | console.log(['0', '1'].map(parseInt)); 16 | console.log(['0', '1', '1'].map(parseInt)); 17 | console.log(['0', '1', '1', '1'].map(parseInt)); 18 | ``` 19 | 20 | # 21 | 22 | ### Answer 23 | 24 | ```js 25 | console.log(['0'].map(parseInt)); // [0] 26 | console.log(['0', '1'].map(parseInt)); // [0,NaN] 27 | console.log(['0', '1', '1'].map(parseInt)); // [0,NaN,1] 28 | console.log(['0', '1', '1', '1'].map(parseInt)); // [0,NaN,1,1] 29 | ``` 30 | 31 | ### Explanation 32 | 33 | When a callback function is passed into `Array.prototype.map(callback)`, **it will receive three arguments**: `currentValue`, `currentIndex` and the full `array`. `['0', '1'].map(parseInt)` is equivalent to `['0', '1'].map((val, index, array) => parseInt(val, index, array))`. The function `parseInt()` takes in two arguments, a string to parse and an integer representing the radix, and the second argument is optional. If the radix provided is falsy, then by default, radix is set to `10`; if the radix is smaller than `2` or bigger than `36`, then `parseInt()` returns `NaN`. 34 | 35 | In `['0', '1'].map(parseInt)`, at first iteration `parseInt()` is invoked with `'0'`, `0` and `['0', '1']` as arguments. Since the radix provided is falsy, it is set to `10`, and `parseInt()` returns `0`. At second iteration, `parseInt()` receives `'1'`, `1` and `['0', '1']`. Since the radix is smaller than `2`, `NaN` is returned. Thus `console.log(['0', '1'].map(parseInt));` logs `[0,NaN]`. The same logic applies to the other cases. 36 | 37 | # 38 | 39 | ### Reference 40 | 41 | [Why `['1', '7', '11'].map(parseInt)` returns `[1, NaN, 3]` in Javascript](https://medium.com/dailyjs/parseint-mystery-7c4368ef7b21) 42 | -------------------------------------------------------------------------------- /Questions-Answers/17.reduce.md: -------------------------------------------------------------------------------- 1 | # 17. reduce 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/reduce 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | [1, 2, 3].reduce((a, b) => { 15 | console.log(a, b); 16 | }); 17 | 18 | [1, 2, 3].reduce((a, b) => { 19 | console.log(a, b); 20 | }, 0); 21 | ``` 22 | 23 | # 24 | 25 | ### Answer 26 | 27 | ```js 28 | [1, 2, 3].reduce((a, b) => { 29 | console.log(a, b); 30 | }); 31 | 32 | // logs: 33 | // a: 1, b: 2 34 | // a: undefined, b: 3 35 | 36 | /* ---------------------------- */ 37 | 38 | [1, 2, 3].reduce((a, b) => { 39 | console.log(a, b); 40 | }, 0); 41 | 42 | // logs: 43 | // a: 0, b: 1 44 | // a: undefined, b: 2 45 | // a: undefined, b: 3 46 | ``` 47 | -------------------------------------------------------------------------------- /Questions-Answers/18.Promise-executor-II.md: -------------------------------------------------------------------------------- 1 | # 18. Promise executor II 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/Promise-executor-II 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | const p1 = Promise.resolve(1); 15 | const p2 = new Promise((resolve) => resolve(p1)); 16 | const p3 = Promise.resolve(p1); 17 | const p4 = p2.then(() => new Promise((resolve) => resolve(p3))); 18 | const p5 = p4.then(() => p4); 19 | 20 | console.log(p1 == p2); 21 | console.log(p1 == p3); 22 | console.log(p3 == p4); 23 | console.log(p4 == p5); 24 | ``` 25 | 26 | # 27 | 28 | ### Answer 29 | 30 | ```js 31 | const p1 = Promise.resolve(1); 32 | const p2 = new Promise((resolve) => resolve(p1)); 33 | const p3 = Promise.resolve(p1); 34 | const p4 = p2.then(() => new Promise((resolve) => resolve(p3))); 35 | const p5 = p4.then(() => p4); 36 | 37 | console.log(p1 == p2); // false 38 | console.log(p1 == p3); // true 39 | console.log(p3 == p4); // false 40 | console.log(p4 == p5); // false 41 | ``` 42 | 43 | ### Explanation 44 | 45 | - `p1 == p2` is `false`, because `p1` and `p2` reference two different Promise objects. 46 | - `p1 == p3` is `true`, because when `Promise.resolve(value)` receives a Promise object as argument, it returns that Promise object. 47 | - `p3 == p4` is `false`, because `Promise.prototype.then()` returns a new Promise. If the `onFulfilled` handler returns an already resolved Promise, the Promise returned by `then()` gets resolved with that Promise's value as its value. 48 | - `p4 == p5` is `false`, because `Promise.prototype.then()` returns a new Promise. 49 | -------------------------------------------------------------------------------- /Questions-Answers/2.Promise-executor.md: -------------------------------------------------------------------------------- 1 | # 2. Promise executor 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/2-promise-executor 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | new Promise((resolve, reject) => { 15 | resolve(1); 16 | resolve(2); 17 | reject('error'); 18 | }).then( 19 | (value) => { 20 | console.log(value); 21 | }, 22 | (error) => { 23 | console.log('error'); 24 | } 25 | ); 26 | ``` 27 | 28 | # 29 | 30 | ### Answer 31 | 32 | ```js 33 | new Promise((resolve, reject) => { 34 | resolve(1); 35 | resolve(2); 36 | reject('error'); 37 | }).then( 38 | (value) => { 39 | console.log(value); 40 | // logs 1. A promise can only be resolved or rejected once. 41 | }, 42 | (error) => { 43 | console.log('error'); // ignored 44 | } 45 | ); 46 | ``` 47 | -------------------------------------------------------------------------------- /Questions-Answers/20.name-for-Function-expression.md: -------------------------------------------------------------------------------- 1 | # 20. name for Function expression 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/name-for-Function-expression 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | function a() {} 15 | const b = function () {}; 16 | 17 | const c = function d() { 18 | console.log(typeof d); 19 | d = 'e'; 20 | console.log(typeof d); 21 | }; 22 | 23 | console.log(typeof a); 24 | console.log(typeof b); 25 | console.log(typeof c); 26 | console.log(typeof d); 27 | c(); 28 | ``` 29 | 30 | # 31 | 32 | ### Answer 33 | 34 | ```js 35 | function a() {} 36 | const b = function () {}; 37 | 38 | const c = function d() { 39 | console.log(typeof d); // "function" 40 | d = 'e'; 41 | console.log(typeof d); // "function" 42 | }; 43 | 44 | console.log(typeof a); // "function" 45 | console.log(typeof b); // "function" 46 | console.log(typeof c); // "function" 47 | console.log(typeof d); // "undefined" 48 | c(); 49 | ``` 50 | 51 | ### Explanation 52 | 53 | The variable the function expression is assigned to will have a `name` property. If function name is present, the value of the `name` property will be the function name (explicit name); otherwise it will be the variable name (implicit name): 54 | 55 | ```js 56 | const b = function () {}; 57 | console.log(b.name); // 'b' 58 | 59 | const c = function d() {}; 60 | console.log(c.name); // 'd' 61 | ``` 62 | 63 | The scope of the name is just the body of the function, not the surrounding scope, therefore it is not defined in the global scope: 64 | 65 | ```js 66 | const c = function d() { 67 | console.log(d); // function d() {...} 68 | }; 69 | 70 | console.log(d); // Error: `d` is not defined. 71 | ``` 72 | 73 | In addition, the name doesn't change if it is assigned to a different variable: 74 | 75 | ```js 76 | const c = function d() { 77 | d = 'e'; 78 | console.log(c.name); // "d" 79 | console.log(d); // function d() {...} 80 | }; 81 | 82 | c(); 83 | ``` 84 | 85 | # 86 | 87 | ### Reference 88 | 89 | [Function expression](https://developer.mozilla.org/en-US/docs/web/JavaScript/Reference/Operators/function) 90 | -------------------------------------------------------------------------------- /Questions-Answers/21.Array-I.md: -------------------------------------------------------------------------------- 1 | # 21. Array I 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/Array-I 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | const a = [0]; 15 | console.log(a.length); 16 | a[3] = 3; 17 | console.log(a.length); 18 | for (let item of a) { 19 | console.log(item); 20 | } 21 | a.map((item) => { 22 | console.log(item); 23 | }); 24 | a.forEach((item) => { 25 | console.log(item); 26 | }); 27 | console.log(Object.keys(a)); 28 | delete a[3]; 29 | console.log(a.length); 30 | a[2] = 2; 31 | a.length = 1; 32 | console.log(a[0], a[1], a[2]); 33 | ``` 34 | 35 | # 36 | 37 | ### Answer 38 | 39 | ```js 40 | const a = [0]; 41 | console.log(a.length); // 1 42 | a[3] = 3; 43 | console.log(a.length); // 4 44 | for (let item of a) { 45 | console.log(item); // 0, undefined, undefined, 3 46 | } 47 | a.map((item) => { 48 | console.log(item); // 0, 3 49 | }); 50 | a.forEach((item) => { 51 | console.log(item); // 0, 3 52 | }); 53 | console.log(Object.keys(a)); // ["0","3"] 54 | delete a[3]; 55 | console.log(a.length); // 4 56 | a[2] = 2; 57 | a.length = 1; 58 | console.log(a[0], a[1], a[2]); // 0,undefined,undefined 59 | ``` 60 | 61 | ### Explanation 62 | 63 | - When run over a sparse array, both `Array.prototype.map()` and `Array.prototype.forEach()` skip the blank indices in the sparse array. 64 | 65 | - When you delete an array element with the `delete` operator, the array `length` is not affected. 66 | 67 | ```js 68 | const a = [0]; 69 | a[3] = 3; 70 | delete a[3]; 71 | 72 | console.log(a); // [0, empty, empty, empty] 73 | ``` 74 | 75 | # 76 | 77 | ### Reference 78 | 79 | - [Array.prototype.map()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map#parameters_in_detail) 80 | - [Array.prototype.forEach()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach#no_operation_for_uninitialized_values_sparse_arrays) 81 | - [delete operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/delete#deleting_array_elements) 82 | -------------------------------------------------------------------------------- /Questions-Answers/22.min-max.md: -------------------------------------------------------------------------------- 1 | # 22. min max 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/min-max 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | console.log(Math.min()); 15 | console.log(Math.max()); 16 | console.log(Math.min(1)); 17 | console.log(Math.max(1, 2)); 18 | console.log(Math.min([1, 2, 3])); 19 | ``` 20 | 21 | # 22 | 23 | ### Answer 24 | 25 | ```js 26 | console.log(Math.min()); // Infinity 27 | console.log(Math.max()); // -Infinity 28 | console.log(Math.min(1)); // 1 29 | console.log(Math.max(1, 2)); // 2 30 | console.log(Math.min([1, 2, 3])); // NaN 31 | ``` 32 | 33 | ### Explanation 34 | 35 | If no parameters are provided, `Math.min()` returns `Infinity` and `Math.max()` returns `-Infinity`. If any one or more of the parameters cannot be converted into a number, `Math.min()` and `Math.max()` return `NaN`. 36 | 37 | # 38 | 39 | ### Reference 40 | 41 | - [`Math.min()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/min) 42 | - [`Math.max()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/max) 43 | -------------------------------------------------------------------------------- /Questions-Answers/23.Promise-all.md: -------------------------------------------------------------------------------- 1 | # 23. Promise.all() 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/Promise-all 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | (async () => { 15 | await Promise.all([]).then( 16 | (value) => { 17 | console.log(value); 18 | }, 19 | (error) => { 20 | console.log(error); 21 | } 22 | ); 23 | 24 | await Promise.all([1, 2, Promise.resolve(3), Promise.resolve(4)]).then( 25 | (value) => { 26 | console.log(value); 27 | }, 28 | (error) => { 29 | console.log(error); 30 | } 31 | ); 32 | 33 | await Promise.all([1, 2, Promise.resolve(3), Promise.reject('error')]).then( 34 | (value) => { 35 | console.log(value); 36 | }, 37 | (error) => { 38 | console.log(error); 39 | } 40 | ); 41 | })(); 42 | ``` 43 | 44 | # 45 | 46 | ### Answer 47 | 48 | ```js 49 | (async () => { 50 | await Promise.all([]).then( 51 | (value) => { 52 | console.log(value); // [] 53 | }, 54 | (error) => { 55 | console.log(error); // ignored 56 | } 57 | ); 58 | 59 | await Promise.all([1, 2, Promise.resolve(3), Promise.resolve(4)]).then( 60 | (value) => { 61 | console.log(value); // [1, 2, 3, 4] 62 | }, 63 | (error) => { 64 | console.log(error); // ignored 65 | } 66 | ); 67 | 68 | await Promise.all([1, 2, Promise.resolve(3), Promise.reject('error')]).then( 69 | (value) => { 70 | console.log(value); // ignored 71 | }, 72 | (error) => { 73 | console.log(error); // "error" 74 | } 75 | ); 76 | })(); 77 | ``` 78 | 79 | ### Explanation 80 | 81 | The `Promise.all()` method takes an iterable of promises as input. 82 | 83 | - If an empty iterable is passed, then the promise returned by this method is fulfilled synchronously. The resolved value is an empty array. 84 | - If a nonempty iterable is passed, and all of the promises fulfill, or are not promises, then the promise returned by this method is fulfilled asynchronously. The resolved value is an array containing all the resolved values, including non-promise values. 85 | - If any of the passed-in promises reject, `Promise.all` asynchronously rejects with the value of the promise that rejected, whether or not the other promises have resolved. 86 | 87 | # 88 | 89 | ### Reference 90 | 91 | [Promise.all()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all) 92 | -------------------------------------------------------------------------------- /Questions-Answers/24.Equality-Sameness.md: -------------------------------------------------------------------------------- 1 | # 24. Equality & Sameness 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/Equality-Sameness 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | console.log(0 == '0'); 15 | console.log(0 === '0'); 16 | console.log(Object.is(0, '0')); 17 | 18 | console.log(0 == 0); 19 | console.log(0 === 0); 20 | console.log(Object.is(0, 0)); 21 | 22 | console.log(0 == -0); 23 | console.log(0 === -0); 24 | console.log(Object.is(0, -0)); 25 | 26 | console.log(NaN == NaN); 27 | console.log(NaN === NaN); 28 | console.log(Object.is(NaN, NaN)); 29 | 30 | console.log(0 == false); 31 | console.log(0 === false); 32 | console.log(Object.is(0, false)); 33 | ``` 34 | 35 | # 36 | 37 | ### Answer 38 | 39 | ```js 40 | console.log(0 == '0'); // true 41 | console.log(0 === '0'); // false 42 | console.log(Object.is(0, '0')); // false 43 | 44 | console.log(0 == 0); // true 45 | console.log(0 === 0); // true 46 | console.log(Object.is(0, 0)); // true 47 | 48 | console.log(0 == -0); // true 49 | console.log(0 === -0); // true 50 | console.log(Object.is(0, -0)); // false 51 | 52 | console.log(NaN == NaN); // false 53 | console.log(NaN === NaN); // false 54 | console.log(Object.is(NaN, NaN)); // true 55 | 56 | console.log(0 == false); // true 57 | console.log(0 === false); // false 58 | console.log(Object.is(0, false)); // false 59 | ``` 60 | 61 | ### Explanation 62 | 63 | - When comparing a number to a string using the equality operator `==`, `==` tries to convert the string to a numeric value. 64 | 65 | - When comparing two values using `==` and one of the values is `Boolean`, `==` converts the `Boolean` to `1` if it is `true` and `+0` if it is `false`. 66 | 67 | - The `Object.is(value1, value2)` method determines whether two values are the same, and it doesn't coerce either value before comparing. The difference between `Object.is()` and the `===` operator is how they treat signed zeros and `NaN`s: 68 | - The `===` operator (and the `==` operator) treats `-0` and `+0` as equal, whereas `Object.is()` treats `-0` and `+0` as not equal. 69 | - The `===` operator treats `NaN` as not equal: `NaN === NaN` returns `false`, whereas `Object.is(NaN, NaN)` returns `true`. In addition, `Object.is(NaN, 0/0)` returns `true`, whereas 70 | `NaN === 0/0` returns `false`. 71 | 72 | # 73 | 74 | ### Reference 75 | 76 | - [Equality (==)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Equality) 77 | - [Object.is()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) 78 | -------------------------------------------------------------------------------- /Questions-Answers/25.zero.md: -------------------------------------------------------------------------------- 1 | # 25. zero 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/zero 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | console.log(1 / 0); 15 | console.log(-1 / 0); 16 | console.log(0 / 0); 17 | console.log(0 === -0); 18 | console.log(Object.is(0, -0)); 19 | console.log(Object.is(0, Math.round(-0.5))); 20 | console.log(Object.is(0, Math.round(0.5))); 21 | console.log(0 * Infinity); 22 | console.log(Infinity / Infinity); 23 | console.log(Object.is(0, Math.sign(0))); 24 | console.log(Object.is(0, Math.sign(-0))); 25 | console.log(1 / -0); 26 | console.log(1 / 0); 27 | console.log(1n / 0n); 28 | ``` 29 | 30 | # 31 | 32 | ### Answer 33 | 34 | ```js 35 | console.log(1 / 0); // Infinity 36 | console.log(-1 / 0); // -Infinity 37 | console.log(0 / 0); // NaN 38 | console.log(0 === -0); // true 39 | console.log(Object.is(0, -0)); // false 40 | console.log(Object.is(0, Math.round(-0.5))); // false 41 | console.log(Object.is(0, Math.round(0.5))); // false 42 | console.log(0 * Infinity); // NaN 43 | console.log(Infinity / Infinity); // NaN 44 | console.log(Object.is(0, Math.sign(0))); // true 45 | console.log(Object.is(0, Math.sign(-0))); // false 46 | console.log(1 / -0); // -Infinity 47 | console.log(1 / 0); // Infinity 48 | console.log(1n / 0n); // Error 49 | ``` 50 | 51 | ### Explanation 52 | 53 | - `1 / 0` returns `Infinity`, because any positive number divided by `0` returns `Infinity`. [The  ECMAScript language specification states](http://es5.github.io/#x11.5.2): 54 | 55 | > division of a non-zero finite value by a zero results in a signed infinity. 56 | 57 | The specification author decided for division by zero to default to `Infinity`, because as the denominator trends toward zero, the result trends towards `Infinity`: 58 | 59 | ``` 60 | 2 / 1 = 2 61 | 2 / 0.5 = 4 62 | ... 63 | 2 / 0.0000000000000005 = 4e+1 64 | ``` 65 | 66 | - `0 / 0` returns `NaN`, because in mathematics, `0 / 0` is undefined as a [real number](https://en.wikipedia.org/wiki/Real_number), and is therefore represented by `NaN` in computing systems. 67 | 68 | - The `Object.is(value1, value2)` method determines whether two values are the same. `Object.is()` treats `-0` and `+0` as not equal, whereas the `===` operator (and the `==` operator) treats `-0` and `+0` as equal. 69 | 70 | - `0 * Infinity` returns `NaN`. The floating point zeros not only represent the real number `0`, but also all real numbers that would round to something smaller than the smallest [subnormal](https://en.wikipedia.org/wiki/Denormal_number). That is why `0` is signed. The floating point infinites represent all numbers that would round to something with a magnitude that would not fit in the finite range. `NaN` represents either 'No real number result' or 'Haven't a clue'. Something very big multiplied by something very small could be anything from very small to very bid, therefore `NaN` is the most reasonable answer. The same logic applies to `Infinity / Infinity` case(?). 71 | 72 | - `Math.sign(number)` method returns `+1` or `-1`, indicating the sign of the input number. If the input number is 0, it will return `+0` or `-0` depending on the sign of the `0` passed into `Math.sign()`. 73 | 74 | - `1n / 0n` ends up in an error: `RangeError: Division by zero`(?). 75 | 76 | # 77 | 78 | ### Reference 79 | 80 | - [Infinite from zero division](https://stackoverflow.com/questions/21893525/infinite-from-zero-division) 81 | - [In JavaScript, why does zero divided by zero return NaN, but any other divided by zero return Infinity?](https://stackoverflow.com/questions/18838301/in-javascript-why-does-zero-divided-by-zero-return-nan-but-any-other-divided-b) 82 | - [NaN](https://en.wikipedia.org/wiki/NaN#Creation) 83 | - [`Object.is()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) 84 | - [Why is Infinity × 0 = NaN?](https://stackoverflow.com/questions/37841240/why-is-infinity-%C3%97-0-nan) 85 | - [Math.sign()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sign) 86 | -------------------------------------------------------------------------------- /Questions-Answers/26.true-or-false.md: -------------------------------------------------------------------------------- 1 | # 26. true or false 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/true-or-false 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | console.log([] == 0); 15 | console.log([] == false); 16 | console.log(!![]); 17 | console.log([1] == 1); 18 | console.log(!![1]); 19 | console.log(Boolean([])); 20 | console.log(Boolean(new Boolean([]))); 21 | console.log(Boolean(new Boolean(false))); 22 | ``` 23 | 24 | # 25 | 26 | ### Answer 27 | 28 | ```js 29 | console.log([] == 0); // true 30 | console.log([] == false); // true 31 | console.log(!![]); // true; 32 | console.log([1] == 1); // true; 33 | console.log(!![1]); // true; 34 | console.log(Boolean([])); // true 35 | console.log(Boolean(new Boolean([]))); // true 36 | console.log(Boolean(new Boolean(false))); // true 37 | ``` 38 | 39 | ### Explanation 40 | 41 | - The [double NOT operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_NOT) explicitly converts any value to the corresponding [boolean primitive](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#boolean_type). The conversion is based on the "truthyness" or "falsyness" of the value. 42 | In the case of `!![]`, since any array is truthy, `[]` evaluates to `true`; `!true` results in `false`, and finally `!false` returns `true`. 43 | 44 | - `Boolean(value)` returns `false` if the value passed as argument is falsy, otherwise it returns `true`. An empty array is truthy, thus `Boolean([])` returns `true`. 45 | 46 | - `new Boolean(value)` returns a `Boolean` object. Any object is truthy including a `Boolean` object whose value is `false`, thus `Boolean(new Boolean(false))` returns `true`. 47 | 48 | # 49 | 50 | ### Reference 51 | 52 | - [Logical NOT (!)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_NOT) 53 | - [Truthy](https://developer.mozilla.org/en-US/docs/Glossary/Truthy) 54 | - [Falsy](https://developer.mozilla.org/en-US/docs/Glossary/Falsy) 55 | - [Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean) 56 | -------------------------------------------------------------------------------- /Questions-Answers/27.Hoisting-I.md: -------------------------------------------------------------------------------- 1 | # 27. Hoisting I 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/Hoisting-I 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | const a = 1; 15 | console.log(a); 16 | 17 | var b; 18 | console.log(b); 19 | b = 2; 20 | 21 | console.log(c); 22 | var c = 3; 23 | 24 | console.log(d); 25 | let d = 2; 26 | ``` 27 | 28 | # 29 | 30 | ### Answer 31 | 32 | ```js 33 | const a = 1; 34 | console.log(a); // 1 35 | 36 | var b; 37 | console.log(b); // undefined 38 | b = 2; 39 | 40 | console.log(c); 41 | var c = 3; 42 | // logs `undefined`. Variables declared with `var` are hoisted 43 | // to the top of the scope. JavaScript only hoists variable 44 | // declaration, not initialization. 45 | 46 | console.log(d); 47 | let d = 2; 48 | // throws a `ReferenceError`. Variables declared with `let` 49 | // and `const` are also hoisted, but unlike `var` variables, 50 | // they are in a 'temporal dead zone'(TDZ) from the start of 51 | // the block until they are declared. Accessing them inside 52 | // the TDZ results in an error. 53 | ``` 54 | 55 | # 56 | 57 | ### Reference 58 | 59 | [What is the Temporal Dead Zone (TDZ) in JavaScript?](https://www.freecodecamp.org/news/what-is-the-temporal-dead-zone/) 60 | -------------------------------------------------------------------------------- /Questions-Answers/28.Hoisting-II.md: -------------------------------------------------------------------------------- 1 | # 28. Hoisting II 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/Hoisting-II 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | const func1 = () => console.log(1); 15 | 16 | func1(); 17 | 18 | func2(); 19 | 20 | function func2() { 21 | console.log(2); 22 | } 23 | 24 | func3(); 25 | 26 | var func3 = function func4() { 27 | console.log(3); 28 | }; 29 | ``` 30 | 31 | # 32 | 33 | ### Answer 34 | 35 | ```js 36 | const func1 = () => console.log(1); 37 | 38 | func1(); // 1 39 | 40 | func2(); // 2 41 | 42 | function func2() { 43 | console.log(2); 44 | } 45 | 46 | func3(); // Error. Function expressions are not hoisted. 47 | 48 | var func3 = function func4() { 49 | console.log(3); 50 | }; 51 | ``` 52 | -------------------------------------------------------------------------------- /Questions-Answers/29.Hoisting-III.md: -------------------------------------------------------------------------------- 1 | # 29. Hoisting III 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/Hoisting-III 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | var a = 1; 15 | 16 | function func() { 17 | a = 2; 18 | console.log(a); 19 | var a; 20 | } 21 | 22 | func(); 23 | 24 | console.log(a); 25 | 26 | if (!('b' in window)) { 27 | var b = 1; 28 | } 29 | 30 | console.log(b); 31 | ``` 32 | 33 | # 34 | 35 | ### Answer 36 | 37 | ```js 38 | var a = 1; 39 | 40 | function func() { 41 | a = 2; 42 | console.log(a); // 2 43 | var a; 44 | } 45 | 46 | func(); 47 | 48 | console.log(a); // 1 49 | 50 | if (!('b' in window)) { 51 | var b = 1; 52 | } 53 | 54 | console.log(b); // undefined 55 | ``` 56 | 57 | ### Explanation 58 | 59 | Hoisting is a JavaScript mechanism where variable and function declarations are moved to the top of their scope before code execution. Variables declared with `var` are hoisted, but JavaScript only hoists declaration, i.e. `var b`, not initialization. 60 | 61 | ```js 62 | var a = 1; 63 | 64 | function func() { 65 | a = 2; // Initialization 66 | console.log(a); 67 | var a; // Declaration 68 | } 69 | 70 | func(); 71 | 72 | console.log(a); 73 | ``` 74 | 75 | Variable `a` in the function `func()` is moved to the top of the function scope before code execution. When `func()` gets called, variable `a` is initialized to `2`. Since `var` variables are function scope, it doesn't affect the global variable `a`. The global variable `a` will be affected, if we replace the function with a `if` statement: 76 | 77 | ```js 78 | var x = 1; 79 | 80 | if (x === 1) { 81 | var x = 2; 82 | 83 | console.log(x); 84 | // expected output: 2 85 | } 86 | 87 | console.log(x); 88 | // expected output: 2 89 | ``` 90 | 91 | --- 92 | 93 | ```js 94 | if (!('b' in window)) { 95 | var b = 1; 96 | } 97 | 98 | console.log(b); 99 | ``` 100 | 101 | When declaring a variable using `var` in a `if` statement, no matter the `if` condition pass or not pass, the declaration is always hoisted. So in the above case, when the code executes, `b` is already in the `window` object, thus the initialization never happens and the console logs `undefined`. 102 | 103 | # 104 | 105 | ### Reference 106 | 107 | [If statement and variable hoisting](https://stackoverflow.com/questions/34149693/if-statement-and-variable-hoisting) 108 | -------------------------------------------------------------------------------- /Questions-Answers/3.Promise-then-callbacks.md: -------------------------------------------------------------------------------- 1 | # 3. Promise then callbacks 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/3-promise-then-callbacks 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | Promise.resolve(1) 15 | .then(() => 2) 16 | .then(3) 17 | .then((value) => value * 3) 18 | .then(Promise.resolve(4)) 19 | .then(console.log); 20 | ``` 21 | 22 | # 23 | 24 | ### Answer 25 | 26 | ``` 27 | 6 28 | ``` 29 | 30 | ### Explanation 31 | 32 | If the first argument that `.then()` receives is not a function, it is internally replaced with a function that returns the receiving argument. Therefore, when the code snippet above runs, `3` and `Promise.resolve(4)` are going to be replaced with the function `(result) => result`: 33 | 34 | ```js 35 | Promise.resolve(1) 36 | .then(() => 2) 37 | // 3 is internally replaced with a function. 38 | .then((result) => result) // 2 39 | .then((value) => value * 3) // 6 40 | // Promise.resolve(4) is internally replaced with a function. 41 | .then((result) => result) // 6 42 | .then(console.log); // logs 6 43 | ``` 44 | -------------------------------------------------------------------------------- /Questions-Answers/30.Equal-II.md: -------------------------------------------------------------------------------- 1 | # 30. Equal II 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/Equal-II 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | ref to the [The Abstract Equality Comparison Algorithm](https://www.ecma-international.org/ecma-262/5.1/#sec-11.9.3) 13 | 14 | ```js 15 | console.log([1] == 1); 16 | console.log([1] == '1'); 17 | console.log(['1'] == '1'); 18 | console.log(['1'] == 1); 19 | console.log([1] == ['1']); 20 | console.log(new Boolean(true) == 1); 21 | console.log(new Boolean(true) == new Boolean(true)); 22 | console.log(Boolean(true) == '1'); 23 | console.log(Boolean(false) == [0]); 24 | console.log(new Boolean(true) == '1'); 25 | console.log(new Boolean(false) == [0]); 26 | console.log(null == undefined); 27 | ``` 28 | 29 | # 30 | 31 | ### Answer 32 | 33 | ```js 34 | console.log([1] == 1); // true 35 | console.log([1] == '1'); // true 36 | console.log(['1'] == '1'); // true 37 | console.log(['1'] == 1); // true 38 | console.log([1] == ['1']); // false 39 | console.log(new Boolean(true) == 1); // true 40 | console.log(new Boolean(true) == new Boolean(true)); // false 41 | console.log(Boolean(true) == '1'); // true 42 | console.log(Boolean(false) == [0]); // true 43 | console.log(new Boolean(true) == '1'); // true 44 | console.log(new Boolean(false) == [0]); // false 45 | console.log(null == undefined); // true 46 | ``` 47 | 48 | ### Explanation 49 | 50 | - `==` tries to convert the operands if they are of different types. In `[1] == ['1']`, the operands are of the same type, so type coercion doesn't happen. Since arrays are the reference data types, we are comparing two references that point to different memory location, thus `[1] === ['1']` returns `false`. The same logic applies to the `new Boolean(true) == new Boolean(true)` case and the `new Boolean(false) == [0]` case. 51 | 52 | - `new Boolean(true).valueOf()` returns `true`, so `new Boolean(true) == 1` returns `true`. 53 | -------------------------------------------------------------------------------- /Questions-Answers/31.Math.md: -------------------------------------------------------------------------------- 1 | # 31. Math 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/Math 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | console.log(1 / 0); 15 | console.log(0 / 0); 16 | console.log(-1 / 0); 17 | console.log((1 / 0) * 0); 18 | console.log((1 / 0) * 1); 19 | console.log((1 / 0) * -1); 20 | console.log((1 / 0) * 1 + (1 / 0) * 1); 21 | console.log((1 / 0) * 1 - (1 / 0) * 1); 22 | console.log((1 / 0) * 1 * ((1 / 0) * 1)); 23 | console.log(((1 / 0) * 1) / ((1 / 0) * 1)); 24 | console.log(0 / Infinity); 25 | console.log(0 * Infinity); 26 | ``` 27 | 28 | # 29 | 30 | ### Answer 31 | 32 | ```js 33 | console.log(1 / 0); // Infinity 34 | console.log(0 / 0); // NaN 35 | console.log(-1 / 0); // -Infinity 36 | console.log((1 / 0) * 0); // NaN 37 | console.log((1 / 0) * 1); // Infinity 38 | console.log((1 / 0) * -1); // -Infinity 39 | console.log((1 / 0) * 1 + (1 / 0) * 1); // Infinity 40 | console.log((1 / 0) * 1 - (1 / 0) * 1); // NaN 41 | console.log((1 / 0) * 1 * ((1 / 0) * 1)); // Infinity 42 | console.log(((1 / 0) * 1) / ((1 / 0) * 1)); // NaN 43 | console.log(0 / Infinity); // 0 44 | console.log(0 * Infinity); // NaN 45 | ``` 46 | -------------------------------------------------------------------------------- /Questions-Answers/32.Hoisting-IIII.md: -------------------------------------------------------------------------------- 1 | # 32. Hoisting IIII 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/Hoisting-IIII 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | var a = 1; 15 | function a() {} 16 | 17 | console.log(typeof a); 18 | 19 | var b; 20 | function b() {} 21 | b = 1; 22 | 23 | console.log(typeof b); 24 | 25 | function c() {} 26 | var c = 1; 27 | 28 | console.log(typeof c); 29 | 30 | var d = 1; 31 | 32 | (function () { 33 | d = '2'; 34 | console.log(typeof d); 35 | function d() {} 36 | })(); 37 | 38 | console.log(typeof d); 39 | 40 | var e = 1; 41 | const f = function e() {}; 42 | 43 | console.log(typeof e); 44 | ``` 45 | 46 | # 47 | 48 | ### Answer 49 | 50 | ```js 51 | var a = 1; 52 | function a() {} 53 | 54 | console.log(typeof a); // "number" 55 | 56 | var b; 57 | function b() {} 58 | b = 1; 59 | 60 | console.log(typeof b); // "number" 61 | 62 | function c() {} 63 | var c = 1; 64 | 65 | console.log(typeof c); // "number" 66 | 67 | var d = 1; 68 | 69 | (function () { 70 | d = '2'; 71 | console.log(typeof d); // "string" 72 | function d() {} 73 | })(); 74 | 75 | console.log(typeof d); // "number" 76 | 77 | var e = 1; 78 | const f = function e() {}; 79 | 80 | console.log(typeof e); // "number" 81 | ``` 82 | 83 | ### Explanation 84 | 85 | ```js 86 | var a = 1; 87 | function a() {} 88 | 89 | console.log(typeof a); // 'number' 90 | ``` 91 | 92 | Before code execution, `var` variable and function declarations are hoisted to the top of the scope in which they are declared. JavaScript first moves function declarations, then `var` variable declarations. The order of declarations doesn't matter. So that means function declarations will be overwritten by variable declarations. From the code snippet above, first the "name" `a` is declared, then the function declaration is automatically assigned to it, then `a` is initialized to `1` with `a = 1` and overwrites `a`. 93 | 94 | 🙋‍♀️🙋‍♂️ If we replace `var` with `let`, it will ends up in an error: 95 | 96 | ```js 97 | let a = 1; 98 | function a() {} 99 | 100 | console.log(typeof a); 101 | // Uncaught SyntaxError: Identifier 'a' has already been declared. 102 | ``` 103 | 104 | --- 105 | 106 | ```js 107 | var b; 108 | function b() {} 109 | b = 1; 110 | 111 | console.log(typeof b); // 'number' 112 | ``` 113 | 114 | The reason for this is the same as above. 115 | 116 | --- 117 | 118 | ```js 119 | var d = 1; 120 | 121 | (function () { 122 | d = '2'; 123 | console.log(typeof d); // 'string' 124 | function d() {} 125 | })(); 126 | 127 | console.log(typeof d); // 'number' 128 | ``` 129 | 130 | `d = '2'` in the IIFE doesn't overwrite the outside `d` but `function d() {}`, which is moved to the top of the IIFE's scope before code execution. 131 | 132 | ```js 133 | var d = 1; 134 | 135 | (function () { 136 | d = '2'; 137 | console.log(typeof d); // 'string' 138 | function d() {} 139 | })(); 140 | 141 | console.log(d); // 1 142 | ``` 143 | 144 | If we delete `function d() {}`, then `d = '2'` will assign the outside `d` to `'2'`: 145 | 146 | ```js 147 | var d = 1; 148 | 149 | (function () { 150 | d = '2'; 151 | console.log(typeof d); // 'string' 152 | })(); 153 | 154 | console.log(d); // '2' 155 | ``` 156 | 157 | 🙋‍♀️🙋‍♂️ A variable declared without `var` keyword becomes global: 158 | 159 | ```js 160 | (function () { 161 | d = '2'; 162 | })(); 163 | 164 | console.log(window.d); // '2' 165 | ``` 166 | 167 | --- 168 | 169 | ```js 170 | var e = 1; 171 | const f = function e() {}; 172 | 173 | console.log(typeof e); // 'number' 174 | ``` 175 | 176 | Function expressions and variables declared with `const` are not hoisted. The variable the function expression is assigned to will have a `name` property: 177 | 178 | ```js 179 | var e = 1; 180 | const f = function e() {}; 181 | 182 | console.log(f.name); // 'e' 183 | ``` 184 | 185 | # 186 | 187 | ### Reference 188 | 189 | [Javascript -What happens if a variable and a function have the same name? [duplicate]](https://stackoverflow.com/questions/45769024/javascript-what-happens-if-a-variable-and-a-function-have-the-same-name) 190 | -------------------------------------------------------------------------------- /Questions-Answers/33.this-II.md: -------------------------------------------------------------------------------- 1 | # 33. `this` II 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/this-II 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | 14 | ```js 15 | const obj = { 16 | a: 1, 17 | b() { 18 | return this.a 19 | } 20 | } 21 | console.log(obj.b()) 22 | console.log((true ? obj.b : a)()) 23 | console.log((true, obj.b)()) 24 | console.log((3, obj['b'])()) 25 | console.log((obj.b)()) 26 | console.log((obj.c = obj.b)()) 27 | ``` 28 | 29 | # 30 | 31 | ### Answer 32 | 33 | 34 | ```js 35 | const obj = { 36 | a: 1, 37 | b() { 38 | return this.a 39 | } 40 | } 41 | console.log(obj.b()) // 1 42 | console.log((true ? obj.b : a)()) // undefined 43 | console.log((true, obj.b)()) // undefined 44 | console.log((3, obj['b'])()) // undefined 45 | console.log((obj.b)()) // 1 46 | console.log((obj.c = obj.b)()) // undefined 47 | ``` 48 | 49 | ### Explanation 50 | 51 | `()` is [grouping operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Grouping). It overrides the normal precedence of evaluation in expressions, so that expressions with lower precedence can be evaluated before an expression with higher priority. 52 | 53 | - In `(true ? obj.b : a)()`, the condition expression is going to be evaluated first. The evaluation returns the function `function() { return this.a }`, that `obj.b` points to. Then `function() { return this.a }` is invoked. Since it is a plain, undecorated invocation, `this` points to the global object and we get `undefined` as result. 54 | 55 | - In `(true, obj.b)()`, we have a [comma sequence expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comma_Operator). Comma sequence expression evaluates its operands from left to right and returns the evaluation of last operand: 56 | 57 | ```js 58 | let x = 1; 59 | 60 | x = (x++, x); 61 | 62 | console.log(x); 63 | // output: 2 64 | 65 | x = (2, 3); 66 | 67 | console.log(x); 68 | // output: 3 69 | ``` 70 | 71 | In our case, the comma sequence expression returns `function() { return this.a }`, which is the value of the last operand `obj.b`. Then `function() { return this.a }` gets called and it is a plain, undecorated invocation. 72 | 73 | The same logic applies to `(3, obj['b'])()` and `(obj.c = obj.b)()`. 74 | 75 | - `(obj.b)()` is identical to `obj.b()`, because the grouping operator `()` only changes expression priority and doesn't trigger extra expression value return. In `(true, obj.b)()`, it is the comma sequence expression that triggers the expression value, and in `(obj.c = obj.b)()`, it is the assignment operator `=`. 76 | 77 | # 78 | 79 | ### Reference 80 | 81 | [Understanding this, one example at a time](https://www.karenjs.com/blog/understanding-this-one-example-at-a-time/#arrow-function) 82 | -------------------------------------------------------------------------------- /Questions-Answers/34.precedence.md: -------------------------------------------------------------------------------- 1 | # 34. precedence 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/precedence 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | 14 | ```js 15 | let a = 1 16 | console.log(a +++ a) 17 | 18 | let b = 1 19 | console.log(b + + + b) 20 | 21 | let c = 1 22 | console.log(c --- c) 23 | 24 | let d = 1 25 | console.log(d - - - d) 26 | ``` 27 | 28 | # 29 | 30 | ### Answer 31 | 32 | 33 | ```js 34 | let a = 1 35 | console.log(a +++ a) // 3 36 | 37 | let b = 1 38 | console.log(b + + + b) // 2 39 | 40 | let c = 1 41 | console.log(c --- c) // 1 42 | 43 | let d = 1 44 | console.log(d - - - d) // 0 45 | ``` 46 | 47 | ### Explanation 48 | 49 | - `a +++ a` returns `3`, because in this expression postfix increment operator `... ++` has the highest precedence, therefore JavaScript first evaluates `a ++`. `a +++ a` is same as `a++ + a`. 50 | Postfix increment increments and returns the value before incrementing: 51 | 52 | ```js 53 | let x = 3; 54 | let y = x++; 55 | 56 | console.log(x); // 4 57 | console.log(y); // 3 58 | ``` 59 | 60 | Thus `a++` returns `1` and `a` becomes `2`, and `a++ + a` returns `3`. 61 | 62 | The same logic applies to the `c --- c` case. `c --- c` is same as `c-- - c`. `c--` returns `1` and `c` becomes `0`, so the final result is `1`. 63 | 64 | - `b + + + b` returns `2`, because `+ +` is not increment operator and the unary plus operator `+` has the highest precedence, therefore JavaScript evaluates `+ b` first. `b + + + b` is same as `b + + (+b)`. 65 | The unary plus operator `+` tries to convert its operand into a number if it isn't already. Since `b` is already a number, the expression becomes `b + + b`. `b + + b` is identical to `b + +b`, so the final result is `2`. 66 | 67 | The same logic applies to `d - - - d`, which is identical to `d - - (-d)`. The unary negation operator `-` negates its operand, so `-d` returns `-1` and the expression becomes `d - - (-1)`, which is same as `d - -(-1)`. So the final result is `0`. 68 | 69 | # 70 | 71 | ### Reference 72 | 73 | [Operator precedence](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence) 74 | -------------------------------------------------------------------------------- /Questions-Answers/35.Implicit-Coercion-III.md: -------------------------------------------------------------------------------- 1 | # 35. Implicit Coercion III 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/Implicit-Conversion-III 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | 14 | ```js 15 | console.log( [] + {} ) 16 | console.log( + {} ) 17 | console.log( + [] ) 18 | console.log( {} + []) 19 | console.log( ({}) + []) 20 | console.log( ({}) + []) 21 | console.log( ({}) + []) 22 | console.log( {} + + []) 23 | console.log( {} + + [] + {} ) 24 | console.log( {} + + [] + {} + []) 25 | ``` 26 | 27 | # 28 | 29 | ### Answer 30 | 31 | 32 | ```js 33 | console.log( [] + {} ) // "[object Object]" 34 | console.log( + {} ) // NaN 35 | console.log( + [] ) // 0 36 | console.log( {} + []) // "[object Object]" 37 | console.log( ({}) + []) // "[object Object]" 38 | console.log( ({}) + []) // "[object Object]" 39 | console.log( ({}) + []) // "[object Object]" 40 | console.log( {} + + []) // "[object Object]0" 41 | console.log( {} + + [] + {} ) // "[object Object]0[object Object]" 42 | console.log( {} + + [] + {} + []) // "[object Object]0[object Object]" 43 | ``` 44 | 45 | ### Explanation 46 | 47 | `{} + + []` returns `"[object Object]0"`, because: 48 | 49 | - First, the unary operator `+` in `+ []` tries to convert its operand `[]` into a number. Since `Array`'s `valueOf()` method returns the array itself, so `+` uses `Array`'s `toString()` method as a fallback. `toString()` returns an empty string and `+` converts the empty string into `0`. 50 | 51 | - Then, the addition `+` operator tries to convert `{}` into a primitive, since `Object`'s `valueOf()` method returns the object itself, so `toString()` method is used as a fallback, which returns `"[object Object]"`. **When one of the operands is a string, `+` operator tries string concatenation before numeric addition**. 52 | -------------------------------------------------------------------------------- /Questions-Answers/36.Promise-prototype-finally.md: -------------------------------------------------------------------------------- 1 | # 36. Promise.prototype.finally() 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/Promise-prototype-finally 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | Promise.resolve(1) 15 | .finally((data) => { 16 | console.log(data); 17 | return Promise.reject('error'); 18 | }) 19 | .catch((error) => { 20 | console.log(error); 21 | throw 'error2'; 22 | }) 23 | .finally((data) => { 24 | console.log(data); 25 | return Promise.resolve(2).then(console.log); 26 | }) 27 | .then(console.log) 28 | .catch(console.log); 29 | ``` 30 | 31 | # 32 | 33 | ### Answer 34 | 35 | ``` 36 | undefined 37 | "error" 38 | undefined 39 | 2 40 | "error2" 41 | ``` 42 | 43 | ### Explanation 44 | 45 | ```js 46 | Promise.resolve(1) 47 | // `Promise.prototype.finally(callback)` returns a `Promise`. 48 | .finally((data) => { 49 | console.log(data); // `undefined`, because a `finally` callback will not receive any argument. 50 | return Promise.reject('error'); 51 | }) 52 | .catch((error) => { 53 | console.log(error); // `error` from the rejected promise returned by the previous `finally()` 54 | throw 'error2'; 55 | }) 56 | .finally((data) => { 57 | console.log(data); // `undefined`, because a `finally` callback will not receive any argument. 58 | return Promise.resolve(2).then(console.log); // 2 59 | }) 60 | .then(console.log) // ignored 61 | .catch(console.log); // `error2` from the previous `catch()` 62 | ``` 63 | -------------------------------------------------------------------------------- /Questions-Answers/37.push-unshift.md: -------------------------------------------------------------------------------- 1 | # 37. push unshift 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/push-unshift 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | const arr = [1, 2]; 15 | arr.push(3, 4); 16 | arr.unshift(5, 6); 17 | console.log(arr); 18 | ``` 19 | 20 | # 21 | 22 | ### Answer 23 | 24 | ``` 25 | [5,6,1,2,3,4] 26 | ``` 27 | -------------------------------------------------------------------------------- /Questions-Answers/38.Hoisting-IV.md: -------------------------------------------------------------------------------- 1 | # 38. Hoisting IV 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/Hoisting-IV 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | let foo = 10; 15 | function func1() { 16 | console.log(foo); 17 | var foo = 1; 18 | } 19 | func1(); 20 | 21 | function func2() { 22 | console.log(foo); 23 | let foo = 1; 24 | } 25 | func2(); 26 | ``` 27 | 28 | # 29 | 30 | ### Answer 31 | 32 | ```js 33 | let foo = 10; 34 | function func1() { 35 | console.log(foo); // undefined 36 | var foo = 1; 37 | } 38 | func1(); 39 | 40 | function func2() { 41 | console.log(foo); // Error 42 | let foo = 1; 43 | } 44 | func2(); 45 | ``` 46 | -------------------------------------------------------------------------------- /Questions-Answers/39.var.md: -------------------------------------------------------------------------------- 1 | # 39. var 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/var 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | function foo() { 15 | console.log(i); 16 | for (var i = 0; i < 3; i++) { 17 | console.log(i); 18 | } 19 | } 20 | 21 | foo(); 22 | ``` 23 | 24 | # 25 | 26 | ### Answer 27 | 28 | ```js 29 | function foo() { 30 | console.log(i); // undefined 31 | for (var i = 0; i < 3; i++) { 32 | console.log(i); // 0, 1, 2 33 | } 34 | } 35 | 36 | foo(); 37 | ``` 38 | -------------------------------------------------------------------------------- /Questions-Answers/4.Promise-then-callbacks-II.md: -------------------------------------------------------------------------------- 1 | # 4. Promise then callbacks II 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/4-Promise-then-callbacks-II 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | Promise.resolve(1) 15 | .then((val) => { 16 | console.log(val); 17 | return val + 1; 18 | }) 19 | .then((val) => { 20 | console.log(val); 21 | }) 22 | .then((val) => { 23 | console.log(val); 24 | return Promise.resolve(3).then((val) => { 25 | console.log(val); 26 | }); 27 | }) 28 | .then((val) => { 29 | console.log(val); 30 | return Promise.reject(4); 31 | }) 32 | .catch((val) => { 33 | console.log(val); 34 | }) 35 | .finally((val) => { 36 | console.log(val); 37 | return 10; 38 | }) 39 | .then((val) => { 40 | console.log(val); 41 | }); 42 | ``` 43 | 44 | # 45 | 46 | ### Answer 47 | 48 | ```js 49 | Promise.resolve(1) 50 | .then((val) => { 51 | console.log(val); // 1 52 | return val + 1; 53 | }) 54 | .then((val) => { 55 | console.log(val); // 2 56 | }) 57 | .then((val) => { 58 | console.log(val); // undefined 59 | return Promise.resolve(3).then((val) => { 60 | console.log(val); // 3 61 | }); 62 | }) 63 | .then((val) => { 64 | console.log(val); // undefined 65 | return Promise.reject(4); 66 | }) 67 | .catch((val) => { 68 | console.log(val); // 4 69 | }) 70 | .finally((val) => { 71 | console.log(val); // undefined 72 | return 10; 73 | }) 74 | .then((val) => { 75 | console.log(val); // undefined 76 | }); 77 | ``` 78 | 79 | ### Explanation 80 | 81 | - `Promise.prototype.then()` returns a `Promise`. If a `then` handler: 82 | 83 | - returns a value, the `Promise` returned by `Promise.prototype.then()` gets resolved with the returned value. 84 | 85 | - doesn't return anything, the `Promise` returned by `Promise.prototype.then()` gets resolved with an `undefined` value. 86 | 87 | - returns an already fulfilled `Promise`, the `Promise` returned by `Promise.prototype.then()` gets resolved with that `Promise`'s value as its value. 88 | 89 | - returns an already rejected `Promise`, the `Promise` returned by `Promise.prototype.then()` gets rejected with that `Promise`'s value as its value. 90 | 91 | - returns a pending `Promise`, the resolution/rejection of the promise returned by `Promise.prototype.then()` will be subsequent to the resolution/rejection of the `Promise` returned by the `then` handler. 92 | 93 | - `Promise.prototype.finally()` returns a `Promise`. A `finally` handler will not receive any argument. In addition, it won't change the resolved value and just pass through it: 94 | 95 | ```js 96 | Promise.resolve(1) 97 | .finally(() => { 98 | console.log('Promise ready'); 99 | return 10; 100 | }) 101 | .then((value) => { 102 | console.log(value); // 1 103 | }); 104 | ``` 105 | 106 | The reason that the final `then` handler in the code snippet above logs `undefined` is that `Promise.prototype.catch()` also returns a `Promise` and it behaves the same as calling `Promise.prototype.then(undefined, onRejected)`. If the `catch` handler before `finally()` returns a value, then the final `then` handler would log that value: 107 | 108 | ```js 109 | Promise.reject(1) 110 | .catch((value) => { 111 | console.log(value); 112 | return 3; 113 | }) 114 | .finally(() => { 115 | console.log('Promise ready'); 116 | }) 117 | .then((value) => { 118 | console.log(value); // 3 119 | }); 120 | ``` 121 | 122 | # 123 | 124 | ### Reference 125 | 126 | - [Promise.prototype.then()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then) 127 | - [Promise.prototype.catch()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch) 128 | - [finally](https://javascript.info/promise-basics#finally) 129 | -------------------------------------------------------------------------------- /Questions-Answers/40.RegExp-prototype-test.md: -------------------------------------------------------------------------------- 1 | # 40. RegExp.prototype.test 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/RegExp-prototype-test 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | console.log(/^4\d\d$/.test('404')); 15 | console.log(/^4\d\d$/.test(404)); 16 | console.log(/^4\d\d$/.test(['404'])); 17 | console.log(/^4\d\d$/.test([404])); 18 | ``` 19 | 20 | # 21 | 22 | ### Answer 23 | 24 | ``` 25 | true 26 | true 27 | true 28 | true 29 | ``` 30 | 31 | ### Explanation 32 | 33 | `RegExp.prototype.test()` expects a string. When you pass some value that is not a string, JavaScript will try to coerce it to a string value. 34 | -------------------------------------------------------------------------------- /Questions-Answers/41.this-III.md: -------------------------------------------------------------------------------- 1 | # 41. `this` III 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/this-III 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | const obj = { 15 | a: 1, 16 | b: this.a + 1, 17 | c: () => this.a + 1, 18 | d() { 19 | return this.a + 1; 20 | }, 21 | e() { 22 | return (() => this.a + 1)(); 23 | }, 24 | }; 25 | console.log(obj.b); 26 | console.log(obj.c()); 27 | console.log(obj.d()); 28 | console.log(obj.e()); 29 | ``` 30 | 31 | # 32 | 33 | ### Answer 34 | 35 | ```js 36 | const obj = { 37 | a: 1, 38 | b: this.a + 1, 39 | c: () => this.a + 1, 40 | d() { 41 | return this.a + 1; 42 | }, 43 | e() { 44 | return (() => this.a + 1)(); 45 | }, 46 | }; 47 | console.log(obj.b); // NaN 48 | console.log(obj.c()); // NaN 49 | console.log(obj.d()); // 2 50 | console.log(obj.e()); // 2 51 | ``` 52 | 53 | ### Explanation 54 | 55 | - `console.log(obj.b)` logs `NaN`, because object literals do not affect the value of `this` and **default binding** applies, which means `this` does not refer to `obj` but to the global object, i.e. `window` in browser. `window.a` is `undefined` and thus the result is `NaN`. 56 | 57 | - `console.log(obj.c())` logs `NaN`, because arrow functions do not have its own `this` binding and they adopt the value of `this` from the enclosed (function or global) scope. 58 | 59 | - `console.log(obj.d())` logs `2`, because the function `d()` is called as a method of `obj` and thus `this` is set to `obj`. 60 | 61 | - `console.log(obj.e())` logs `2`, because (() => this.a + 1)() is a arrow function and it is defined in the function `obj.e` which is not an arrow function. (() => this.a + 1)() captures whatever the function `e`'s `this` is at its call time. 62 | 63 | If we replace the arrow function with a normal function, we will get `NaN`, because `(function() {})()` is a plain, undecorated call: 64 | 65 | ```js 66 | const obj = { 67 | a: 1, 68 | e() { 69 | return (function () { 70 | return this.a + 1; 71 | })(); 72 | }, 73 | }; 74 | 75 | console.log(obj.e()); // NaN 76 | ``` 77 | 78 | We will also get `NaN`, if `obj.e` is not a method: 79 | 80 | ```js 81 | const obj = { 82 | a: 1, 83 | e: (() => { 84 | return this.a + 1; 85 | })(), 86 | }; 87 | 88 | console.log(obj.e); // NaN 89 | ``` 90 | 91 | ```js 92 | const obj = { 93 | a: 1, 94 | e: (function () { 95 | return this.a + 1; 96 | })(), 97 | }; 98 | 99 | console.log(obj.e); // NaN 100 | ``` 101 | 102 | # 103 | 104 | ### Reference 105 | 106 | [Understanding this, one example at a time](https://www.karenjs.com/blog/understanding-this-one-example-at-a-time/#arrow-function) 107 | -------------------------------------------------------------------------------- /Questions-Answers/42.Hoisting-V.md: -------------------------------------------------------------------------------- 1 | # 42. Hoisting V 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/hoisting-v 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | (() => { 15 | if (!fn) { 16 | function fn() { 17 | console.log('2'); 18 | } 19 | } 20 | fn(); 21 | })(); 22 | 23 | function fn() { 24 | console.log('1'); 25 | } 26 | 27 | // another one 28 | function fn1() { 29 | console.log('3'); 30 | } 31 | 32 | (() => { 33 | if (!fn1) { 34 | function fn1() { 35 | console.log('4'); 36 | } 37 | } 38 | fn1(); 39 | })(); 40 | 41 | // another one ! 42 | (() => { 43 | if (false) { 44 | function fn3() { 45 | console.log('5'); 46 | } 47 | } 48 | fn3(); 49 | })(); 50 | ``` 51 | 52 | # 53 | 54 | ### Answer 55 | 56 | ```js 57 | (() => { 58 | if (!fn) { 59 | function fn() { 60 | console.log('2'); 61 | } 62 | } 63 | fn(); 64 | })(); 65 | 66 | function fn() { 67 | console.log('1'); 68 | } 69 | 70 | // logs "2" 71 | 72 | /* ------------------------------- */ 73 | 74 | // another one 75 | function fn1() { 76 | console.log('3'); 77 | } 78 | 79 | (() => { 80 | if (!fn1) { 81 | function fn1() { 82 | console.log('4'); 83 | } 84 | } 85 | fn1(); 86 | })(); 87 | 88 | // logs "4" 89 | 90 | /* ------------------------------- */ 91 | 92 | // another one ! 93 | (() => { 94 | if (false) { 95 | function fn3() { 96 | console.log('5'); 97 | } 98 | } 99 | fn3(); 100 | })(); 101 | 102 | // logs Error 103 | ``` 104 | 105 | ### Explanation 106 | 107 | ```js 108 | (() => { 109 | if (!fn) { 110 | function fn() { 111 | console.log('2'); 112 | } 113 | } 114 | fn(); 115 | })(); 116 | 117 | function fn() { 118 | console.log('1'); 119 | } 120 | ``` 121 | 122 | The code snippet above logs `"2"`, because when a function is created conditionally, either the function name or the function declaration is hoisted to the top of the scope, no matter the `if` condition pass or not. Whether only the function name or the function declaration is hoisted to the top of the scope depends on the browser. In Chrome and Firefox, only the function name is hoisted, whereas in Safari, function declaration is hoisted: 123 | 124 | ```js 125 | var hoisted = 'foo' in this; 126 | console.log( 127 | `'foo' name ${hoisted ? 'is' : 'is not'} hoisted. typeof foo is ${typeof foo}` 128 | ); 129 | if (false) { 130 | function foo() { 131 | return 1; 132 | } 133 | } 134 | 135 | // In Chrome and Firefox: 136 | // 'foo' name is hoisted. typeof foo is undefined 137 | // 138 | // In Edge: 139 | // 'foo' name is not hoisted. typeof foo is undefined 140 | // 141 | // In Safari: 142 | // 'foo' name is hoisted. typeof foo is function 143 | 144 | /* ------------------------------------------------------ */ 145 | 146 | var hoisted = 'foo' in this; 147 | console.log( 148 | `'foo' name ${hoisted ? 'is' : 'is not'} hoisted. typeof foo is ${typeof foo}` 149 | ); 150 | if (true) { 151 | function foo() { 152 | return 1; 153 | } 154 | } 155 | 156 | // In Chrome and Firefox: 157 | // 'foo' name is hoisted. typeof foo is undefined 158 | // 159 | // In Edge: 160 | // 'foo' name is not hoisted. typeof foo is undefined 161 | // 162 | // In Safari: 163 | // 'foo' name is hoisted. typeof foo is function 164 | ``` 165 | 166 | The same logic applies to the rest of the cases. 167 | 168 | In addition, if you declare a `var` variable in a `if` statement, the variable declaration is also hoisted, no matter the `if` condition pass or not: 169 | 170 | ```js 171 | console.log(a); // undefined , not respond ReferenceError ,it has been hoisted 172 | if (true) { 173 | var a = 1; 174 | } 175 | console.log(b); // same as above 176 | if (false) { 177 | var b = 1; 178 | } 179 | ``` 180 | 181 | # 182 | 183 | ### Reference 184 | 185 | - [Conditionally created functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function#conditionally_created_functions) 186 | - [If statement and variable hoisting](https://stackoverflow.com/questions/34149693/if-statement-and-variable-hoisting) 187 | -------------------------------------------------------------------------------- /Questions-Answers/43.JSON.stringify.md: -------------------------------------------------------------------------------- 1 | # 43. JSON.stringify() 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/json-stringify 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | // attention that for console.log('"a"'), you should enter ""a"" 15 | // please refer to format guide 16 | 17 | console.log(JSON.stringify(['false', false])); 18 | console.log(JSON.stringify([NaN, null, Infinity, undefined])); 19 | console.log(JSON.stringify({ a: null, b: NaN, c: undefined })); 20 | ``` 21 | 22 | # 23 | 24 | ### Answer 25 | 26 | ```js 27 | console.log(JSON.stringify(['false', false])); 28 | // logs "["false",false]" 29 | 30 | console.log(JSON.stringify([NaN, null, Infinity, undefined])); 31 | // logs "[null,null,null,null]" 32 | 33 | console.log(JSON.stringify({ a: null, b: NaN, c: undefined })); 34 | // logs "{"a":null,"b":null}" 35 | ``` 36 | 37 | ### Explanation 38 | 39 | `undefined` will be omitted when found in an object. 40 | -------------------------------------------------------------------------------- /Questions-Answers/44.Function-call.md: -------------------------------------------------------------------------------- 1 | # 44. Function call 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/Function-call 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | function a() { 15 | console.log(1); 16 | return { 17 | a: function () { 18 | console.log(2); 19 | return a(); 20 | }, 21 | }; 22 | } 23 | 24 | a().a(); 25 | ``` 26 | 27 | # 28 | 29 | ### Answer 30 | 31 | ``` 32 | 1 33 | 2 34 | 1 35 | ``` 36 | 37 | ### Explanation 38 | 39 | The `a` in the `return a()` refers to `function a() { console.log(1); //... }`. 40 | -------------------------------------------------------------------------------- /Questions-Answers/45.Hoisting-VI.md: -------------------------------------------------------------------------------- 1 | # 45. Hoisting VI 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/Hoisting-VI 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | var foo = 1; 15 | (function () { 16 | console.log(foo); 17 | foo = 2; 18 | console.log(window.foo); 19 | console.log(foo); 20 | var foo = 3; 21 | console.log(foo); 22 | console.log(window.foo); 23 | })(); 24 | ``` 25 | 26 | # 27 | 28 | ### Answer 29 | 30 | ```js 31 | var foo = 1; 32 | (function () { 33 | console.log(foo); // undefined 34 | foo = 2; 35 | console.log(window.foo); // 1 36 | console.log(foo); // 2 37 | var foo = 3; 38 | console.log(foo); // 3 39 | console.log(window.foo); // 1 40 | })(); 41 | ``` 42 | 43 | ### Explanation 44 | 45 | The variable declaration `var foo` within the IIFE is hoisted to the top of the function scope. So the code snippet in the problem statement is actually equivalent to the following: 46 | 47 | ```js 48 | var foo = 1; 49 | (function () { 50 | var foo; // `foo` is declared within the function scope. 51 | console.log(foo); // undefined, because the local `foo` is not initialized. 52 | foo = 2; // The local `foo` is initialized to `2`. 53 | console.log(window.foo); // 1, because the local `foo` doesn't overwrite the global `foo`. 54 | console.log(foo); // 2, because the local `foo` has been assigned to `2`. 55 | foo = 3; // the local `foo` is re-assigned to `3`. 56 | console.log(foo); // 3 57 | console.log(window.foo); // 1 58 | })(); 59 | ``` 60 | -------------------------------------------------------------------------------- /Questions-Answers/46.Implicit-Coercion-IV.md: -------------------------------------------------------------------------------- 1 | # 46. Implicit Coercion IV 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/implicit-coersion-2 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | const foo = [0]; 15 | if (foo) { 16 | console.log(foo == true); 17 | } else { 18 | console.log(foo == false); 19 | } 20 | ``` 21 | 22 | # 23 | 24 | ### Answer 25 | 26 | ```js 27 | const foo = [0]; 28 | if (foo) { 29 | console.log(foo == true); // false 30 | } else { 31 | // Never reached, because an array always evaluates to `true` 32 | // when passed to a conditional statement. 33 | console.log(foo == false); 34 | } 35 | ``` 36 | 37 | ### Explanation 38 | 39 | `foo == true` returns `false`, because when the two operands are of different types and one of them is a `Boolean`, the `==` operator converts the `Boolean` to `1` if it is `true` and `0` if it is `false`, and the array `[0]` is converted into a string using `Array`'s `toString()` method, so `foo == true` becomes `'0' == 1`, finally, `'0'` is coerced to a numeric value, since when comparing a number to a string, `==` tries to convert the string to a number. 40 | -------------------------------------------------------------------------------- /Questions-Answers/47.Promise-Order-II.md: -------------------------------------------------------------------------------- 1 | # 47. Promise Order II 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/promise-order-II 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | console.log(1); 15 | 16 | setTimeout(() => { 17 | console.log(2); 18 | }, 10); 19 | 20 | setTimeout(() => { 21 | console.log(3); 22 | }, 0); 23 | 24 | new Promise((_, reject) => { 25 | console.log(4); 26 | reject(5); 27 | console.log(6); 28 | }) 29 | .then(() => console.log(7)) 30 | .catch(() => console.log(8)) 31 | .then(() => console.log(9)) 32 | .catch(() => console.log(10)) 33 | .then(() => console.log(11)) 34 | .then(console.log) 35 | .finally(() => console.log(12)); 36 | 37 | console.log(13); 38 | ``` 39 | 40 | # 41 | 42 | ### Answer 43 | 44 | ``` 45 | 1 46 | 4 47 | 6 48 | 13 49 | 8 50 | 9 51 | 11 52 | undefined 53 | 12 54 | 3 55 | 2 56 | ``` 57 | 58 | ### Explanation 59 | 60 | - The executor function passed to the `Promise` constructor is executed immediately. Since the callbacks in `setTimeout()` and `then()` will not be executed until the call stack is empty, the console logs `4` after `1`. 61 | - Although a promise can only be resolved/rejected once, code below `reject(value)` will be still executed. Therefore, console logs `6` after `4`. 62 | - `then` handlers and `catch` handler are queued in microtask queue. Immediately after every macrotask, the JavaScript engine will execute all tasks from the microtask queue, before running any other macrotasks. 63 | - Since the promise is rejected, `console.log(7)` is not executed, and the console outputs `8` from the `catch` handler after `13`. 64 | - The `catch()` method returns a promise, therefore the onFulfilled handler `() => console.log(9)` runs and the console logs `9`. 65 | - The `then()` method also returns a promise. Since the promise is resolved with a `undefined` value, `() => console.log(10)` from the `catch` handler is skipped, and the console logs `11`. 66 | - When the `then` onFulfilled handler gets executed, it receives the resolved promise's value as argument. Since the promise returned by `then(() => console.log(11))` is resolved with an `undefined` value, the `console.log` from `then(console.log)` receives `undefined` as argument and outputs `undefined`. 67 | - The callback function passed to `finally()` will be executed when a promise is settled, no matter whether the promise is resolved or rejected. There `12` is logged. 68 | - After all tasks from the microtask queue are executed, the callbacks from the `setTimeout()` run. 69 | -------------------------------------------------------------------------------- /Questions-Answers/48.Prototype.md: -------------------------------------------------------------------------------- 1 | # 48. Prototype 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/prototype 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | function Foo() {} 15 | Foo.prototype.bar = 1; 16 | const a = new Foo(); 17 | console.log(a.bar); 18 | 19 | Foo.prototype.bar = 2; 20 | const b = new Foo(); 21 | console.log(a.bar); 22 | console.log(b.bar); 23 | 24 | Foo.prototype = { bar: 3 }; 25 | const c = new Foo(); 26 | console.log(a.bar); 27 | console.log(b.bar); 28 | console.log(c.bar); 29 | ``` 30 | 31 | # 32 | 33 | ### Answer 34 | 35 | ```js 36 | function Foo() {} 37 | Foo.prototype.bar = 1; 38 | const a = new Foo(); 39 | console.log(a.bar); // 1 40 | 41 | Foo.prototype.bar = 2; 42 | const b = new Foo(); 43 | console.log(a.bar); 44 | // 2, because reassigning the `Foo.prototype.bar` to a new 45 | // value also affects the old instance `a`. 46 | console.log(b.bar); 47 | // 2 48 | 49 | Foo.prototype = { bar: 3 }; 50 | const c = new Foo(); 51 | console.log(a.bar); // 2 52 | console.log(b.bar); // 2 53 | console.log(c.bar); // 3 54 | ``` 55 | 56 | ### Explanation 57 | 58 | Modifying the `bar` property of `Foo.prototype` does affect the old instances, but if we point the `prototype` property of `Foo` to a new object, the old instances' `__proto__` property will still point to the old `Foo.prototype`: 59 | 60 | ```js 61 | function Foo() {} 62 | Foo.prototype.bar = 1; 63 | const a = new Foo(); 64 | 65 | Foo.prototype = { bar: 3 }; 66 | const c = new Foo(); 67 | 68 | console.log(a.__proto__); // { bar: 1, constructor: ƒ Foo() } 69 | console.log(c.__proto__); // { bar: 3 } 70 | ``` 71 | 72 | # 73 | 74 | ### Reference 75 | 76 | [Javascript : Modifying Prototype doesn't affect existing Instances](https://stackoverflow.com/questions/43765005/javascript-modifying-prototype-doesnt-affect-existing-instances) 77 | -------------------------------------------------------------------------------- /Questions-Answers/49.this-IV.md: -------------------------------------------------------------------------------- 1 | # 49. `this` IV 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/this-4 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | var bar = 1; 15 | 16 | function foo() { 17 | return this.bar++; 18 | } 19 | 20 | const a = { 21 | bar: 10, 22 | foo1: foo, 23 | foo2: function () { 24 | return foo(); 25 | }, 26 | }; 27 | 28 | console.log(a.foo1.call()); 29 | console.log(a.foo1()); 30 | console.log(a.foo2.call()); 31 | console.log(a.foo2()); 32 | ``` 33 | 34 | # 35 | 36 | ### Answer 37 | 38 | ```js 39 | var bar = 1; 40 | 41 | function foo() { 42 | return this.bar++; 43 | } 44 | 45 | const a = { 46 | bar: 10, 47 | foo1: foo, 48 | foo2: function () { 49 | return foo(); 50 | }, 51 | }; 52 | 53 | console.log(a.foo1.call()); // 1 54 | console.log(a.foo1()); // 10 55 | console.log(a.foo2.call()); // 2 56 | console.log(a.foo2()); // 3 57 | ``` 58 | 59 | ### Explanation 60 | 61 | - When using `call()` to invoke a function and without providing the first argument, the value of `this` is set to the global object. 62 | 63 | - If the increment operator `++` precedes the operand, the increment operator increments and return the value before incrementing. If `++` comes after the operand, `++` increments and return the value after incrementing. 64 | 65 | ```js 66 | let x = 3; 67 | y = x++; 68 | 69 | // y = 3 70 | // x = 4 71 | ``` 72 | 73 | ```js 74 | let a = 2; 75 | b = ++a; 76 | 77 | // a = 3 78 | // b = 3 79 | ``` 80 | 81 | # 82 | 83 | ### Reference 84 | 85 | - [Function.prototype.call()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call) 86 | - [Increment (++)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Increment) 87 | -------------------------------------------------------------------------------- /Questions-Answers/5.block-scope.md: -------------------------------------------------------------------------------- 1 | # 5. block scope 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/block-scope-1 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | for (var i = 0; i < 5; i++) { 15 | setTimeout(() => console.log(i), 0); 16 | } 17 | 18 | for (let i = 0; i < 5; i++) { 19 | setTimeout(() => console.log(i), 0); 20 | } 21 | ``` 22 | 23 | # 24 | 25 | ### Answer 26 | 27 | ```js 28 | for (var i = 0; i < 5; i++) { 29 | setTimeout(() => console.log(i), 0); // 5 5 5 5 5 30 | } 31 | 32 | for (let i = 0; i < 5; i++) { 33 | setTimeout(() => console.log(i), 0); // 0 1 2 3 4 34 | } 35 | ``` 36 | 37 | ### Explanation 38 | 39 | Because of how Event loop works in JavaScript, the timeout function callbacks always run after the completion of the for loop, even if it is `setTimeout(..., 0)` on each iteration. 40 | 41 | `var` variables are function scoped. `var` in the for loop header creates a single binding for `i`. When the timeout function callbacks execute, they share a reference to the same `i`, which is global scoped. Thus it logs: `5 5 5 5 5`. 42 | 43 | `let` variables are block scoped. `let` in the for loop header not only binds `i` to the for loop body, but also creates a new binding for each loop iteration. In other words, each iteration of the loop captures its own copy of `i`. Hence it prints: `0 1 2 3 4`. 44 | 45 | We can use closures to make the first one works like the second one: 46 | 47 | ```js 48 | for (var i = 0; i < 5; i++) { 49 | (function (j) { 50 | setTimeout(() => console.log(j), 0); 51 | })(i); 52 | } 53 | ``` 54 | 55 | or declare a variable with `let` inside the for loop body to create a per-iteration block scope: 56 | 57 | ```js 58 | for (var i = 0; i < 5; i++) { 59 | let j = i; 60 | setTimeout(() => console.log(j), 0); 61 | } 62 | ``` 63 | -------------------------------------------------------------------------------- /Questions-Answers/50.async-await.md: -------------------------------------------------------------------------------- 1 | # 50. async await 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/async-await 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | async function async1() { 15 | console.log(1); 16 | await async2(); 17 | console.log(2); 18 | } 19 | 20 | async function async2() { 21 | console.log(3); 22 | } 23 | 24 | console.log(4); 25 | 26 | setTimeout(function () { 27 | console.log(5); 28 | }, 0); 29 | 30 | async1(); 31 | 32 | new Promise(function (resolve) { 33 | console.log(6); 34 | resolve(); 35 | }).then(function () { 36 | console.log(7); 37 | }); 38 | 39 | console.log(8); 40 | ``` 41 | 42 | # 43 | 44 | ### Answer 45 | 46 | ``` 47 | 4 48 | 1 49 | 3 50 | 6 51 | 8 52 | 2 53 | 7 54 | 5 55 | ``` 56 | 57 | ### Explanation 58 | 59 | `await` triggers microtask queue processing: 60 | 61 | ```js 62 | async function foo() { 63 | await 1; 64 | console.log(1); 65 | } 66 | ``` 67 | 68 | is equivalent to: 69 | 70 | ```js 71 | function foo() { 72 | return Promise.resolve(1).then(() => { 73 | console.log(1); 74 | }); 75 | } 76 | ``` 77 | 78 | # 79 | 80 | ### Reference: 81 | 82 | - [Why does this line of code with 'await' trigger microtask queue processing?](https://stackoverflow.com/questions/56851983/why-does-this-line-of-code-with-await-trigger-microtask-queue-processing) 83 | - [Does using `await` always involve a microtask?](https://stackoverflow.com/questions/61635992/does-using-await-always-involve-a-microtask) 84 | -------------------------------------------------------------------------------- /Questions-Answers/51.method.md: -------------------------------------------------------------------------------- 1 | # 51. method 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/method 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | // This is a trick question 15 | 16 | // case 1 17 | const obj1 = { 18 | foo() { 19 | console.log(super.foo()); 20 | }, 21 | }; 22 | 23 | Object.setPrototypeOf(obj1, { 24 | foo() { 25 | return 'bar'; 26 | }, 27 | }); 28 | 29 | obj1.foo(); 30 | 31 | // case 2 32 | 33 | const obj2 = { 34 | foo: function () { 35 | console.log(super.foo()); 36 | }, 37 | }; 38 | 39 | Object.setPrototypeOf(obj2, { 40 | foo() { 41 | return 'bar'; 42 | }, 43 | }); 44 | 45 | obj2.foo(); 46 | ``` 47 | 48 | # 49 | 50 | ### Answer 51 | 52 | ```js 53 | // case 1 54 | 55 | const obj1 = { 56 | foo() { 57 | console.log(super.foo()); 58 | }, 59 | }; 60 | 61 | Object.setPrototypeOf(obj1, { 62 | foo() { 63 | return 'bar'; 64 | }, 65 | }); 66 | 67 | obj1.foo(); // didn't run because of the error caused by the second case 68 | 69 | // case 2 70 | 71 | const obj2 = { 72 | foo: function () { 73 | console.log(super.foo()); 74 | }, 75 | }; 76 | 77 | Object.setPrototypeOf(obj2, { 78 | foo() { 79 | return 'bar'; 80 | }, 81 | }); 82 | 83 | obj2.foo(); // Error: 'super' keyword unexpected here 84 | ``` 85 | 86 | ### Explanation 87 | 88 | We can use either the ES6 shorthand syntax `propertyName() {}` or `propertyName: function() {}` to define "methods" on object literals. However, they are not fully identical. Only the shorthand syntax `propertyName() {}` is a [Method Definition](https://262.ecma-international.org/6.0/#sec-method-definitions). `propertyName: function() {}` is just a property, not a method. In JavaScript, starting with ES6, a method is defined as a function that has an internal `[[HomeObject]]` property containing the object to which the method belongs. The `[[HomeObject]]` property is used by `super` to resolve the parent prototype and its methods. 89 | 90 | # 91 | 92 | ### Reference 93 | 94 | - [super keyword unexpected here](https://stackoverflow.com/questions/39263358/super-keyword-unexpected-here) 95 | - [A Formal Method Definition](https://leanpub.com/understandinges6/read/#leanpub-auto-a-formal-method-definition) 96 | - [Super: internals, [[HomeObject]]](https://javascript.info/class-inheritance#super-internals-homeobject) 97 | -------------------------------------------------------------------------------- /Questions-Answers/52.requestAnimationFrame.md: -------------------------------------------------------------------------------- 1 | # 52. requestAnimationFrame 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/requestanimationframe 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | console.log(1); 15 | 16 | setTimeout(() => { 17 | console.log(2); 18 | }, 100); 19 | 20 | requestAnimationFrame(() => { 21 | console.log(3); 22 | }); 23 | 24 | requestAnimationFrame(() => { 25 | console.log(4); 26 | setTimeout(() => { 27 | console.log(5); 28 | }, 10); 29 | }); 30 | 31 | const end = Date.now() + 200; 32 | while (Date.now() < end) {} 33 | 34 | console.log(6); 35 | ``` 36 | 37 | # 38 | 39 | ### Answer 40 | 41 | ``` 42 | 1 43 | 6 44 | 3 45 | 4 46 | 2 47 | 5 48 | ``` 49 | 50 | ### Explanation 51 | 52 | The browser executes all queued `requestAnimationFrame` callbacks just before it repaints the page. Typically the browser repaints the page 60 times per second, if it is not blocked by the running task. The order of execution is specified in the [Event Loop Processing Model](https://html.spec.whatwg.org/multipage/webappapis.html#event-loop-processing-model) section: 53 | 54 | 1. Do the oldest macrotask 55 | 56 | 2. Do microtasks 57 | 58 | 3. If it is a good time to render: 59 | 60 | 1. Do preparation work 61 | 62 | 2. Run `requestAnimationFrame` callbacks 63 | 64 | 3. Render 65 | 66 | Thus the console logs `3` and `4` before `2` and `5`. 67 | 68 | The console logs `2` before `5` is because of the `while` loop. Even though the loop body is empty, the rest of the code has to wait for the while loop to finish before they can execute, which means it blocks the browser from repainting the page(?). When we remove the `while` loop, the console logs `5` before `2`: https://jsitor.com/WaSG_fzH3 69 | 70 | ```js 71 | console.log(1); 72 | 73 | setTimeout(() => { 74 | console.log(2); 75 | }, 100); 76 | 77 | requestAnimationFrame(() => { 78 | console.log(3); 79 | }); 80 | 81 | requestAnimationFrame(() => { 82 | console.log(4); 83 | setTimeout(() => { 84 | console.log(5); 85 | }, 10); 86 | }); 87 | 88 | const end = Date.now() + 200; 89 | while (Date.now() < end) { 90 | console.log('while loop runs'); 91 | } 92 | 93 | console.log(6); 94 | 95 | // logs: 96 | // 1 97 | // 5164 times: while loop runs 98 | // 6 99 | // 3 100 | // 4 101 | // 2 102 | // 5 103 | ``` 104 | 105 | # 106 | 107 | ### Reference 108 | 109 | [When will requestAnimationFrame be executed?](https://stackoverflow.com/questions/43050448/when-will-requestanimationframe-be-executed) 110 | -------------------------------------------------------------------------------- /Questions-Answers/53.Prototype-2.md: -------------------------------------------------------------------------------- 1 | # 53. Prototype 2 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/prototype2 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | function F() { 15 | this.foo = 'bar'; 16 | } 17 | 18 | const f = new F(); 19 | console.log(f.prototype); 20 | ``` 21 | 22 | # 23 | 24 | ### Answer 25 | 26 | ``` 27 | undefined 28 | ``` 29 | 30 | ### Explanation 31 | 32 | The `prototype` property is only available on functions, or more specifically, on `Function` objects. The value of the `prototype` property is an object containing a `constructor` property, which points to the original constructor function. When you create an object with `new`, `prototype` is the object that is used to build `__proto__`. Therefore, the object `f` doesn't have a `prototype` property, but a `__proto__` property, which is a reference to `F.prototype`. 33 | -------------------------------------------------------------------------------- /Questions-Answers/54.setTimeout-0ms.md: -------------------------------------------------------------------------------- 1 | # 54. setTimeout(0ms) 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/setTimeout-0ms 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | // This snippet's result may vary on browsers 15 | 16 | setTimeout(() => { 17 | console.log(2); 18 | }, 2); 19 | 20 | setTimeout(() => { 21 | console.log(1); 22 | }, 1); 23 | 24 | setTimeout(() => { 25 | console.log(0); 26 | }, 0); 27 | ``` 28 | 29 | # 30 | 31 | ### Answer 32 | 33 | For Chrome, Safari, Node.js 34 | 35 | ``` 36 | 1 37 | 0 38 | 2 39 | ``` 40 | 41 | For Firefox 42 | 43 | ``` 44 | 0 45 | 1 46 | 2 47 | ``` 48 | 49 | ### Explanation 50 | 51 | In Node.js, `setTimeout(fn, 0)` is converted to `setTimeout(fn, 1)`, so they are exactly the same. 52 | 53 | # 54 | 55 | ### Reference 56 | 57 | [What is the difference between setTimeout(fn, 0) and setTimeout(fn, 1)?](https://stackoverflow.com/questions/8341803/what-is-the-difference-between-settimeoutfn-0-and-settimeoutfn-1/37961816#37961816) 58 | -------------------------------------------------------------------------------- /Questions-Answers/55.sparse-array.md: -------------------------------------------------------------------------------- 1 | # 55. sparse array 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/sparse-array 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | const arr = [1, , , 2]; 15 | 16 | // forEach 17 | arr.forEach((i) => console.log(i)); 18 | 19 | // map 20 | console.log(arr.map((i) => i * 2)); 21 | 22 | // for ... of 23 | for (const i of arr) { 24 | console.log(i); 25 | } 26 | 27 | // spread 28 | console.log([...arr]); 29 | ``` 30 | 31 | # 32 | 33 | ### Answer 34 | 35 | ```js 36 | const arr = [1, , , 2]; 37 | 38 | // forEach 39 | arr.forEach((i) => console.log(i)); 40 | // logs: 1, 2 41 | // `Array.prototype.forEach()` skips these blank indices. 42 | 43 | // map 44 | console.log(arr.map((i) => i * 2)); 45 | // logs: [2, empty, empty, 4] 46 | // If the array which `Array.prototype.map()` is called upon is sparse, 47 | // resulting array will also be sparse, meaning that `Array.prototype.map()` 48 | // skips the blank indices in the sparse array. 49 | 50 | // for ... of 51 | for (const i of arr) { 52 | console.log(i); 53 | } 54 | // logs: 1, undefined, undefined, 2 55 | // for...of treats these blank indices as `undefined`. 56 | 57 | // spread 58 | console.log([...arr]); 59 | // logs: [1, undefined, undefined, 2] 60 | // Spread operator treats these blank indices as `undefined`. 61 | ``` 62 | -------------------------------------------------------------------------------- /Questions-Answers/56.to-primitive.md: -------------------------------------------------------------------------------- 1 | # 56. to primitive 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/primitive 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | // case 1 15 | const obj1 = { 16 | valueOf() { 17 | return 1; 18 | }, 19 | toString() { 20 | return '100'; 21 | }, 22 | }; 23 | 24 | console.log(obj1 + 1); 25 | console.log(parseInt(obj1)); 26 | 27 | // case 2 28 | const obj2 = { 29 | [Symbol.toPrimitive]() { 30 | return 200; 31 | }, 32 | 33 | valueOf() { 34 | return 1; 35 | }, 36 | toString() { 37 | return '100'; 38 | }, 39 | }; 40 | 41 | console.log(obj2 + 1); 42 | console.log(parseInt(obj2)); 43 | 44 | // case 3 45 | const obj3 = { 46 | toString() { 47 | return '100'; 48 | }, 49 | }; 50 | 51 | console.log(+obj3); 52 | console.log(obj3 + 1); 53 | console.log(parseInt(obj3)); 54 | 55 | // case 4 56 | const obj4 = { 57 | valueOf() { 58 | return 1; 59 | }, 60 | }; 61 | 62 | console.log(obj4 + 1); 63 | console.log(parseInt(obj4)); 64 | 65 | // case 5 66 | const obj5 = { 67 | [Symbol.toPrimitive](hint) { 68 | return hint === 'string' ? '100' : 1; 69 | }, 70 | }; 71 | 72 | console.log(obj5 + 1); 73 | console.log(parseInt(obj5)); 74 | ``` 75 | 76 | # 77 | 78 | ### Answer 79 | 80 | ```js 81 | /* ------- case 1 ------- */ 82 | 83 | const obj1 = { 84 | valueOf() { 85 | return 1; 86 | }, 87 | toString() { 88 | return '100'; 89 | }, 90 | }; 91 | 92 | console.log(obj1 + 1); // 2 93 | // JavaScript uses `obj1`'s `valueOf()` to convert the object to a primitive. 94 | 95 | console.log(parseInt(obj1)); // 100 96 | // `parseInt()` expects a string value. If the argument is not a string, 97 | // then it is converted to one. 98 | 99 | /* ------- case 2 ------- */ 100 | 101 | const obj2 = { 102 | [Symbol.toPrimitive]() { 103 | return 200; 104 | }, 105 | 106 | valueOf() { 107 | return 1; 108 | }, 109 | toString() { 110 | return '100'; 111 | }, 112 | }; 113 | 114 | console.log(obj2 + 1); // 201 115 | console.log(parseInt(obj2)); // 200 116 | // When converting an object to a primitive value, JavaScript will first 117 | // call the method `Symbol.toPrimitive` if it is present. 118 | // The `Symbol.toPrimitive` takes in a string argument `hint`, which 119 | // gives us fine-grained control over the result primitive value. 120 | 121 | /* ------- case 3 ------- */ 122 | 123 | const obj3 = { 124 | toString() { 125 | return '100'; 126 | }, 127 | }; 128 | 129 | console.log(+obj3); // 100 130 | console.log(obj3 + 1); // '1001' 131 | console.log(parseInt(obj3)); // 100 132 | 133 | /* ------- case 4 ------- */ 134 | 135 | const obj4 = { 136 | valueOf() { 137 | return 1; 138 | }, 139 | }; 140 | 141 | console.log(obj4 + 1); // 2 142 | console.log(parseInt(obj4)); // NaN 143 | 144 | /* ------- case 5 ------- */ 145 | 146 | const obj5 = { 147 | [Symbol.toPrimitive](hint) { 148 | return hint === 'string' ? '100' : 1; 149 | }, 150 | }; 151 | 152 | console.log(obj5 + 1); // 2 153 | console.log(parseInt(obj5)); // 100 154 | ``` 155 | 156 | # 157 | 158 | ### Reference 159 | 160 | - [parseInt()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt) 161 | - [Symbol.toPrimitive](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/toPrimitive) 162 | -------------------------------------------------------------------------------- /Questions-Answers/57.non-writable.md: -------------------------------------------------------------------------------- 1 | # 57. non-writable 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/inherit-writable-flag 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | const a = {}; 15 | Object.defineProperty(a, 'foo1', { 16 | value: 1, 17 | }); 18 | const b = Object.create(a); 19 | b.foo2 = 1; 20 | 21 | console.log(b.foo1); 22 | console.log(b.foo2); 23 | 24 | b.foo1 = 2; 25 | b.foo2 = 2; 26 | 27 | console.log(b.foo1); 28 | console.log(b.foo2); 29 | ``` 30 | 31 | # 32 | 33 | ### Answer 34 | 35 | ```js 36 | const a = {}; 37 | Object.defineProperty(a, 'foo1', { 38 | value: 1, 39 | }); 40 | const b = Object.create(a); 41 | b.foo2 = 1; 42 | 43 | console.log(b.foo1); // 1 44 | console.log(b.foo2); // 1 45 | 46 | b.foo1 = 2; 47 | b.foo2 = 2; 48 | 49 | console.log(b.foo1); // 1 50 | console.log(b.foo2); // 2 51 | ``` 52 | 53 | ### Explanation 54 | 55 | Values added by `Object.defineProperty()` are immutable and not enumerable. 56 | 57 | # 58 | 59 | ### Reference 60 | 61 | [Object.defineProperty()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty) 62 | -------------------------------------------------------------------------------- /Questions-Answers/58.inherit-getter-setter.md: -------------------------------------------------------------------------------- 1 | # 58. inherit getter setter 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/inherit-getter-setter 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | let val = 0; 15 | 16 | class A { 17 | set foo(_val) { 18 | val = _val; 19 | } 20 | get foo() { 21 | return val; 22 | } 23 | } 24 | 25 | class B extends A {} 26 | 27 | class C extends A { 28 | get foo() { 29 | return val; 30 | } 31 | } 32 | 33 | const b = new B(); 34 | console.log(b.foo); 35 | b.foo = 1; 36 | console.log(b.foo); 37 | 38 | const c = new C(); 39 | console.log(c.foo); 40 | c.foo = 2; 41 | console.log(c.foo); 42 | console.log(b.foo); 43 | ``` 44 | 45 | # 46 | 47 | ### Answer 48 | 49 | ```js 50 | let val = 0; 51 | 52 | class A { 53 | set foo(_val) { 54 | val = _val; 55 | } 56 | get foo() { 57 | return val; 58 | } 59 | } 60 | 61 | class B extends A {} 62 | 63 | class C extends A { 64 | get foo() { 65 | return val; 66 | } 67 | } 68 | 69 | const b = new B(); 70 | console.log(b.foo); // 0 71 | b.foo = 1; 72 | console.log(b.foo); // 1 73 | 74 | const c = new C(); 75 | console.log(c.foo); // 1 76 | c.foo = 2; 77 | console.log(c.foo); // 1 78 | console.log(b.foo); // 1 79 | ``` 80 | 81 | ### Explanation 82 | 83 | The reason that both `c.foo` and `b.foo` return `1` after setting `c.foo` to `2` is that when we override the `get` method of an attribute in an inherited class, `set` method must also be overridden, and vice versa, because if an object has own property, this property will be used and not an inherited one. 84 | 85 | ```js 86 | let val = 0; 87 | 88 | class A { 89 | set foo(_val) { 90 | val = _val; 91 | } 92 | get foo() { 93 | return val; 94 | } 95 | } 96 | 97 | class C extends A { 98 | get foo() { 99 | return val; 100 | } 101 | set foo(_val) { 102 | super.foo = _val; 103 | } 104 | } 105 | 106 | const c = new C(); 107 | console.log(c.foo); // 0 108 | c.foo = 2; 109 | console.log(c.foo); // 2 110 | ``` 111 | 112 | # 113 | 114 | ### Reference 115 | 116 | [Override a setter, and the getter must also be overridden](https://stackoverflow.com/questions/28950760/override-a-setter-and-the-getter-must-also-be-overridden?noredirect=1&lq=1) 117 | -------------------------------------------------------------------------------- /Questions-Answers/59.override-setter.md: -------------------------------------------------------------------------------- 1 | # 59. override setter 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/override-setter 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | class A { 15 | val = 1; 16 | get foo() { 17 | return this.val; 18 | } 19 | } 20 | 21 | class B { 22 | val = 2; 23 | set foo(val) { 24 | this.val = val; 25 | } 26 | } 27 | const a = new A(); 28 | const b = new B(); 29 | console.log(a.foo); 30 | console.log(b.foo); 31 | b.foo = 3; 32 | console.log(b.val); 33 | console.log(b.foo); 34 | ``` 35 | 36 | # 37 | 38 | ### Answer 39 | 40 | ```js 41 | class A { 42 | val = 1; 43 | get foo() { 44 | return this.val; 45 | } 46 | } 47 | 48 | class B { 49 | val = 2; 50 | set foo(val) { 51 | this.val = val; 52 | } 53 | } 54 | const a = new A(); 55 | const b = new B(); 56 | console.log(a.foo); // 1 57 | console.log(b.foo); // undefined 58 | b.foo = 3; 59 | console.log(b.val); // 3 60 | console.log(b.foo); // undefined 61 | ``` 62 | 63 | ### Explanation 64 | 65 | If a property is not defined in an object and only a setter for the property is defined, any attempt to access the property directly will return `undefined`. 66 | -------------------------------------------------------------------------------- /Questions-Answers/60.postMessage.md: -------------------------------------------------------------------------------- 1 | # 60. postMessage 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/postMessage 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | console.log(1); 15 | 16 | window.onmessage = () => { 17 | console.log(2); 18 | }; 19 | 20 | Promise.resolve().then(() => { 21 | console.log(3); 22 | }); 23 | 24 | setTimeout(() => { 25 | console.log(4); 26 | }, 0); 27 | 28 | console.log(5); 29 | 30 | window.postMessage(''); 31 | 32 | console.log(6); 33 | ``` 34 | 35 | # 36 | 37 | ### Answer 38 | 39 | ``` 40 | 1 41 | 5 42 | 6 43 | 3 44 | 2 45 | 4 46 | ``` 47 | 48 | # 49 | 50 | ### Reference 51 | 52 | https://html.spec.whatwg.org/multipage/web-messaging.html 53 | -------------------------------------------------------------------------------- /Questions-Answers/61.onClick.md: -------------------------------------------------------------------------------- 1 | # 61. onClick 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/messsage-channel-is-async 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | console.log(1); 15 | 16 | document.body.addEventListener('click', () => { 17 | console.log(2); 18 | }); 19 | 20 | Promise.resolve().then(() => { 21 | console.log(3); 22 | }); 23 | 24 | setTimeout(() => { 25 | console.log(4); 26 | }, 0); 27 | 28 | console.log(5); 29 | 30 | document.body.click(); 31 | 32 | console.log(6); 33 | ``` 34 | 35 | # 36 | 37 | ### Answer 38 | 39 | ``` 40 | 1 41 | 5 42 | 2 43 | 6 44 | 3 45 | 4 46 | ``` 47 | 48 | ### Explanation 49 | 50 | The `click` event is handled synchronously. 51 | -------------------------------------------------------------------------------- /Questions-Answers/62.MessageChannel.md: -------------------------------------------------------------------------------- 1 | # 62. MessageChannel 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/message-channel 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | console.log(1); 15 | 16 | const mc = new MessageChannel(); 17 | 18 | mc.port1.onmessage = () => { 19 | console.log(2); 20 | }; 21 | 22 | Promise.resolve().then(() => { 23 | console.log(3); 24 | }); 25 | 26 | setTimeout(() => { 27 | console.log(4); 28 | }, 0); 29 | 30 | console.log(5); 31 | 32 | mc.port2.postMessage(''); 33 | 34 | console.log(6); 35 | ``` 36 | 37 | # 38 | 39 | ### Answer 40 | 41 | ``` 42 | 1 43 | 5 44 | 6 45 | 3 46 | 2 47 | 4 48 | ``` 49 | 50 | # 51 | 52 | ### Reference 53 | 54 | - [MessageChannel()](https://developer.mozilla.org/en-US/docs/Web/API/MessageChannel/MessageChannel) 55 | - [Channel messaging](https://html.spec.whatwg.org/multipage/web-messaging.html#channel-messaging) 56 | -------------------------------------------------------------------------------- /Questions-Answers/64.reference-type.md: -------------------------------------------------------------------------------- 1 | # 64. reference type 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/reference-type 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | 14 | ```js 15 | const obj = { 16 | msg: 'BFE', 17 | foo() { 18 | console.log(this.msg) 19 | }, 20 | bar() { 21 | console.log('dev') 22 | } 23 | } 24 | 25 | obj.foo(); 26 | (obj.foo)(); 27 | (obj.foo || obj.bar)(); 28 | ``` 29 | 30 | # 31 | 32 | ### Answer 33 | 34 | 35 | ```js 36 | const obj = { 37 | msg: 'BFE', 38 | foo() { 39 | console.log(this.msg) 40 | }, 41 | bar() { 42 | console.log('dev') 43 | } 44 | } 45 | 46 | obj.foo(); // 'BFE' 47 | (obj.foo)(); // 'BFE' 48 | (obj.foo || obj.bar)(); // undefined 49 | ``` 50 | 51 | ### Explanation 52 | 53 | - `(obj.foo)();` returns `'BFE'`, because `(obj.foo)()` is identical to `obj.foo()`. The [grouping operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Grouping) only changes expression priority and doesn't trigger extra expression value return. 54 | 55 | - `(obj.foo || obj.bar)()` returns `undefined`, because the [grouping operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Grouping) changes expression priority, so the `obj.foo || obj.bar` is evaluated first and the function call becomes secondary, `obj.foo || obj.bar` returns `function() { console.log(this.msg) }`, which `obj.foo` points to, and then `function() { console.log(this.msg) }` gets invoked, since it is a plain, undecorated function invocation, `this` refers to the global object and `undefined` is returned. 56 | -------------------------------------------------------------------------------- /Questions-Answers/65.Function-name.md: -------------------------------------------------------------------------------- 1 | # 65. Function name 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/Function-name 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | var foo = function bar() { 15 | return 'BFE'; 16 | }; 17 | 18 | console.log(foo()); 19 | console.log(bar()); 20 | ``` 21 | 22 | # 23 | 24 | ### Answer 25 | 26 | ```js 27 | var foo = function bar() { 28 | return 'BFE'; 29 | }; 30 | 31 | console.log(foo()); // 'BFE' 32 | console.log(bar()); // Error 33 | ``` 34 | 35 | ### Explanation 36 | 37 | When we define a function using function expression, the variable that the function expression is assigned to will have a name property. If function name is omitted, it will be the variable name. If function name is present, it will be the function name. This name is local only to the function body. Thus trying to call `bar` in the globe scope ended up in an error, because `bar` is `undefined` in the globe scope. 38 | 39 | # 40 | 41 | ### Reference 42 | 43 | [Function expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/function) 44 | -------------------------------------------------------------------------------- /Questions-Answers/67.if.md: -------------------------------------------------------------------------------- 1 | # 67. if 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/if 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | if (true) { 15 | function foo() { 16 | console.log('BFE'); 17 | } 18 | } 19 | if (false) { 20 | function bar() { 21 | console.log('dev'); 22 | } 23 | } 24 | 25 | foo(); 26 | bar(); 27 | ``` 28 | 29 | # 30 | 31 | ### Answer 32 | 33 | ```js 34 | if (true) { 35 | function foo() { 36 | console.log('BFE'); 37 | } 38 | } 39 | if (false) { 40 | function bar() { 41 | console.log('dev'); 42 | } 43 | } 44 | 45 | // In Chrome and Firefox: 46 | foo(); // 'BFE' 47 | bar(); // Error 48 | 49 | // In Safari: 50 | foo(); // 'BFE' 51 | bar(); // 'dev' 52 | ``` 53 | 54 | ### Explanation 55 | 56 | When we define a function within an `if` statement, the result varies on browsers. In Chrome and Firefox, only the name of the function is hoisted, whereas in Safari, the function is hoisted. 57 | 58 | # 59 | 60 | ### Reference 61 | 62 | [Conditionally created functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function#conditionally_created_functions) 63 | -------------------------------------------------------------------------------- /Questions-Answers/68.if-II.md: -------------------------------------------------------------------------------- 1 | # 68. if II 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/if-II 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | if ( 15 | function foo() { 16 | console.log('BFE'); 17 | } 18 | ) { 19 | console.log('dev'); 20 | } 21 | foo(); 22 | ``` 23 | 24 | # 25 | 26 | ### Answer 27 | 28 | ``` 29 | "dev" 30 | Error 31 | ``` 32 | 33 | ### Explanation 34 | 35 | When a function is created inside an expression or inside another syntax construct, it is a function expression. So in the code snippet above, `function foo() {}` is a **named function expression**, where `foo` is the function name. It is similar to: 36 | 37 | ```js 38 | const bar = function foo() {}; 39 | ``` 40 | 41 | Since the function name `foo` is local only to the function body, trying to call `foo()` in the global scope 42 | ends up with the error: `foo is not defined`. 43 | 44 | # 45 | 46 | ### Reference 47 | 48 | - [Function definition inside the if condition is not defined in javascript](https://stackoverflow.com/questions/24751277/function-definition-inside-the-if-condition-is-not-defined-in-javascript) 49 | - [Function Expression vs Function Declaration](https://javascript.info/function-expressions#function-expression-vs-function-declaration) 50 | -------------------------------------------------------------------------------- /Questions-Answers/69.undefined.md: -------------------------------------------------------------------------------- 1 | # 69. undefined 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/undefined 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | function foo(a, b, undefined, undefined) { 15 | console.log('BFE.dev'); 16 | } 17 | console.log(foo.length); 18 | ``` 19 | 20 | # 21 | 22 | ### Answer 23 | 24 | ``` 25 | 4 26 | ``` 27 | 28 | ### Explanation 29 | 30 | Before ES 5, the global value of `undefined` could be overridden: 31 | 32 | ```js 33 | var undefined = 'bar'; 34 | ``` 35 | 36 | `function(value, undefined) {}` ensures that `undefined` is the authentic `undefined` value within the function. When the function gets called and only one argument is passed, the second parameter, called "undefined", will really be `undefined`. 37 | 38 | ```js 39 | // Before ES 5 40 | var undefined = 'bar'; 41 | function foo(undefined) { 42 | console.log(undefined); 43 | } 44 | 45 | foo(); // undefined 46 | foo(undefined); // 'bar' 47 | foo(10); // 10 48 | ``` 49 | 50 | # 51 | 52 | ### Reference 53 | 54 | [What does “undefined” parameter signify in a function definition](https://stackoverflow.com/questions/54487492/what-does-undefined-parameter-signify-in-a-function-definition?noredirect=1&lq=1) 55 | -------------------------------------------------------------------------------- /Questions-Answers/7.Increment-Operator.md: -------------------------------------------------------------------------------- 1 | # 7. Increment Operator 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/Increment-Operator 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | let a = 1; 15 | const b = ++a; 16 | const c = a++; 17 | console.log(a); 18 | console.log(b); 19 | console.log(c); 20 | ``` 21 | 22 | # 23 | 24 | ### Answer 25 | 26 | ```js 27 | let a = 1; 28 | const b = ++a; 29 | const c = a++; 30 | console.log(a); // 3 31 | console.log(b); // 2 32 | console.log(c); // 2 33 | ``` 34 | 35 | ### Explanation 36 | 37 | If the increment operator `++` precedes operand, the increment operator increments and return the value after incrementing. 38 | 39 | If the increment operator `++` comes after operand, the increment operator increments and return the value before incrementing. 40 | -------------------------------------------------------------------------------- /Questions-Answers/70.function.md: -------------------------------------------------------------------------------- 1 | # 70. function 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/function 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | function foo() { 15 | console.log(1); 16 | } 17 | var foo = 2; 18 | function foo() { 19 | console.log(3); 20 | } 21 | foo(); 22 | ``` 23 | 24 | # 25 | 26 | ### Answer 27 | 28 | ``` 29 | Error 30 | ``` 31 | 32 | ### Explanation 33 | 34 | Before code execution, function and `var` variable declarations are hoisted to the top of the scope in which they are declared. JavaScript first moves function declarations, then `var` variable declarations. The order of declarations doesn't matter. When a `var` variable and a function have the same name, the `var` variable declaration overrides the function declaration, thus the code snippet above ends up in error: "foo is not a function". 35 | -------------------------------------------------------------------------------- /Questions-Answers/71.two-way-generator.md: -------------------------------------------------------------------------------- 1 | # 71. two-way generator 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/generator-2-way 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | function* gen() { 15 | yield 2 * (yield 100); 16 | } 17 | 18 | const generator = gen(); 19 | console.log(generator.next().value); 20 | console.log(generator.next(1).value); 21 | console.log(generator.next(1).value); 22 | ``` 23 | 24 | # 25 | 26 | ### Answer 27 | 28 | ```js 29 | function* gen() { 30 | yield 2 * (yield 100); 31 | } 32 | 33 | const generator = gen(); 34 | console.log(generator.next().value); // 100 35 | console.log(generator.next(1).value); // 2 36 | console.log(generator.next(1).value); // undefined 37 | ``` 38 | 39 | ### Explanation 40 | 41 | On the first iteration (`generator.next().value`), the inner yield `yield 100` is resolved, so the console logs `100`. 42 | 43 | --- 44 | 45 | On the second iteration (`generator.next(1).value`), `generator.next(1)` passes `1` to the outer yield, so it is `yield 2 * 1` and logs `2`. When providing an argument to `.next()`, the argument becomes the result of `yield`. For example, in `variable = yield expression`, the value passed to `.next()` will be assigned to the `variable`. However, the value passed to `.next()` will be only assigned when resuming execution from a previous `yield`, the argument passed to the first call to `.next()` will be ignored. In other words, what you're passing in to `.next()` is being returned from the previous `yield`. 46 | 47 | Consider the following example: 48 | 49 | ```js 50 | function* gen() { 51 | const result = yield '2 + 2 = ?'; 52 | 53 | console.log(result); 54 | } 55 | 56 | const generator = gen(); 57 | 58 | const question = generator.next().value; 59 | console.log(question); // 2 + 2 = ? 60 | 61 | generator.next(4); // 4 62 | ``` 63 | 64 | ```js 65 | function* gen() { 66 | const result = yield '2 + 2 = ?'; 67 | 68 | console.log(result); 69 | } 70 | 71 | const generator = gen(); 72 | 73 | const question = generator.next(1).value; // Argument `1` is ignored. 74 | console.log(question); // 2 + 2 = ? 75 | 76 | generator.next(4); // 4 77 | ``` 78 | 79 | If we don't provide any argument to the second `.next()`, it will logs `undefined`: 80 | 81 | ```js 82 | function* gen() { 83 | const result = yield '2 + 2 = ?'; 84 | 85 | // yield result; 86 | console.log(result); 87 | } 88 | 89 | const generator = gen(); 90 | 91 | const question = generator.next().value; 92 | console.log(question); // 2 + 2 = ? 93 | 94 | // console.log(generator.next().value); // undefined 95 | generator.next(); // undefined 96 | ``` 97 | 98 | So, we can rewrite the code snippet from the problem as following: 99 | 100 | ```js 101 | function* gen() { 102 | const returnedFromYield = yield 100; 103 | yield 2 * returnedFromYield; 104 | } 105 | 106 | const generator = gen(); 107 | console.log(generator.next().value); // 100 108 | console.log(generator.next(1).value); // 2 109 | ``` 110 | 111 | --- 112 | 113 | The third `generator.next(1).value` returns `undefined`, because the end of the generator is reached. 114 | 115 | ```js 116 | function* gen() { 117 | yield 2 * (yield 100); 118 | } 119 | 120 | const generator = gen(); 121 | console.log(generator.next().value); // 100 122 | console.log(generator.next(1).value); // 2 123 | console.log(generator.next(1)); // { value: undefined, done: true } 124 | ``` 125 | 126 | If we have a `return` statement at the end of the generator function `gen()`, then the third `.next()` will return whatever the `return` statement returns: 127 | 128 | ```js 129 | function* gen() { 130 | yield 2 * (yield 100); 131 | return 'Final result'; 132 | } 133 | 134 | const generator = gen(); 135 | console.log(generator.next().value); // 100 136 | console.log(generator.next(1).value); // 2 137 | console.log(generator.next(1)); // { value: 'Final result', done: true } 138 | ``` 139 | 140 | If we assign `yield 2 * (yield 100)` to a variable and pass an argument to the third `.next()`, then it will return the argument: 141 | 142 | ```js 143 | function* gen() { 144 | const returnedFromYield = yield 2 * (yield 100); 145 | return `Final result: ${returnedFromYield}`; 146 | } 147 | 148 | const generator = gen(); 149 | console.log(generator.next().value); // 100 150 | console.log(generator.next(1).value); // 2 151 | console.log(generator.next(4).value); // Final result: 4 152 | ``` 153 | 154 | # 155 | 156 | ### Reference 157 | 158 | - [“yield” is a two-way street](https://javascript.info/generators#yield-is-a-two-way-street) 159 | - [How does Generator.next() processes its parameter?](https://stackoverflow.com/questions/37354461/how-does-generator-next-processes-its-parameter) 160 | -------------------------------------------------------------------------------- /Questions-Answers/72.Array-length.md: -------------------------------------------------------------------------------- 1 | # 72. Array length 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/array-length 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | class MyArray extends Array { 15 | get length() { 16 | return 3; 17 | } 18 | } 19 | 20 | const arr1 = new MyArray(10); 21 | console.log(arr1.length); 22 | 23 | const arr2 = new Array(10); 24 | console.log(arr2.length); 25 | ``` 26 | 27 | # 28 | 29 | ### Answer 30 | 31 | ``` 32 | 10 33 | 10 34 | ``` 35 | 36 | ### Explanation 37 | 38 | The behavior of array `length` property cannot be overwritten. 39 | -------------------------------------------------------------------------------- /Questions-Answers/73.window-name.md: -------------------------------------------------------------------------------- 1 | # 73. window name 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/window-name 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | var a = 1; 15 | (function () { 16 | console.log(a + this.a); 17 | var a = '2'; 18 | console.log(a + this.a); 19 | })(); 20 | 21 | var name = 1; 22 | (function () { 23 | console.log(name + this.name); 24 | var name = '2'; 25 | console.log(name + this.name); 26 | })(); 27 | ``` 28 | 29 | # 30 | 31 | ### Answer 32 | 33 | ```js 34 | var a = 1; 35 | (function () { 36 | console.log(a + this.a); // NaN 37 | var a = '2'; 38 | console.log(a + this.a); // "21" 39 | })(); 40 | 41 | var name = 1; 42 | (function () { 43 | console.log(name + this.name); // "undefined1" 44 | var name = '2'; 45 | console.log(name + this.name); // "21" 46 | })(); 47 | ``` 48 | 49 | ### Explanation 50 | 51 | ```js 52 | var a = 1; 53 | (function () { 54 | console.log(a + this.a); 55 | var a = '2'; 56 | console.log(a + this.a); 57 | })(); 58 | ``` 59 | 60 | 1. First, we initialize a variable called `a` to `1` using `var`. In the global scope, a variable declared with `var` is added as a property of global object. In our case, the global object is `window`. 61 | 62 | 2. Then, we declare an IIFE. Inside the IIFE, 63 | 64 | 1. first, we log `a + this.a`. Because `(function(){})()` is a plain, undecorated invocation, `this` refers to the global object, which is `window`, so `this.a` returns `1`. `a` returns `undefined`, because we declare a variable `a` with `var` in the next line and the variable declaration is hoisted to the top of the function scope. Thus `a + this.a` returns `NaN`. 65 | 66 | 2. then, we initialize the local variable `a` to `'2'`, so `a + this.a` in the next line evaluates to `'2' + 1`. If one of the operands is a string, the `+` operator tries string concatenation before numeric addition, thus `a + this.a` returns `'21'`. 67 | 68 | --- 69 | 70 | ```js 71 | var name = 1; 72 | (function () { 73 | console.log(name + this.name); // "undefined1" 74 | var name = '2'; 75 | console.log(name + this.name); // "21" 76 | })(); 77 | ``` 78 | 79 | The reason that the first `name + this.name` returns `'undefined1` is `window.name` converts all stored values to their string representations. For instance, 80 | 81 | ```js 82 | var name = { a: 1 }; 83 | 84 | console.log(window.name); // '[object Object]' 85 | ``` 86 | 87 | # 88 | 89 | ### Reference 90 | 91 | [Window.name](https://developer.mozilla.org/en-US/docs/Web/API/Window/name) 92 | -------------------------------------------------------------------------------- /Questions-Answers/74.Typed-Array-length.md: -------------------------------------------------------------------------------- 1 | # 74. Typed Array length 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/Typed-Array-length 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | class MyArray extends Uint8Array { 15 | get length() { 16 | return 3; 17 | } 18 | } 19 | 20 | const arr1 = new MyArray(10); 21 | console.log(arr1.length); 22 | 23 | const arr2 = new Uint8Array(10); 24 | console.log(arr2.length); 25 | ``` 26 | 27 | # 28 | 29 | ### Answer 30 | 31 | ```js 32 | class MyArray extends Uint8Array { 33 | get length() { 34 | return 3; 35 | } 36 | } 37 | 38 | const arr1 = new MyArray(10); 39 | console.log(arr1.length); // 3 40 | 41 | const arr2 = new Uint8Array(10); 42 | console.log(arr2.length); // 10 43 | ``` 44 | -------------------------------------------------------------------------------- /Questions-Answers/75.meaningless-calculation.md: -------------------------------------------------------------------------------- 1 | # 75. meaningless calculation 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/meaningless-calculation 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | 14 | ```js 15 | const num = +((~~!+[])+(~~!+[])+[]+(~~!+[])) 16 | console.log(num) 17 | ``` 18 | 19 | # 20 | 21 | ### Answer 22 | 23 | ``` 24 | 21 25 | ``` 26 | 27 | ### Explanation 28 | 29 | `+((~~!+[])+(~~!+[])+[]+(~~!+[]))` is equivalent to `+(~~!+[] + ~~!+[] + [] + ~~!+[])`. 30 | 31 | 1. First, JavaScript evaluates `~~!+[]`, starting with `+[]`. 32 | 33 | 1. `+[]` evaluates to `0`, because the unary plus `+` convert a operand into a number. When the operand is an array, the array is first converted to a string and then to a number. The empty array is first converted to `''`, then the empty string is converted to `0`. 34 | 35 | 2. Then `!0` evaluates to `true`, because the logical NOT(`!`) operator returns `true` if the operand is not a Boolean value and cannot be converted to `true`. 36 | 37 | 3. `~~` is a double [NOT bitwise operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_NOT). The first `~` operator forces the operand to an integer, then inverts the lowest 31 bits. Then the second `~` operator inverts the bits back, so we will get an integer. In our case, `~true` returns `-2`, then `~-2` returns `1`. 38 | 39 | 2. Now we get `1 + 1 + [] + 1`. JavaScript then evaluates from left to right. 40 | 41 | 1. `1 + 1 + [] + 1` = `2 + [] + 1`. 42 | 43 | 2. The empty array is converted to a string value: `''`. When one of the operands is a string, the addition operator `+` tries string concatenation before numeric addition. Therefore, we got `'2' + 1`. 44 | 45 | 3. Finally, `'2' + 1` returns `'21'`. 46 | 47 | # 48 | 49 | ### Reference 50 | 51 | [What does ~~ ("double tilde") do in Javascript?](https://stackoverflow.com/questions/4055633/what-does-double-tilde-do-in-javascript) 52 | -------------------------------------------------------------------------------- /Questions-Answers/76.const.md: -------------------------------------------------------------------------------- 1 | # 76. const 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/const 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | 14 | ```js 15 | function func() { 16 | const a = b = c = 1; 17 | } 18 | func(); 19 | console.log(typeof a, typeof b, typeof c); 20 | ``` 21 | 22 | # 23 | 24 | ### Answer 25 | 26 | ``` 27 | "undefined","number","number" 28 | ``` 29 | 30 | ### Explanation 31 | 32 | - `typeof a` returns `"undefined"`, because constants are block-scoped. We declared `a` with `const` inside the function `func()`, therefore `a` is local only to the `func() {}` block. When we access `a` outside of that scope, i.e., in the global scope, `a` is `undefined`. 33 | 34 | - `typeof b` and `typeof c` both return `"number"`, because `b` and `c` are declared globally. 35 | 36 | `const a = b = c = 1` is equivalent to the following: 37 | 38 | ```js 39 | c = 1; 40 | b = c; 41 | 42 | const a = b; 43 | ``` 44 | 45 | Since there are no declarations for `b` and `c`, both of them are created as global variables. Therefore, the code snippet in the problem statement is essentially the same as the following: 46 | 47 | ```js 48 | var b; 49 | var c; 50 | 51 | function func() { 52 | c = 1; 53 | b = c; 54 | 55 | const a = b; 56 | } 57 | func(); 58 | console.log(typeof a, typeof b, typeof c); 59 | ``` 60 | 61 | First, we call `func()`; `c` and `b` are assigned to `1`. Then we log the type of `b` and `c`. Since now `b` and `c` are pointing to the number value `1`, `typeof b` and `typeof c` return `"number"`. 62 | 63 | It's worth noting, when declaring a constant, we must specify its value in the same statement in which it is declared: 64 | 65 | ```js 66 | // throws an error 67 | // Uncaught SyntaxError: Missing initializer in const declaration 68 | 69 | const a; 70 | ``` 71 | 72 | # 73 | 74 | ### Reference 75 | 76 | [Initialization of several variables](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var#initialization_of_several_variables) 77 | -------------------------------------------------------------------------------- /Questions-Answers/77.parseInt-2.md: -------------------------------------------------------------------------------- 1 | # 77. parseInt 2 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/parseInt-2 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | console.log(parseInt(0.00001)); 15 | console.log(parseInt(0.000001)); 16 | console.log(parseInt(0.0000001)); 17 | console.log(parseInt('0x12')); 18 | console.log(parseInt('1e2')); 19 | ``` 20 | 21 | # 22 | 23 | ### Answer 24 | 25 | ```js 26 | console.log(parseInt(0.00001)); // 0 27 | console.log(parseInt(0.000001)); // 0 28 | 29 | console.log(parseInt(0.0000001)); // 1 30 | // If the input value is less than or equal to 1e-7 (0.0000001), `parseInt()` 31 | // returns `1`. 32 | 33 | console.log(parseInt('0x12')); // 18 34 | // If the input string starts with `"0x"`, `radix` is assumed to be `16`. 35 | // (12)₁₆ = (1 × 16¹) + (2 × 16⁰) = (18)₁₀ 36 | 37 | console.log(parseInt('1e2')); // 1 38 | // Since `"1e2"` is a string, `parseInt()` does not recognize exponential notation 39 | // and thus stops at the first letter. 40 | ``` 41 | 42 | # 43 | 44 | ### Reference 45 | 46 | - [parseInt()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt) 47 | 48 | - [parseInt('1e1') vs parseFloat('1e1')](https://stackoverflow.com/questions/31732983/parseint1e1-vs-parsefloat1e1) 49 | -------------------------------------------------------------------------------- /Questions-Answers/8.Implicit-Coercion-I.md: -------------------------------------------------------------------------------- 1 | # 8. Implicit Coercion I 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/Implicit-Conversion-1 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | console.log(Boolean('false')); 15 | console.log(Boolean(false)); 16 | console.log('3' + 1); 17 | console.log('3' - 1); 18 | console.log('3' - ' 02 '); 19 | console.log('3' * ' 02 '); 20 | console.log(Number('1')); 21 | console.log(Number('number')); 22 | console.log(Number(null)); 23 | console.log(Number(false)); 24 | ``` 25 | 26 | # 27 | 28 | ### Answer 29 | 30 | ```js 31 | console.log(Boolean('false')); // true 32 | console.log(Boolean(false)); // false 33 | console.log('3' + 1); // "31" 34 | console.log('3' - 1); // 2 35 | console.log('3' - ' 02 '); // 1 36 | console.log('3' * ' 02 '); // 6 37 | console.log(Number('1')); // 1 38 | console.log(Number('number')); // NaN 39 | console.log(Number(null)); // 0 40 | console.log(Number(false)); // 0 41 | ``` 42 | 43 | ### Explanation 44 | 45 | - When using `Boolean()` as a function, it converts the input value to a boolean value. Since `'false'` is a non-empty string, it evaluates to `true`. 46 | 47 | 🙋‍♀️🙋‍♂️ However, if we use `new Boolean()`, e.g. `new Boolean(false)`, a `Boolean` object will be created. Since any object of which the value is not `undefined` or `null`, evaluates to `true` when passed to a conditional statement. 48 | 49 | ```js 50 | var x = new Boolean(false); 51 | if (x) { 52 | // this code is executed 53 | } 54 | ``` 55 | 56 | - If the `+` operator is used with a string, it acts as the concatenation operator. When concatenating a number on to a string, the number will be converted to a string. 57 | - When using non-numeric operands with the arithmetic operators, JavaScript will attempt to convert it to a numeric value. 58 | -------------------------------------------------------------------------------- /Questions-Answers/9.null-and-undefined.md: -------------------------------------------------------------------------------- 1 | # 9. null and undefined 2 | 3 | ### Problem 4 | 5 | https://bigfrontend.dev/quiz/null-and-undefined 6 | 7 | # 8 | 9 | ### Problem Description 10 | 11 | What does the code snippet below output by `console.log`? 12 | 13 | ```js 14 | console.log(JSON.stringify([1, 2, null, 3])); 15 | console.log(JSON.stringify([1, 2, undefined, 3])); 16 | console.log(null === undefined); 17 | console.log(null == undefined); 18 | console.log(null == 0); 19 | console.log(null < 0); 20 | console.log(null > 0); 21 | console.log(null <= 0); 22 | console.log(null >= 0); 23 | console.log(undefined == 0); 24 | console.log(undefined < 0); 25 | console.log(undefined > 0); 26 | console.log(undefined <= 0); 27 | console.log(undefined >= 0); 28 | ``` 29 | 30 | # 31 | 32 | ### Answer 33 | 34 | ```js 35 | // `null` and `undefined` are not JSON values. If such values 36 | // are encountered in an array, they will be changed to `null`. 37 | console.log(JSON.stringify([1, 2, null, 3])); // "[1,2,null,3]" 38 | console.log(JSON.stringify([1, 2, undefined, 3])); // "[1,2,null,3]" 39 | 40 | console.log(null === undefined); // false 41 | 42 | // `null` is only comparable to `undefined` when using `==`. 43 | // Therefore `null == undefined` returns `true`, and `null == 0` 44 | // returns `false`. 45 | console.log(null == undefined); // true 46 | console.log(null == 0); // false 47 | 48 | // `>`, `<`, `>=` and `<=` perform type coercion with a hint type 49 | // of `Number`. Therefore `null` is converted to `0` before comparison. 50 | console.log(null < 0); // false 51 | console.log(null > 0); // false 52 | console.log(null <= 0); // true 53 | console.log(null >= 0); // true 54 | 55 | console.log(undefined == 0); // false 56 | 57 | // `undefined` becomes `NaN` when coerced to numeric type. 58 | console.log(undefined < 0); // false 59 | console.log(undefined > 0); // false 60 | console.log(undefined <= 0); // false 61 | console.log(undefined >= 0); // false 62 | ``` 63 | 64 | # 65 | 66 | ### Reference 67 | 68 | [Equality (==)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Equality) 69 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🚀 Javascript Internals 🔥 2 | 3 | Welcome to **Javascript Internals**! This repository is your backstage pass to the world of JavaScript, revealing the magic behind its core functions and features. Whether you're a coding wizard or a curious learner, this repo is packed with insights to supercharge your JavaScript skills. Let's dive in! 🌟 4 | 5 | ## 🌟 What You'll Find Here 6 | 7 | * **🔧 Core Functions**: Detailed recreations of built-in JavaScript functions like `Array.prototype.map`, `String.prototype.slice`, `Object.assign`, and more. 8 | * **📚 Data Structures**: In-depth explanations and implementations of fundamental data structures such as arrays, objects, and sets. 9 | * **🧠 Execution Contexts**: Insights into how JavaScript manages execution contexts, scope chains, and the call stack. 10 | * **⏳ Event Loop**: A thorough exploration of the event loop, task queues, and asynchronous programming. 11 | * **🗑️ Memory Management**: An overview of how JavaScript handles memory allocation, garbage collection, and optimization techniques. 12 | * **🏗️ Prototypes and Inheritance**: Clear explanations of prototype-based inheritance and how JavaScript handles object creation and property lookup. 13 | 14 | ## 🎯 Goals of This Repository 15 | 16 | 1. **Educational Resource**: Provide a clear and detailed educational resource for developers wanting to understand JavaScript beyond its syntax. 17 | 2. **Practical Examples**: Offer practical examples and implementations that can be directly tested and modified. 18 | 3. **Collaborative Learning**: Encourage collaboration and contributions from the community to continuously improve and expand the content. 19 | 20 | ## 🚀 Getting Started 21 | 22 | 1. **Clone the repository**: 23 | 24 | ```bash 25 | git clone https://github.com/Shaban-Eissa/Javascript-Internals 26 | ``` 27 | 28 | 2. **Navigate to the project directory**: 29 | 30 | ```bash 31 | cd Javascript-Internals 32 | ``` 33 | 34 | 3. **Explore the different modules** and run the examples to see the inner workings of JavaScript functions and features. 35 | 36 | ## 🤝 How to Contribute 37 | 38 | We welcome contributions! If you have insights, improvements, or new implementations, feel free to fork the repository and submit a pull request. Let's make this a vibrant, collaborative learning community. 39 | -------------------------------------------------------------------------------- /implement-String.prototype.slice.md: -------------------------------------------------------------------------------- 1 | # Implement String.prototype.slice 2 | 3 | ### Problem Description 4 | 5 | Implement your own version of the `String.prototype.slice` method in JavaScript. 6 | 7 | The `slice()` method extracts a section of a string and returns it as a new string, without modifying the original string. 8 | 9 | Your implementation should handle the following: 10 | 11 | - If `beginIndex` is greater than or equal to the length of the string, return an empty string. 12 | - If `endIndex` is omitted, extract until the end of the string. 13 | - Negative indices count back from the end of the string. 14 | - If `endIndex` is greater than the length of the string, extract until the end of the string. 15 | - Ensure the method works correctly for both positive and negative indices, and for edge cases where indices are out of bounds. 16 | 17 | ### Syntax 18 | 19 | ```js 20 | str.slice(beginIndex[, endIndex]) 21 | ``` 22 | 23 | # 24 | 25 | ### Solution 26 | ```js 27 | /** 28 | * Custom implementation of String.prototype.slice 29 | * 30 | * @param {string} str - The string to slice. 31 | * @param {number} beginIndex - The index at which to begin extraction. 32 | * @param {number} [endIndex] - The index before which to end extraction. 33 | * @return {string} - The extracted section of the string. 34 | */ 35 | function customSlice(str, beginIndex, endIndex) { 36 | // Ensure the beginIndex is within the bounds of the string length 37 | if (beginIndex < 0) { 38 | beginIndex = Math.max(str.length + beginIndex, 0); 39 | } else { 40 | beginIndex = Math.min(beginIndex, str.length); 41 | } 42 | 43 | // If endIndex is not provided, use the length of the string 44 | if (endIndex === undefined || endIndex > str.length) { 45 | endIndex = str.length; 46 | } else if (endIndex < 0) { 47 | endIndex = Math.max(str.length + endIndex, 0); 48 | } 49 | 50 | // Calculate the length of the substring 51 | const length = Math.max(endIndex - beginIndex, 0); 52 | 53 | // Build the sliced string 54 | let result = ''; 55 | for (let i = 0; i < length; i++) { 56 | result += str[beginIndex + i]; 57 | } 58 | 59 | return result; 60 | } 61 | 62 | // Usage 63 | 64 | console.log(customSlice("Hello, world!", 7, 12)); // Expected: "world" 65 | console.log(customSlice("Hello, world!", 7)); // Expected: "world!" 66 | console.log(customSlice("Hello, world!", -5, -1)); // Expected: "orld" 67 | console.log(customSlice("Hello, world!", -5)); // Expected: "orld!" 68 | console.log(customSlice("Hello, world!", 7, 7)); // Expected: "" 69 | console.log(customSlice("Hello, world!", 7, 6)); // Expected: "" 70 | console.log(customSlice("Hello, world!", 7, 100)); // Expected: "world!" 71 | console.log(customSlice("Hello, world!", 7, -100)); // Expected: "" 72 | console.log(customSlice("Hello, world!", -100, 7)); // Expected: "Hello, " 73 | console.log(customSlice("Hello, world!", 100, 7)); // Expected: "" 74 | console.log(customSlice("Hello, world!", -100, -100)); // Expected: "" 75 | console.log(customSlice("Hello, world!", 100, 100)); // Expected: "" 76 | console.log(customSlice("Hello, world!", -100, -100)); // Expected: "" 77 | console.log(customSlice("Hello, world!", 0, 0)); // Expected: "" 78 | console.log(customSlice("Hello, world!", 0, 1)); // Expected: "H" 79 | console.log(customSlice("Hello, world!", 0, 100)); // Expected: "Hello, world!" 80 | console.log(customSlice("Hello, world!", 0, -100)); // Expected: "" 81 | console.log(customSlice("Hello, world!", -100, 0)); // Expected: "" 82 | console.log(customSlice("Hello, world!", 0, -1)); // Expected: "Hello, world" 83 | console.log(customSlice("Hello, world!", -1, 0)); // Expected: "" 84 | console.log(customSlice("Hello, world!", -1, -1)); // Expected: "" 85 | console.log(customSlice("Hello, world!", -1, -100)); // Expected: "" 86 | console.log(customSlice("Hello, world!", -1, 100)); // Expected: "!" 87 | console.log(customSlice("Hello, world!", -1)); // Expected: "!" 88 | console.log(customSlice("Hello, world!", 0)); // Expected: "Hello, world!" 89 | console.log(customSlice("Hello, world!", 1)); // Expected: "ello, world!" 90 | ``` 91 | 92 | # 93 | 94 | ### Explanation 95 | 96 | The provided code is a custom implementation of the `String.prototype.slice` method in JavaScript. This method is used to extract a section of a string and return it as a new string, without modifying the original string. 97 | 98 | 99 | 1. The function takes three parameters: `str` the string to slice, `beginIndex` the index at which to begin extraction, and `endIndex` the index before which to end extraction. 100 | 101 | 2. The function first checks if `beginIndex` is less than 0. If it is, it adjusts `beginIndex` to count from the end of the string. If `beginIndex` is greater than the length of the string, it is set to the length of the string. 102 | 103 | 3. Next, the function checks if `endIndex` is provided. If it's not, or if it's greater than the length of the string, `endIndex` is set to the length of the string. If `endIndex` is less than 0, it is adjusted to count from the end of the string. 104 | 105 | 4. The function then calculates the length of the substring to be extracted. If `endIndex` is less than `beginIndex`, the length is set to 0. 106 | 107 | 5. Finally, the function builds the sliced string by iterating over the characters in the specified range and appending them to the result string. 108 | -------------------------------------------------------------------------------- /v8-performance-metrics/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /v8-performance-metrics/data/performance_metrics.csv: -------------------------------------------------------------------------------- 1 | "file","executionTime","bytecodeTime","heapUsed","heapTotal","optimizedFunctions","deoptimizedFunctions","garbageCollectionTime" 2 | "simpleLoop.js",230,0,4024224,5652480,11,10,35 3 | "complexCalculation.js",103,0,4093632,5652480,41,2,24 4 | "functionCalls.js",98,0,4152336,5652480,86,13,8 -------------------------------------------------------------------------------- /v8-performance-metrics/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "v8-jit-performance-metrics", 3 | "version": "1.0.0", 4 | "description": "A project to benchmark V8 and JIT performance metrics", 5 | "main": "server.js", 6 | "scripts": { 7 | "start": "node server.js", 8 | "benchmark": "node scripts/benchmark.js" 9 | }, 10 | "dependencies": { 11 | "chart.js": "^3.9.1", 12 | "chartjs-node-canvas": "^4.1.6", 13 | "express": "^4.17.1", 14 | "json2csv": "^5.0.6", 15 | "v8": "^0.1.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /v8-performance-metrics/samples/complexCalculation.js: -------------------------------------------------------------------------------- 1 | function complexCalculation() { 2 | let result = 0; 3 | for (let i = 1; i <= 1000; i++) { 4 | result += Math.sin(i) * Math.log(i); 5 | } 6 | return result; 7 | } 8 | 9 | console.log(complexCalculation()); 10 | -------------------------------------------------------------------------------- /v8-performance-metrics/samples/functionCalls.js: -------------------------------------------------------------------------------- 1 | function functionCalls() { 2 | function add(a, b) { 3 | return a + b; 4 | } 5 | 6 | let sum = 0; 7 | for (let i = 0; i < 100000; i++) { 8 | sum += add(i, i + 1); 9 | } 10 | return sum; 11 | } 12 | 13 | console.log(functionCalls()); 14 | -------------------------------------------------------------------------------- /v8-performance-metrics/samples/simpleLoop.js: -------------------------------------------------------------------------------- 1 | function simpleLoop() { 2 | let sum = 0; 3 | for (let i = 0; i < 1000000; i++) { 4 | sum += i; 5 | } 6 | return sum; 7 | } 8 | 9 | console.log(simpleLoop()); 10 | -------------------------------------------------------------------------------- /v8-performance-metrics/scripts/benchmark.js: -------------------------------------------------------------------------------- 1 | const { spawnSync } = require("child_process"); 2 | const fs = require("fs"); 3 | const { parse } = require("json2csv"); 4 | const v8 = require("v8"); 5 | 6 | function measureTime(file) { 7 | const start = process.hrtime.bigint(); 8 | 9 | // Run the script and measure total execution time 10 | const result = spawnSync("node", [`samples/${file}`], { encoding: "utf-8" }); 11 | const end = process.hrtime.bigint(); 12 | const executionTime = (end - start) / BigInt(1000000); // Convert to milliseconds 13 | 14 | // Measure bytecode generation time 15 | const bytecodeStart = process.hrtime.bigint(); 16 | const script = fs.readFileSync(`samples/${file}`, "utf-8"); 17 | new Function(script); 18 | const bytecodeEnd = process.hrtime.bigint(); 19 | const bytecodeTime = (bytecodeEnd - bytecodeStart) / BigInt(1000000); // Convert to milliseconds 20 | 21 | // Get V8 heap statistics 22 | const heapStats = v8.getHeapStatistics(); 23 | const heapUsed = heapStats.used_heap_size; 24 | const heapTotal = heapStats.total_heap_size; 25 | 26 | // Mock data for optimized and deoptimized function counts 27 | const optimizedFunctions = Math.floor(Math.random() * 100); 28 | const deoptimizedFunctions = Math.floor(Math.random() * 20); 29 | 30 | // Mock data for garbage collection time (in ms) 31 | const garbageCollectionTime = Math.floor(Math.random() * 50); 32 | 33 | return { 34 | file, 35 | executionTime: Number(executionTime), 36 | bytecodeTime: Number(bytecodeTime), // Include bytecode time 37 | heapUsed, 38 | heapTotal, 39 | optimizedFunctions, 40 | deoptimizedFunctions, 41 | garbageCollectionTime, 42 | }; 43 | } 44 | 45 | const files = ["simpleLoop.js", "complexCalculation.js", "functionCalls.js"]; 46 | const results = files.map(measureTime); 47 | 48 | // Save results to CSV 49 | const csv = parse(results, { 50 | fields: [ 51 | "file", 52 | "executionTime", 53 | "bytecodeTime", // Include bytecode time field 54 | "heapUsed", 55 | "heapTotal", 56 | "optimizedFunctions", 57 | "deoptimizedFunctions", 58 | "garbageCollectionTime", 59 | ], 60 | }); 61 | fs.writeFileSync("data/performance_metrics.csv", csv); 62 | 63 | console.log( 64 | "Benchmarking complete. Results saved to data/performance_metrics.csv" 65 | ); 66 | -------------------------------------------------------------------------------- /v8-performance-metrics/server.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const path = require("path"); 3 | 4 | const app = express(); 5 | const port = 3000; 6 | 7 | // Serve static files from the root directory 8 | app.use(express.static(path.join(__dirname))); 9 | 10 | // Serve the index.html file 11 | app.get("/", (req, res) => { 12 | res.sendFile(path.join(__dirname, "index.html")); 13 | }); 14 | 15 | app.listen(port, () => { 16 | console.log(`Server is running at http://localhost:${port}`); 17 | }); 18 | --------------------------------------------------------------------------------