This post will cover the JavaScript questions I have encountered and have seen during my programming career. They will mainly focus on vanilla JavaScript though there are lots of excellent frameworks out there and many people are using them in their daily work.
this keyword
this keyword is an very important but easy to confuse concept in JavaScript since it is always referring to the calling object of the function.
1. What will be the output of below code snippet?
function User(name) {
this.name = name;
this.display = function(){
console.log(this.name);
}
}
var user = new User("javascript");
setTimeout(user.display,0);
setTimeout(function(){user.display();},0);
Will it print javascript twice? The answer is no. It will print undefined and then javascript. The reason behind this is that in the first setTimeout() call, the function reference is passed to it as a parameter and it starts to execute immediately. Since it's just a function reference so this function is actually bind to the outer scope object which is window in a browser environment. Hence when executing the display function, the this keyword will refer to the window object and there is no name defined for window, hence the output will be undefined.
However, for the second setTimeout() call, since an anonymous function is passed as a parameter and its function body contains the statement user.display() where the display() function is called on user object. Since user object has name set as javascript and its output will be javascript.
To make the above two setTimeout function to display javascript, what can we do? Basically we u=just need to change the definition of display() function to a lambda expression. See below code
function User(name) {
this.name = name;
this.display = () => {
console.log(this.name);
}
}
var user = new User("javascript");
setTimeout(user.display,0);
setTimeout(function(){user.display();},0);
The reason why this works is that an arrow function does not have its own this. The this value of the enclosing lexical scope is used; arrow functions follow the normal variable lookup rules. So while searching for this which is not present in current scope they end up finding this from its enclosing scope.
Closure concept
1. What will be the output of below script after the for loop execution?
for(var i = 1; i <= 5; i++) {
setTimeout(function(){
console.log(i);
},0);
}
Will it be 1, 2,3,4,5? The answer will be it prints 6 for 5 times. This is because that all the functions to be executed in setTimeout() will be queued up until the for loop execution completes. Thereafter when those functions start to execute, the i value has been set to 6 already. So they will print 6 for 5 times. The reason why the for loop will execute first is that JavaScript is single threaded and all functions set in setTimeout or setInterval will be put in a queue when there is free timeslot for executing them. Hence these functions will wait until the for loop execution completes.
To make the code to print 1,2,3,4,5, we need to use some closure to make the value evaluated and passed to the function call.
for(var i = 1; i <= 5; i++) {
setTimeout(function(i){
return function(){
console.log(i);
}
}(i),0);
}
Or another option is to use let instead of var to define the i variable.
for(let i = 1; i <= 5; i++) {
setTimeout(function(){
console.log(i);
},0);
}
Since let defines a block level variable which means it will only be accessible within the block. Hence every time when the for loop runs, it actually creates a new local variable and assigns the value to it. So when later the functions in setTimeout get executed, the i will actually refer to the local variable created in the block level.
Data type conversion
1. What will the value of below two array addition?
var a = [1,2];
var b = [3,4];
console.log(a + b);
Are you expecting to see a new array of [1,2,3,4]? Unfortunately the answer will be a string 1,23,4. This is about how JavaScript handles object addition. For string addition, it's simple that it will just concatenate the strings. And for numbers, it will just do math addition. But for objects, the object will first be converted to primitive. Which means it will first call toPrimitive(), this would internally either call valueOf() or toString(), in this case, a will become 1,2 and b will come 3,4 and then these two strings will be concatenated and form 1,23,4. For more details, you can refer to + operation on JavaScript objects.
2. Can a == true && a == false be true in JavaScript?
The answer is yes. JavaScript is not a strong typed language and when comparing an object with a boolean value, the object will be converted based on some rules. Below code can return true.
const a = {
num: 1,
valueOf: function(){
return this.num--;
}
};
console.log(a == true && a== false);
Since a is an object, when it tries to convert the value to a primitive, it will call toPrimitive() and it will then call valueOf() internally. Hence when the first valueOf() is called, the return value will be 1 and it is considered as true. Then when comparing a == false, it will call valueOf() again and now it will return 0 and hence will be considered as false. So both comparisons will be true in this case. For more details on how the conversion is done. Please refer to Can a == true && a == false be true in JavaScript?
3. What is a possible input to make the return value true for below function?
function magic_length(input) {
return input.length == 10 && input == ",,,,,,,,,";
}
One possible value is [undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined]
, and it can also be ["","","","","","","","","",""]
.
The length is 10 is easy to understand as it is an array of ten elements. The second one involves how JavaScript converts an array into a string. Based on ECMAScript standard, when comparing an array with a string, input will be converted to string by ToPrimitive(input). in the end, the toString method of array will be called. toString joins the array and returns one string containing each array element separated by commas. Also, undefined will be converted to empty string. Hence, ,,,,,,,,, actually comes from the commas used to separate the elements.
Syntax
1. The evolving history of callbacks?
JavaScript is single threaded. To achieve asynchronous like effect, setTimeout()/setInterval() maybe needed. Since these operations are not executing in sequence, then they would be a potential issue is that how data gets synced. Assume there is a long running process may need a bit time to run and the normal process shouldn't be blocked but some operations later depend on the output of setTimeout() function. In this case, a callback maybe needed so that it can be invoked when the function in setTimeout() completes. But this approach has a problem is its code will become unreadable if there are too many callbacks in a nested call chain.
// callback
function callback(name){
console.log("callback name: " + name);
}
setTimeout(function(cb){
let name = "test";
cb(name);
}(callback), 0);
Hence there comes the promise, from its name, it ensures that the function either in then() or catch() would be invoked when resolving or rejection happens. This approach makes the code more intuitive to understand.
// promise
function callback(name){
console.log("callback name: " + name);
}
let promise = new Promise(function(resolve, reject){
setTimeout(function(){
resolve("promise");
}, 1000);
});
promise.then(function(name){
callback(name);
}).catch(function(error){
console.error(error);
});
In ECMAScript 2017 specification, there is even further update to this mechanism. It introduces two new keywords: async and await. These two will enable you to write async code just like normal sequential code. async and await indeed are promised based.
// async/await
function callback(name){
console.log("callback name: " + name);
}
var promise = new Promise(function(resolve, reject){
setTimeout(function(){
resolve("promise");
}, 1000);
});
async function run(){
try {
name = await promise;
} catch (ex) {
console.log("error");
}
callback(name);
}
run();
2. Can you explain why a.x is undefined in below code snippet?
var a = {n: 1};
var b = a;
a.x = a = {n: 2};
console.log(a.x);//undefined
Let's analyze them statement by statement. At the beginning, a is assigned with an object which means a is pointing the a memory address storing object {n:1}, then a is assigned to another variable b, this means that both a and b are pointing to the object {n:1}.
Now the third line is very important, it is a consecutive assignment. According to JavaScript syntax, a.x is undefined at the moment and pointing to some memory address. Then {n:2} is assigned to a which indicates that a now is pointing to a new memory address storing object {n:2}, and the original a.x is now being assigned with the {n:2} object address and it's pointing from undefined to this new memory address.
Now since a is pointing to {n:2} and it has no x property defined. This leads to a.x as undefined. Now do you know what's the value of b? You can test it out.
The list will keep updating. Please stay tuned. The next step is a coding interview. If you are up to get a new job as JavaScript developer, check the top coding interview tools to be prepared