Interview - JavaScript
What is function composition
"Function Composition" is applying one function to the results of another. ie: f(g(x))
for (var i = 0; i < 5; i++) { var btn = document.createElement('button'); btn.appendChild(document.createTextNode('Button ' + i)); btn.addEventListener('click', function(){ console.log(i); }); document.body.appendChild(btn); }
(a) No matter what button the user clicks the number 5 will always be logged to the console. This is because, at the point that the onclick method is invoked (for any of the buttons), the for loop has already completed and the variable i already has a value of 5. (Bonus points for the interviewee if they know enough to talk about how execution contexts, variable objects, activation objects, and the internal "scope" property contribute to the closure behavior.) for (let i = 0; i < 5; i++) { var btn = document.createElement('button'); btn.appendChild(document.createTextNode('Button ' + i)); btn.addEventListener('click', function(){ console.log(i); }); document.body.appendChild(btn); }
What is IIFEs (Immediately Invoked Function Expressions)?
(function IIFE(){ console.log( "Hello!" ); })(); // "Hello!"
console.log("0 || 1 = "+(0 || 1)); console.log("1 || 2 = "+(1 || 2)); console.log("0 && 1 = "+(0 && 1)); console.log("1 && 2 = "+(1 && 2));
0 || 1 = 1 1 || 2 = 1 0 && 1 = 0 1 && 2 = 2
console.log(0.1 + 0.2); console.log(0.1 + 0.2 == 0.3);
0.30000000000000004 false Because floating point is unreliable
What will be the output of the following code? var x = 1; var output = (function() { delete x; return x; })(); console.log(output);
1 Above code will output 1 as output. delete operator is used to delete property from object. Here x is not an object it's global variable of type number.
(function () { try { throw new Error(); } catch (x) { var x = 1, y = 2; console.log(x); } console.log(x); console.log(y); })();
1 undefined 2 var statements are hoisted (without their value initialization) to the top of the global or function scope it belongs to, even when it's inside a with or catch block. However, the error's identifier is only visible inside the catch block. It is equivalent to: (function () { var x, y; // outer and hoisted try { throw new Error(); } catch (x /* inner */) { x = 1; // inner x, not the outer one y = 2; // there is only one y, which is in the outer scope console.log(x /* inner */); } console.log(x); console.log(y); })();
What is the "new" keyword in JavaScript?
1. It creates a new object. The type of this object is simply object. 2. It sets this new object's internal, inaccessible, [[prototype]] (i.e.__proto__) property to be the constructor function's external, accessible, prototype object (every function object automatically has a prototype property). 3. It makes the this variable point to the newly created object. 4. It executes the constructor function, using the newly created object whenever this is mentioned. 5. It returns the newly created object, unless the constructor function returns a non-null object reference. In this case, that object reference is returned instead.
What is a higher order function?
A function that takes in a function as a parameter, or returns a function as a result
When would you use the "bind" function?
A good use of the bind function is when you have a particular function that you want to call with a specific this value. You can then use bind to pass a specific object to a function that uses a this reference.
What is the difference between a shim and a polyfill?
A shim is any piece of code that performs interception of an API call and provides a layer of abstraction. It isn't necessarily restricted to a web application or HTML5/CSS3. A polyfill is a type of shim that retrofits legacy browsers with modern HTML5/CSS3 features usually using Javascript or Flash.
What is type conversion?
A type conversion turns one type of object into another.
Describe the Revealing Module Pattern design pattern
A variation of the module pattern is called the Revealing Module Pattern. The purpose is to maintain encapsulation and reveal certain variables and methods returned in an object literal. The direct implementation looks like this: var Exposer = (function() { var privateVariable = 10; var privateMethod = function() { console.log('Inside a private method!'); privateVariable++; } var methodToExpose = function() { console.log('This is a method I want to expose!'); } var otherMethodIWantToExpose = function() { privateMethod(); } return { first: methodToExpose, second: otherMethodIWantToExpose }; })(); Exposer.first(); // Output: This is a method I want to expose! Exposer.second(); // Output: Inside a private method! Exposer.methodToExpose; // undefined
What is a template literal?
A way to concatenate strings in JS (ES6). Easier to work with than a bunch of strings concatenated wit '+'. Example: var greet = `Hello ${name}`;
What is a potential pitfall with using typeof bar === "object" to determine if bar is an object? How can this pitfall be avoided?
Although typeof bar === "object" is a reliable way of checking if bar is an object, the surprising gotcha in JavaScript is that null is also considered an object! Therefore, the following code will, to the surprise of most developers, log true (not false) to the console: var bar = null; console.log(typeof bar === "object"); // logs true!
How would you add your own method to the Array object?
Array.prototype.average = function() { // calculate sum var sum = this.reduce(function(prev, cur) { return prev + cur; }); // return sum divided by number of elements return sum / this.length; }
What is the difference between asynchronous and synchronous code?
Asynchronous is non-blocking. Synchronous is blocking.
What is the difference between classical inheritance and prototypal inheritance?
Class Inheritance: instances inherit from classes (like a blueprint — a description of the class), and create sub-class relationships: hierarchical class taxonomies. Instances are typically instantiated via constructor functions with the new keyword. Class inheritance may or may not use the class keyword from ES6. There are two entities (classes and objects) and two kinds of relationships between entities (the instance-of relationship between an object and a class and the subclass-of relationship between classes). Prototypal Inheritance: instances inherit directly from other objects. Instances are typically instantiated via factory functions or Object.create(). Instances may be composed from many different objects, allowing for easy selective inheritance. There is only one kind of entity (the object) and one relationship between entities (the prototype-of relationship between objects). However, the conceptual difference between subclassing and instantiating still exists. One advantage of prototypal inheritance is that you can start with objects and introduce abstractions later. In class-based languages you normally need a class to produce an object, even if it is just a single one (hence the singleton pattern, as a work-around).
for (var i = 0; i < 5; i++) { setTimeout(function() { console.log(i); }, i * 1000 ); }
Closures can be used to prevent this problem by creating a unique scope for each iteration, storing each unique value of the variable within its scope, as follows: for (var i = 0; i < 5; i++) { (function(x) { setTimeout(function() { console.log(x); }, x * 1000 ); })(i); }
What is the difference between declared and initialized variables?
Declared: var a; Initialized: var a = 100; or: a = 100; (if declared)
What is a destructuring assignment?
Destructuring is a JavaScript expression that makes it possible to unpack values from arrays, or properties from objects, into distinct variables. That is, we can extract data from arrays and objects and assign them to variables. const {foo} = { foo: 12 } // foo = 12 const [foo,bar] = [1,2,3,4] // foo = 1 // bar = 2
What is the difference between for...in and for...of
Difference for..in and for..of: Both for..in and for..of are looping constructs which are used to iterate over data structures. The only difference is over what they iterate: for..in iterates over all enumerable property keys of an object for..of iterates over the values of an iterable object. Examples of iterable objects are arrays, strings, and NodeLists. Example: let arr = ['el1', 'el2', 'el3']; arr.addedProp = 'arrProp'; // elKey are the property keys for (let elKey in arr) { console.log(elKey); } // elValue are the property values for (let elValue of arr) { console.log(elValue) } In this example we can observe that the for..in loop iterates over the keys of the object, which is an array object in this example. The keys are 0, 1, 2 which correspond to the array elements we added and addedProp. This is how the arr array object looks in chrome devtools: You see that our for..in loop does nothing more than simply iterating over these values. The for..of loop in our example iterates over the values of a data structure. The values in this specific example are 'el1', 'el2', 'el3'. The values which an iterable data structure will return using for..of is dependent on the type of iterable object. For example an array will return the values of all the array elements whereas a string returns every individual character of the string.
Could you explain the difference between ES5 and ES6
ECMAScript 5 (ES5): The 5th edition of ECMAScript, standardized in 2009. This standard has been implemented fairly completely in all modern browsers ECMAScript 6 (ES6)/ ECMAScript 2015 (ES2015): The 6th edition of ECMAScript, standardized in 2015. This standard has been partially implemented in most modern browsers. - arrow functions - default params in functions - let - for-of - spread operator - module import/export
Could you explain the difference between ES5 and ES6
ECMAScript 5 (ES5): The 5th edition of ECMAScript, standardized in 2009. This standard has been implemented fairly completely in all modern browsers ECMAScript 6 (ES6)/ ECMAScript 2015 (ES2015): The 6th edition of ECMAScript, standardized in 2015. This standard has been partially implemented in most modern browsers. - arrow functions - default params in functions - let - for-of - spread operator - module import/export - destructing
Check if a given string is a isomorphic
For two strings to be isomorphic, all occurrences of a character in string A can be replaced with another character to get string B. The order of the characters must be preserved. There must be one-to-one mapping for ever char of string A to every char of string B. paper and title would return true. egg and sad would return false. dgg and add would return true
What is functional programming?
Functional programming involves using pure functions that avoid shared state, mutating data and side effects. It is declarative vs imperative;
What is Hoisting in JavaScript?
Hoisting is the JavaScript interpreter's action of moving all variable and function declarations to the top of the current scope. There are two types of hoisting: variable hoisting - rare function hoisting - more common
What is an IIFE
Immediately-invoked Function Expression let fooBar = (function foobar(bar) { this.foo = bar; return this.foo; // <--- must specify return })(10) console.log(fooBar()) // 10
What is the difference between imperative and declarative coding?
Imperative - Indirect way of giving instructions. "HOW" to do something. Declaritive - Direct way of giving instructions. "WHAT" to do.
for (let i = 0; i < 5; i++) { setTimeout(function() { console.log(i); }, i * 1000 ); }
It will print 0 1 2 3 4, because we use let instead of var here. The variable i is only seen in the for loop's block scope.
What is JavaScript?
JavaScript is a cross-platform, object-oriented scripting language used to make webpages interactive
What are derived data types?
JavaScript objects, including functions, arrays, and regular expressions
Describe the JS module design pattern
Modules should be Immediately-Invoked-Function-Expressions (IIFE) to allow for private scopes - that is, a closure that protect variables and methods (however, it will return an object instead of a function). This is what it looks like: (function() { // declare private variables and/or functions return { // declare public variables and/or functions } })(); Here we instantiate the private variables and/or functions before returning our object that we want to return. Code outside of our closure is unable to access these private variables since it is not in the same scope.
What are the benefits of arrow functions?
More concise code. Binds the context of the wrapping function's this to the context of the function that contains it.
var x = 21; var girl = function () { console.log(x); var x = 20; }; girl ();
Neither 21, nor 20, the result is undefined It's because JavaScript initialization is not hoisted. (Why doesn't it show the global value of 21? The reason is that when the function is executed, it checks that there's a local x variable present but doesn't yet declare it, so it won't look for global one.)
Are classes hoisted?
No, you must always specify a class above where it is instantiated.
What are the primitive data types?
Null, undefined, string, number, boolean, and symbol
var b = 1; function outer(){ var b = 2 function inner(){ b++; var b = 3; console.log(b) } inner(); } outer();
Output to the console will be "3".
var length = 10; function fn() { console.log(this.length); } var obj = { length: 5, method: function(fn) { fn(); arguments[0](); } }; obj.method(fn, 1);
Output: 10 2 Why isn't it 10 and 5? In the first place, as fn is passed as a parameter to the function method, the scope (this) of the function fn is window. var length = 10; is declared at the window level. It also can be accessed as window.length or length or this.length (when this === window.)
Assuming d is an "empty" object in scope, say: var d = {}; ...what is accomplished using the following code? [ 'zebra', 'horse' ].forEach(function(k) { d[k] = undefined; });
Running this code marks those properties as "own properties" of the object.
What are the built-in iterable objects?
String, Array, TypedArray, Map and Set
Explain the Prototype Design Pattern
The Prototype Pattern creates new objects, but rather than creating non-initialized objects it returns objects that are initialized with values it copied from a prototype - or sample - object. The Prototype pattern is also referred to as the Properties pattern.
What will the following code output to the console: console.log((function f(n){return ((n > 1) ? n * f(n-1) : n)})(10));
The code will output the value of 10 factorial (i.e., 10!, or 3,628,800). Here's why: The named function f() calls itself recursively, until it gets down to calling f(1) which simply returns 1. Here, therefore, is what this does: f(1): returns n, which is 1 f(2): returns 2 * f(1), which is 2 f(3): returns 3 * f(2), which is 6 f(4): returns 4 * f(3), which is 24 f(5): returns 5 * f(4), which is 120 f(6): returns 6 * f(5), which is 720 f(7): returns 7 * f(6), which is 5040 f(8): returns 8 * f(7), which is 40320 f(9): returns 9 * f(8), which is 362880 f(10): returns 10 * f(9), which is 3628800
var hero = { _name: 'John Doe', getSecretIdentity: function (){ return this._name; } }; var stoleSecretIdentity = hero.getSecretIdentity; console.log(stoleSecretIdentity()); console.log(hero.getSecretIdentity());
The code will output: undefined John Doe The first console.log prints undefined because we are extracting the method from the hero object, so stoleSecretIdentity() is being invoked in the global context (i.e., the window object) where the _name property does not exist. One way to fix the stoleSecretIdentity() function is as follows: var stoleSecretIdentity = hero.getSecretIdentity.bind(hero);
What is the value of typeof undefined == typeof NULL?
The expression will be evaluated to true, since NULL will be treated as any other undefined variable.
console.log(1 < 2 < 3); console.log(3 > 2 > 1);
The first statement returns true which is as expected. The second returns false because of how the engine works regarding operator associativity for < and >. It compares left to right, so 3 > 2 > 1 JavaScript translates to true > 1. true has value 1, so it then compares 1 > 1, which is false.
What is the difference between Object and Map
The keys of an Object are Strings and Symbols, whereas they can be any value for a Map, including functions, objects, and any primitive. The keys in Map are ordered while keys added to object are not. Thus, when iterating over it, a Map object returns keys in order of insertion. You can get the size of a Map easily with the size property, while the number of properties in an Object must be determined manually. A Map is an iterable and can thus be directly iterated, whereas iterating over an Object requires obtaining its keys in some fashion and iterating over them. An Object has a prototype, so there are default keys in the map that could collide with your keys if you're not careful. As of ES5 this can be bypassed by using map = Object.create(null), but this is seldom done. A Map may perform better in scenarios involving frequent addition and removal of key pairs.
var arr1 = "john".split(''); var arr2 = arr1.reverse(); var arr3 = "jones".split(''); arr2.push(arr3); console.log("array 1: length=" + arr1.length + " last=" + arr1.slice(-1)); console.log("array 2: length=" + arr2.length + " last=" + arr2.slice(-1));
The logged output will be: "array 1: length=5 last=j,o,n,e,s" "array 2: length=5 last=j,o,n,e,s" arr1 and arr2 are the same (i.e. ['n','h','o','j', ['j','o','n','e','s'] ]) after the above code is executed for the following reasons: Calling an array object's reverse() method doesn't only return the array in reverse order, it also reverses the order of the array itself (i.e., in this case, arr1). The reverse() method returns a reference to the array itself (i.e., in this case, arr1). As a result, arr2 is simply a reference to (rather than a copy of) arr1. Therefore, when anything is done to arr2 (i.e., when we invoke arr2.push(arr3);), arr1 will be affected as well since arr1 and arr2 are simply references to the same object. And a couple of side points here that can sometimes trip someone up in answering this question: Passing an array to the push() method of another array pushes that entire array as a single element onto the end of the array. As a result, the statement arr2.push(arr3); adds arr3 in its entirety as a single element to the end of arr2 (i.e., it does not concatenate the two arrays, that's what the concat() method is for). Like Python, JavaScript honors negative subscripts in calls to array methods like slice() as a way of referencing elements at the end of the array; e.g., a subscript of -1 indicates the last element in the array, and so on.
var a={}, b={key:'b'}, c={key:'c'}; a[b]=123; a[c]=456; console.log(a[b]);
The output of this code will be 456 (not 123). The reason for this is as follows: When setting an object property, JavaScript will implicitly stringify the parameter value. In this case, since b and c are both objects, they will both be converted to "[object Object]". As a result, a[b] anda[c] are both equivalent to a["[object Object]"] and can be used interchangeably. Therefore, setting or referencing a[c] is precisely the same as setting or referencing a[b].
(function(x) { return (function(y) { console.log(x); })(2) })(1);
The output will be 1, even though the value of x is never set in the inner function. Here's why: As explained in our JavaScript Hiring Guide, a closure is a function, along with all variables or functions that were in-scope at the time that the closure was created. In JavaScript, a closure is implemented as an "inner function"; i.e., a function defined within the body of another function. An important feature of closures is that an inner function still has access to the outer function's variables. Therefore, in this example, since x is not defined in the inner function, the scope of the outer function is searched for a defined variable x, which is found to have a value of 1.
The following recursive code will cause a stack overflow if the array list is too large. How can you fix this and still retain the recursive pattern? var list = readHugeList(); var nextListItem = function() { var item = list.pop(); if (item) { // process the list item... nextListItem(); } };
The potential stack overflow can be avoided by modifying the nextListItem function as follows: var list = readHugeList(); var nextListItem = function() { var item = list.pop(); if (item) { // process the list item... setTimeout( nextListItem, 0); } }; The stack overflow is eliminated because the event loop handles the recursion, not the call stack. When nextListItem runs, if item is not null, the timeout function (nextListItem) is pushed to the event queue and the function exits, thereby leaving the call stack clear. When the event queue runs its timed-out event, the next item is processed and a timer is set to again invoke nextListItem. Accordingly, the method is processed from start to finish without a direct recursive call, so the call stack remains clear, regardless of the number of iterations.
Q4: What does the term "Transpiling" stand for?
There's no way to polyfill new syntax that has been added to the language. So the better option is to use a tool that converts your newer code into older code equivalents. This process is commonly called transpiling, a term for transforming + compiling.
What is the significance of, and reason for, wrapping the entire content of a JavaScript source file in a function block?
This technique creates a closure around the entire contents of the file which, perhaps most importantly, creates a private namespace and thereby helps avoid potential name clashes between different JavaScript modules and libraries.
How would you create a private variable in JavaScript?
To create a private variable in JavaScript that cannot be changed you need to create it as a local variable within a function.
What is the difference between two-way binding and one-way data flow.
Two-way binding, UI and model data change together. One-way data flow - Single source of truth, changes to that single source of truth can only flow in one direction.
What is a closure?
When an inner function has access to the scope of an outer function after the outer function has finished execution.
Imagine you have this code: var a = [1, 2, 3]; a) Will this result in a crash? a[10] = 99; b) What will this output? console.log(a[6]);
a) It will not crash. The JavaScript engine will make array slots 3 through 9 be "empty slots." b) Here, a[6] will output undefined, but the slot still remains empty rather than filled with undefined. This may be an important nuance in some cases. For example, when using map(), empty slots will remain empty in map()'s output, but undefined slots will be remapped using the function passed to it: var b = [undefined]; b[2] = 1; console.log(b); // (3) [undefined, empty × 1, 1] console.log(b.map(e => 7)); // (3) [7, empty × 1, 7]
What is NaN? What is its type? How can you reliably test if a value is equal to NaN?
console.log(typeof NaN === "number"); // logs "true" or use Number.isNaN()
How do you merge two objects?
const obj1 = { a: 1, b: 2 } const obj2 = { a: 2, c: 3, d: 4} const obj3 = {...obj1, ...obj2} or Object.assign({foo:bar}, {newFoo: newBar})
What is currying?
currying transforms a function with multiple arguments into a sequence/series of functions each taking a single argument. add(1)(2)(3) (see image)
What will the following code output? 0.1 + 0.2 === 0.3
false Due to floating point errors
Consider the two functions below. Will they both return the same thing? Why or why not? function foo1() { return { bar: "hello" }; } function foo2() { return { bar: "hello" }; }
foo1 returns: Object {bar: "hello"} foo2 returns: undefined The reason for this has to do with the fact that semicolons are technically optional in JavaScript (although omitting them is generally really bad form). As a result, when the line containing the return statement (with nothing else on the line) is encountered in foo2(), a semicolon is automatically inserted immediately after the return statement.
How do you 'break out of': for...in for...of forEach for (loop) while
for...in - break for...of - break forEach - you CANT, use for...in or for...of instead for (loop) - break while - break
What is output? var double; function double(num) { return (num*2); } console.log(typeof double);
function because function declaration has precedence over variable declaration.
Discuss possible ways to write a function isInteger(x) that determines if x is an integer.
function isInteger(x) { return (x ^ 0) === x; } function isInteger(x) { return Math.round(x) === x; } function isInteger(x) { return (typeof x === 'number') && (x % 1 === 0); } INCORRECT: function isInteger(x) { return parseInt(x, 10) === x; }
Write a simple function (less than 160 characters) that returns a boolean indicating whether or not a string is a palindrome.
function isPalindrome(str) { str = str.replace(/\W/g, '').toLowerCase(); // all non-alpha to '' and then all lowercase return (str == str.split('').reverse().join('')); }
Write a sum method which will work properly when invoked using either syntax below. console.log(sum(2,3)); // Outputs 5 console.log(sum(2)(3)); // Outputs 5
function sum(x, y) { if (y !== undefined) { return x + y; } else { return function(y) { return x + y; }; } }
What is output? var double = 22; function double(num) { return (num*2); } console.log(typeof double);
number because variable assignment has precedence over function declaration
var myObject = { foo: "bar", func: function() { var self = this; console.log("outer func: this.foo = " + this.foo); console.log("outer func: self.foo = " + self.foo); (function() { console.log("inner func: this.foo = " + this.foo); console.log("inner func: self.foo = " + self.foo); }()); } }; myObject.func();
outer func: this.foo = bar outer func: self.foo = bar inner func: this.foo = undefined inner func: self.foo = bar In the outer function, both this and self refer to myObject and therefore both can properly reference and access foo. In the inner function, though, this no longer refers to myObject. As a result, this.foo is undefined in the inner function, whereas the reference to the local variable self remains in scope and is accessible there.
What would following code return? console.log(typeof typeof 1);
string
(function(){ var a = b = 3; })(); console.log("a defined? " + (typeof a !== 'undefined')); console.log("b defined? " + (typeof b !== 'undefined'));
var a = b = 3; is actually shorthand for: b = 3; var a = b; As a result (if you are not using strict mode), the output of the code snippet would be: a defined? false b defined? true
What is the difference between anonymous and named functions?
var foo = function() { // anonymous function assigned to variable foo // .. }; var x = function bar(){ // named function (bar) assigned to variable x // .. };
How do you add an element at the begining of an array? How do you add one at the end?
var myArray = ['a', 'b', 'c', 'd']; myArray.push('end'); myArray.unshift('start'); console.log(myArray); // ["start", "a", "b", "c", "d", "end"] With ES6, one can use the spread operator: myArray = ['start', ...myArray]; myArray = [...myArray, 'end']; Or, in short: myArray = ['start', ...myArray, 'end'];
How do you clone an object?
var obj = {a: 1 ,b: 2} var objclone = Object.assign({},obj);
what is the difference between object.create and object.assign
var target1 = {}, target2 = {}; var obj1 = Object.create(target1, {myProp: {value: 1}}); var obj2 = Object.assign(target2, {myProp: 1}); Prototypical chain Object.create creates a new object with the specified [[Prototype]], and Object.assignassigns the properties directly on the specified object: obj1 !== target1; obj2 === target2; The prototypical chains of obj1 and obj2 look like obj1 --> target1 --> Object.prototype --> null obj2 --------------> Object.prototype --> null Properties Object.create defines properties and Object.assign only assigns them. When creating a property, assignments will create it as configurable, writable and enumerable. When defining a property, you can specify those flags, but by default it's not configurable, nor writable and not enumerable. Object.getOwnPropertyDescriptor(obj1, 'myProp'); // { value: 1, writable: false, enumerable: false, configurable: false } Object.getOwnPropertyDescriptor(obj2, 'myProp'); // { value: 1, writable: true, enumerable
what is the difference between object.create and new
with new, the constructor is exceuted
What is the value of 'hoist': console.log(hoist); var hoist = 'The variable has been hoisted.';
undefined The hoist variable is declared, but not initialized at the point of console.log.
What are the differences between var and let?
var = sets value for scope of function where declared. s hoisted. let = Works within current enclosing block only. Cannot be hoisted
console.log(1 + "2" + "2"); console.log(1 + +"2" + "2"); console.log(1 + -"1" + "2"); console.log(+"1" + "1" + "2"); console.log( "A" - "B" + "2"); console.log( "A" - "B" + 2);
"122" "32" "02" "112" "NaN2" NaN The fundamental issue here is that JavaScript (ECMAScript) is a loosely typed language and it performs automatic type conversion on values to accommodate the operation being performed. Let's see how this plays out with each of the above examples. Example 1: 1 + "2" + "2" Outputs: "122" Explanation: The first operation to be performed in 1 + "2". Since one of the operands ("2") is a string, JavaScript assumes it needs to perform string concatenation and therefore converts the type of 1 to "1", 1 + "2" yields "12". Then, "12" + "2" yields "122". Example 2: 1 + +"2" + "2" Outputs: "32" Explanation: Based on order of operations, the first operation to be performed is +"2" (the extra + before the first "2" is treated as a unary operator). Thus, JavaScript converts the type of "2" to numeric and then applies the unary + sign to it (i.e., treats it as a positive number). As a result, the next operation is now 1 + 2 which of course yields 3. But then, we have an operation between a number and a string (i.e., 3 and "2"), so once again JavaScript converts the type of the numeric value to a string and performs string concatenation, yielding "32". Example 3: 1 + -"1" + "2" Outputs: "02" Explanation: The explanation here is identical to the prior example, except the unary operator is - rather than +. So "1" becomes 1, which then becomes -1 when the - is applied, which is then added to 1 yielding 0, which is then converted to a string and concatenated with the final "2" operand, yielding "02". Example 4: +"1" + "1" + "2" Outputs: "112" Explanation: Although the first "1" operand is typecast to a numeric value based on the unary + operator that precedes it, it is then immediately converted back to a string when it is concatenated with the second "1" operand, which is then concatenated with the final "2" operand, yielding the string "112". Example 5: "A" - "B" + "2" Outputs: "NaN2" Explanation: Since the - operator can not be applied to strings, and since neither "A" nor "B" can be converted to numeric values, "A" - "B" yields NaN which is then concatenated with the string "2" to yield "NaN2". Example 6: "A" - "B" + 2 Outputs: NaN Explanation: As exlained in the previous example, "A" - "B" yields NaN. But any operator applied to NaN with any other numeric operand will still yield NaN.
console.log(false == '0') console.log(false === '0')
true false