š¦ A curated list of javascript fundamentals and algorithms. Javascript is ā¤ļø
Maintained by: Sung Woo Park
##Table of Contents
Can you name two programming paradigms important for JavaScript app developers?
What is functional programming?
What is the difference between classical inheritance and prototypal inheritance?
What are the pros and cons of functional programming vs object-oriented programming?
When is classical inheritance an appropriate choice?
What does āfavor object composition over class inheritanceā mean?
What are two-way data binding and one-way data flow, and how are they different?
What are the pros and cons of monolithic vs microservice architectures?
What is asynchronous programming, and why is it important in JavaScript?
What is Javascript's hoisting?
What Is AMD, CommonJS, and UMD?
What is IIFE, or Immediately-Invoked Function Expression?
Explain why the following doesn't work as an IIFE:Ā function foo(){ }();
. What needs to be changed to properly make it an IIFE?
What's the difference between feature detection, feature inference, and using the UA string?
Explain AJAX in as much detail as possible-JavaScript. What are some advantages and disadvantages to using AJAX?
What's the difference between an "attribute" and a "property"?
Why is extending built-in JavaScript objects not a good idea?
What is a potential pitfall with using
typeof bar === "object"
to determine if bar is an object? How can this pitfall be avoided?
What isĀ NaN
? What is its type? How can you reliably test if a value is equal toĀ NaN
?
What will the code below output to the console and why ?
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);
What's the difference between using āletā and āvarā to declare a variable?
What's the difference between null
and undefined
?
#### 1.2.1
What will the code below output to the console and why?
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();
What is the significance of, and reason for, wrapping the entire content of a JavaScript source file in a function block?
Consider the following code snippet:
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) What gets logged to the console when the user clicks on āButton 4ā and why?
(b) Provide one or more alternate implementations that will work as expected.
What is a āclosureā in JavaScript? Provide an example.
What will be the output of the following code:
for (var i = 0; i < 5; i++) {
setTimeout(function() { console.log(i); }, i * 1000 );
}
Explain your answer. How could the use of closures help here?
Consider the code snippet below. What will the console output be and why?
(function(x) {
return (function(y) {
console.log(x);
})(2)
})(1);
What will the following code output to the console and why:
var hero = {
_name: 'John Doe',
getSecretIdentity: function (){
return this._name;
}
};
var stoleSecretIdentity = hero.getSecretIdentity;
console.log(stoleSecretIdentity());
console.log(hero.getSecretIdentity());
What is the issue with this code and how can it be fixed.
How and why would you use closure?
What is the significance, and what are the benefits, of includingĀ 'use strict'
Ā at the beginning of a JavaScript source file?
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"
};
}
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();
}
};
What will the code below output? Explain your answer.
console.log(0.1 + 0.2);
console.log(0.1 + 0.2 == 0.3);
Discuss possible ways to write a functionĀ isInteger(x)
Ā that determines ifĀ x
Ā is an integer.
In what order will the numbers 1-4 be logged to the console when the code below is executed? Why?
(function() {
console.log(1);
setTimeout(function(){console.log(2)}, 1000);
setTimeout(function(){console.log(3)}, 0);
console.log(4);
})();
What is Javascript's Event Bubbling and Capturing?
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
What will the following code output to the console:
console.log((function f(n){return ((n > 1) ? n * f(n-1) : n)})(10));
Explain your answer.
Difference between:Ā function Person(){}
,Ā var person = Person()
, andĀ var person = new Person()
?
What's the difference betweenĀ .call
Ā andĀ .apply
?
When would you useĀ document.write()
?
What will the code below output to the console and why?
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));
What would the following lines of code output to the console?
console.log("0 || 1 = "+(0 || 1));
console.log("1 || 2 = "+(1 || 2));
console.log("0 && 1 = "+(0 && 1));
console.log("1 && 2 = "+(1 && 2));
Explain your answer.
What will be the output when the following code is executed? Explain.
console.log(false == '0')
console.log(false === '0')
What is the output out of the following code? Explain your answer.
var a={},
b={key:'b'},
c={key:'c'};
a[b]=123;
a[c]=456;
console.log(a[b]);
Compare and contrast objects and hashtables in JavaScript.
What's the difference between host objects and native objects?
Create a function that, given a DOM Element on the page, will visit the element itself andĀ allĀ of its descendents (not just its immediate children). For each element visited, the function should pass that element to a provided callback function.
The arguments to the function should be:
- a DOM element
- a callback function (that takes a DOM element as its argument)
Given a node from a DOM tree find the node in the same position from an identical DOM tree. See diagram below for clarity.
A B
O O
|\ |\
O O O O
/|\ /|\
O O O O O O
\ \
O O
Describe inheritance and the prototype chain in JavaScript. Give an example.
When is prototypal inheritance an appropriate choice?
ExplainĀ Function.prototype.bind
Write a simple function (less than 80 characters) that returns a boolean indicating whether or not a string is aĀ palindrome.
Manually calculate the square root of a number with Javascript.
Can you write a function that deeply flattens an array?
//example
input = [0, 1, [2, 3], [[4, [5]]]];
output = [0, 1, 2, 3, 4, 5];
We have an array of objects A and an array of indexes B. Reorder objects in array A with given indexes in array B. Do not change array A's length.Ā
//example
var A = [C, D, E, F, G];
var B = [3, 0, 4, 1, 2];
sort(A, B);
// A is now [D, F, G, C, E];
Given a string Sting="ABCSC" Check whether it contains a Substring="ABC"?
-
If no , return "-1".Ā
-
If yes , remove the substring from string and return "SC".Ā
Given an arrayĀ nums
, write a function to move allĀ 0
's to the end of it while maintaining the relative order of the non-zero elements.
For example, givenĀ nums = [0, 1, 0, 3, 12]
, after calling your function,Ā nums
Ā should beĀ [1, 3, 12, 0, 0]
.
Note:
- You must do thisĀ in-placeĀ without making a copy of the array.
- Minimize the total number of operations.
Given an array of integers, every element appears twice except for one. Find that single one.
Note: Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?
Example :
Input : [1 2 2 3 1]
Output : 3
##Answers
JavaScript is a multi-paradigm language, supportingĀ imperative/proceduralĀ programming along withĀ OOPĀ (Object-Oriented Programming) andĀ functional programming. JavaScript supports OOP withĀ prototypal inheritance.
Javascript is Objects Linking to Other Objects (OLOO).
//imperative
function double (arr) {
let results = []
for (let i = 0; i < arr.length; i++){
results.push(arr[i] * 2)
}
return results
}
//functional
function double (arr) {
return arr.map((item) => item * 2)
}
//functional does not mutate any state, or information held in memory
Functional programming produces programs by composing mathematical functions and avoids shared state & mutable data. Pure functions don't mutate any state or data.
**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.
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.
- compositionĀ - your object contains another object, called its prototype, and
- delegationĀ - when you access a property on your object, if it's not directly defined on it, javascript will search the prototype chain and delegate that behavior to the first object it finds that defines that property.
**OOP Pros:Ā **Itās easy to understand the basic concept of objects and easy to interpret the meaning of method calls. OOP tends to use an imperative style rather than a declarative style, which reads like a straight-forward set of instructions for the computer to follow.
OOP Cons:Ā OOP Typically depends on shared state. Objects and behaviors are typically tacked together on the same entity, which may be accessed at random by any number of functions with non-deterministic order, which may lead to undesirable behavior such as race conditions.
FP Pros:Ā Using the functional paradigm, programmers avoid any shared state or side-effects, which eliminates bugs caused by multiple functions competing for the same resources. With features such as the availability of point-free style (aka tacit programming), functions tend to be radically simplified and easily recomposed for more generally reusable code compared to OOP.
FP Cons:Ā Over exploitation of FP features such as point-free style and large compositions can potentially reduce readability because the resulting code is often more abstractly specified, more terse, and less concrete.
This is a trick question. The answer is never. Iāve been issuing this challenge for years, and the only answers Iāve ever heard fall into one of severalĀ common misconceptions. More frequently, the challenge is met with silence.
This is a quote fromĀ āDesign Patterns: Elements of Reusable Object-Oriented Softwareā. It means that code reuse should be achieved by assembling smaller units of functionality into new objects instead of inheriting from classes and creating object taxonomies.
In other words, useĀ can-do, has-a,Ā orĀ uses-aĀ relationships instead ofĀ is-aĀ relationships.
Two way data binding means that UI fields are bound to model data dynamically such that when a UI field changes, the model data changes with it and vice-versa.
One way data flow means that the model is the single source of truth. Changes in the UI trigger messages that signal user intent to the model (or āstoreā in React). Only the model has the access to change the appās state. The effect is that data always flows in a single direction, which makes it easier to understand.
One way data flows are deterministic, whereas two-way binding can cause side-effects which are harder to follow and understand.
Good to hear:
- React is the new canonical example of one-way data flow, so mentions of React are a good signal. Cycle.js is another popular implementation of uni-directional data flow.
- Angular is a popular framework which uses two-way binding.
A monolithic architecture means that your app is written as one cohesive unit of code whose components are designed to work together, sharing the same memory space and resources.
A microservice architecture means that your app is made up of lots of smaller, independent applications capable of running in their own memory space and scaling independently from each other across potentially many separate machines.
**Monolithic Pros:Ā **The major advantage of the monolithic architecture is that most apps typically have a large number of cross-cutting concerns, such as logging, rate limiting, and security features such audit trails and DOS protection.
When everything is running through the same app, itās easy to hook up components to those cross-cutting concerns.
There can also be performance advantages, since shared-memory access is faster than inter-process communication (IPC).
Monolithic cons:Ā Monolithic app services tend to get tightly coupled and entangled as the application evolves, making it difficult to isolate services for purposes such as independent scaling or code maintainability.
Monolithic architectures are also much harder to understand, because there may be dependencies, side-effects, and magic which are not obvious when youāre looking at a particular service or controller.
Microservice pros:Ā Microservice architectures are typically better organized, since each microservice has a very specific job, and is not concerned with the jobs of other components. Decoupled services are also easier to recompose and reconfigure to serve the purposes of different apps (for example, serving both the web clients and public API).
They can also have performance advantages depending on how theyāre organized because itās possible to isolate hot services and scale them independent of the rest of the app.
Microservice cons:Ā As youāre building a new microservice architecture, youāre likely to discover lots of cross-cutting concerns that you did not anticipate at design time. A monolithic app could establish shared magic helpers or middleware to handle such cross-cutting concerns without much effort.
In a microservice architecture, youāll either need to incur the overhead of separate modules for each cross-cutting concern, or encapsulate cross-cutting concerns in another service layer that all traffic gets routed through.
Eventually, even monolthic architectures tend to route traffic through an outer service layer for cross-cutting concerns, but with a monolithic architecture, itās possible to delay the cost of that work until the project is much more mature.
Microservices are frequently deployed on their own virtual machines or containers, causing a proliferation of VM wrangling work. These tasks are frequently automated with container fleet management tools.
Synchronous programming means that, barring conditionals and function calls, code is executed sequentially from top-to-bottom, blocking on long-running tasks such as network requests and disk I/O.
Asynchronous programming means that the engine runs in an event loop. When a blocking operation is needed, the request is started, and the code keeps running without blocking for the result. When the response is ready, an interrupt is fired, which causes an event handler to be run, where the control flow continues. In this way, a single program thread can handle many concurrent operations.
User interfaces are asynchronous by nature, and spend most of their time waiting for user input to interrupt the event loop and trigger event handlers.
Node is asynchronous by default, meaning that the server works in much the same way, waiting in a loop for a network request, and accepting more incoming requests while the first one is being handled.
This is important in JavaScript, because it is a very natural fit for user interface code, and very beneficial to performance on the server.
Hoisting is JavaScript's default behavior of moving declarations to the top. In JavaScript, a variable can be declared after it has been used. In other words; a variable can be used before it has been declared.
Example 1Ā gives the same result asĀ Example 2:
Example 1:
x = 5; // Assign 5 to x
elem = document.getElementById("demo"); // Find an element
elem.innerHTML = x; // Display x in the element
var x; // Declare x
Example2 :
var x; // Declare x
x = 5; // Assign 5 to x
elem = document.getElementById("demo"); // Find an element
elem.innerHTML = x; // Display x in the element
Don't get confused that ONLY the declaration is moved to the top. Value initialization is done on the same line.
Thus y
in this example is undefined:
var x = 5; // Initialize x
elem = document.getElementById("demo"); // Find an element
elem.innerHTML = x + " " + y; // Display x and y
var y = 7; // Initialize y
Over the years thereās been a steadily increasing ecosystem of JavaScript components to choose from. The sheer amount of choices is fantastic, but this also infamously presents a difficulty when components are mixed-and-matched. And it doesnāt take too long for budding developers to find out that not all components are built to play nicely together.
To address these issues, the competing module specs AMD and CommonJS have appeared on the scene, allowing developers to write their code in an agreed-upon sandboxed and modularized way, so as not to āpollute the ecosystemā
Asynchronous Module Definition (AMD) has gained traction on the frontend, with RequireJS being the most popular implementation.
Hereās moduleĀ foo
Ā with a single dependency onĀ jquery
:
// filename: foo.js
define(['jquery'], function ($) {
// methods
function myFunc(){};
// exposed public methods
return myFunc;
});
CommonJS is a style you may be familiar with if youāre written anything in Node (which uses a slight variant). Itās also been gaining traction on the frontend with Browserify.
Using the same format as before, hereās what ourĀ foo
Ā module looks like in CommonJS:
// filename: foo.js
// dependencies
var $ = require('jquery');
// methods
function myFunc(){};
// exposed public method (single)
module.exports = myFunc;
Since CommonJS and AMD styles have both been equally popular, it seems thereās yet no consensus. This has brought about the push for a āuniversalā pattern that supports both styles, which brings us to none other than the Universal Module Definition.
The pattern is admittedly ugly, but is both AMD and CommonJS compatible, as well as supporting the old-style āglobalā variable definition:
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD
define(['jquery'], factory);
} else if (typeof exports === 'object') {
// Node, CommonJS-like
module.exports = factory(require('jquery'));
} else {
// Browser globals (root is window)
root.returnExports = factory(root.jQuery);
}
}(this, function ($) {
// methods
function myFunc(){};
// exposed public method
return myFunc;
}));
IIFE is a function that executes immediately after itās created.
It has nothing to do with any event-handler for any events (such asĀ document.onload
).
The first pair of parenthesesĀ (function(){...})
Ā turns the code within (in this case, a function) into an expression, and the second pair of parenthesesĀ (function(){...})()
Ā calls the function that results from that evaluated expression.
This pattern is often used when trying to avoid polluting the global namespace, because all the variables used inside the IIFE (like in any otherĀ normalĀ function) are not visible outside its scope.
This is why, maybe, you confused this construction with an event-handler forĀ window.onload
, because itās often used as this:
(function(){
// all your code here
var foo = function() {};
window.onload = foo;
// ...
})();
// foo is unreachable here (itās undefined)
The function is executed right after it's created, not after it is parsed. The entire script block is parsed before any code in it is executed. Also, parsing code doesn't automatically mean that it's executed, if for example the IIFE is inside a function then it won't be executed until the function is called.
The function is missing the first pair of parantheses that turns the code within into an expression.
//wrong
function foo(){ }();
//correct
(function foo(){})();
Feature detectionĀ checks a feature for existence, e.g.:
if (window.XMLHttpRequest) {
new XMLHttpRequest();
}
FeatureĀ inferenceĀ checks for a feature just like feature detection, but uses another function because itĀ assumesĀ it will also exist, e.g.:
if (document.getElementsByTagName) {
element = document.getElementById(id);
}
Checking theĀ UA stringĀ is an old practice and should not be used anymore. You keep changing the UA checks and never benefit from newly implemented features, e.g.:
if (navigator.userAgent.indexOf("MSIE 7") > -1){
//do something
}
Simply put, AJAX is the use of JavaScript to send and receive using HTTP without reloading the page. AJAXĀ is an acronym forĀ asynchronous JavaScript and XML,Ā andĀ is used as a technique for creating client-side asynchronous web applications. AJAX is considered aĀ groupĀ of technologies. HTML and CSS can be used in combination to mark up and style information. JavaScript and the XMLHttpRequest object provide the method for exchanging data asynchronously between the browser and the server.
AJAX, sends and retrieves data from a server asynchronously. This enables the web application to continue running and dynamically display. It allows the user to interact with the information presented on the page, avoiding full page reloads.
The image below shows the process the execution of AJAX.
- A user interaction in the browser triggers the event, such as a button click
- The AJAX call fires. This creates and AJAX request, browsers use the XMLHttpRequest object. When the server responds to the browserās request, the same XMLHttpRequest object will process the result.
- The server-side script receives the input from JavaScript, and processes the data.
- After the data is processed, the script sends the data back to the original client-side page that made the request via XML
- Once the data is received, a second JavaScript callback function, is called this function captures the data, and updates the web page accordingly.
Advantages
AJAX provides more efficient and smoother running applications, which gives users better interactive experiences.
The best use of AJAX is where it is used to send small payloads. Here is a simple example.
I load a page that contains information about stock. It has graphs, charts, company information and it also displays the share-price. Every 30 seconds, I make an AJAX request that gets the updated share-price and changes it on the page.
Without AJAX, I might decide to refresh the entire page every 30 seconds, but with AJAX, I can just make a lightweight request to get the tiny bit of information I need.
Disadvantages
Using AJAX to submit forms isn't always the best bet. Asides from not really giving you a clear advantage over posting the form normally, you break conventions such as browser history (although some browsers now include JavaScript "states" as pages in the history).
When using AJAX, you need to handle the task of telling the user if something has gone wrong. You can do this with jQuery by specifying what should happen on error, but many people forget to do this and the end user is blissfully unaware of any problem.
Other issues to watch out for are any JavaScript errors that may prevent your events from firing - or if JavaScript is disabled, in either case ensuring that the form can submit normally before you add the AJAX code is the safest option.
Attributes are defined by HTML. Properties are defined by DOM.
Some HTML attributes have 1:1 mapping onto properties.Ā id
Ā is one example of such.
Some do not (e.g. theĀ value
Ā attribute specifies the initial value of an input, but theĀ value
property specifies theĀ currentĀ value).
When you extend an object, you change its behaviour.
Changing the behaviour of an object that will only be used by your own code is fine. But when you change the behaviour of something that is also used by other code there is a risk you will break that other code.
When it comes adding methods to the object and array classes in javascript, the risk of breaking something is very high, due to how javascript works. Long years of experience have taught me that this kind of stuff causes all kinds of terrible bugs in javascript.
If you need custom behaviour, it is far better to define your own class (perhaps a subclass) instead of changing a native one. That way you will not break anything at all.
The ability to change how a class works without subclassing it is an important feature of any good programming language, but it is one that must be used rarely and with caution.
In Javascript, null
is also considered an object. Therefore, the code below surprises javascript newcomers.
var bar = null;
console.log(typeof bar === "object"); //logs true
As long as one is aware of this, the problem can easily be avoided by also checking if bar is null:
console.log((bar !== null) && (typeof bar === "object")); // logs false
To be entirely thorough in our answer, there are two other things worth noting:
First, the above solution will return false if bar is a function. In most cases, this is the desired behavior, but in situations where you want to also return true for functions, you could amend the above solution to be:
console.log((bar !== null) && ((typeof bar === "object") || (typeof bar === "function")));
Second, the above solution will return true if bar is an array (e.g., if var bar = [];). In most cases, this is the desired behavior, since arrays are indeed objects, but in situations where you want to also false for arrays, you could amend the above solution to be:
console.log((bar !== null) && (typeof bar === "object") && (toString.call(bar) !== "[object Array]"));
TheĀ NaN
Ā property represents a value that is ānot a numberā. This special value results from an operation that could not be performed either because one of the operands was non-numeric (e.g.,Ā "abc" / 4
), or because the result of the operation is non-numeric (e.g., an attempt to divide by zero).
While this seems straightforward enough, there are a couple of somewhat surprising characteristics ofĀ NaN
Ā that can result in hair-pulling bugs if one is not aware of them.
For one thing, althoughĀ NaN
Ā means ānot a numberā, its type is, believe it or not,Ā Number
:
console.log(typeof NaN === "number"); // logs "true"
Additionally,Ā NaN
Ā compared to anything ā even itself! ā is false:
console.log(NaN === NaN); // logs "false"
AĀ semi-reliableĀ way to test whether a number is equal to NaN is with the built-in functionĀ isNaN()
, but even usingĀ isNaN()
Ā is an imperfect solution.
A better solution would either be to useĀ value !== value
, which wouldĀ onlyĀ produce true if the value is equal to NaN. Also, ES6 offers a newĀ Number.isNaN()
Ā function, which is a different and more reliable than the old globalĀ isNaN()
Ā function.
The above code will output the following to the console:
"122"
"32"
"02"
"112"
"NaN2"
NaN
Hereās whyā¦
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
.
The difference is scoping.Ā var
Ā is scoped to the nearest function block andĀ let
Ā is scoped to the nearestĀ enclosingĀ block (both are global if outside any block), which can be smaller than a function block.
Also, variables declared withĀ let
Ā are not accessible before they are declared in their enclosing block.
They are very similar when used like this outside a function block.
let me = 'go'; // globally scoped
var i = 'able'; // globally scoped
However, global variables defined withĀ let
Ā will not be added as properties on the globalĀ window
object like those defined withĀ var
.
console.log(window.me); // undefined
console.log(window.i); // 'able'
They are identical when used like this in a function block.
function ingWithinEstablishedParameters() {
let terOfRecommendation = 'awesome worker!'; //function block scoped
var sityCheerleading = 'go!'; //function block scoped
}
Here is the difference.Ā let
Ā is only visible in theĀ for()
Ā loop andĀ var
Ā is visible to the whole function.
function allyIlliterate() {
//tuce is *not* visible out here
for( let tuce = 0; tuce < 5; tuce++ ) {
//tuce is only visible in here (and in the for() parentheses)
//and there is a separate tuce variable for each iteration of the loop
}
//tuce is *not* visible out here
}
function byE40() {
//nish *is* visible out here
for( var nish = 0; nish < 5; nish++ ) {
//nish is visible to the whole function
}
//nish *is* visible out here
}
Assuming strict mode,Ā var
Ā will let you re-declare the same variable in the same scope. On the other hand,Ā let
Ā will not:
'use strict';
let me = 'foo';
let me = 'bar'; // SyntaxError: Identifier 'me' has already been declared
'use strict';
var me = 'foo';
var me = 'bar'; // No problem, `me` is replaced.
In JavaScript,Ā undefined
Ā means a variable has been declared but has not yet been assigned a value, such as:
var TestVar;
alert(TestVar); //shows undefined
alert(typeof TestVar); //shows undefined
null
Ā is an assignment value. It can be assigned to a variable as a representation of no value:
var TestVar = null;
alert(TestVar); //shows null
alert(typeof TestVar); //shows object
From the preceding examples, it is clear thatĀ undefined
Ā andĀ null
Ā are two distinct types:Ā undefined
Ā is a type itself (undefined) whileĀ null
Ā is an object.
null === undefined // false
null == undefined // true
null === null // true
and
null = 'value' // ReferenceError
undefined = 'value' // 'value'
The above code will output the following to the console:
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.
This is an increasingly common practice, employed by many popular JavaScript libraries (jQuery, Node.js, etc.). 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.
Another feature of this technique is to allow for an easily referenceable (presumably shorter) alias for a global variable. This is often used, for example, in jQuery plugins. jQuery allows you to disable theĀ $
Ā reference to the jQuery namespace, usingĀ jQuery.noConflict()
. If this has been done, your code can still useĀ $
Ā employing this closure technique, as follows:
(function($) { /* jQuery plugin code referencing $ */ } )(jQuery);
(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.)
(b) The key to making this work is to capture the value ofĀ i
Ā at each pass through theĀ for
Ā loop by passing it into a newly created function object. Here are three possible ways to accomplish this:
for (var i = 0; i < 5; i++) {
var btn = document.createElement('button');
btn.appendChild(document.createTextNode('Button ' + i));
btn.addEventListener('click', (function(i) {
return function() { console.log(i); };
})(i));
document.body.appendChild(btn);
}
Alternatively, you could wrap the entire call toĀ btn.addEventListener
Ā in the new anonymous function:
for (var i = 0; i < 5; i++) {
var btn = document.createElement('button');
btn.appendChild(document.createTextNode('Button ' + i));
(function (i) {
btn.addEventListener('click', function() { console.log(i); });
})(i);
document.body.appendChild(btn);
}
Or, we could replace theĀ for
Ā loop with a call to the array objectās nativeĀ forEach
Ā method:
['a', 'b', 'c', 'd', 'e'].forEach(function (value, i) {
var btn = document.createElement('button');
btn.appendChild(document.createTextNode('Button ' + i));
btn.addEventListener('click', function() { console.log(i); });
document.body.appendChild(btn);
});
A closure is an inner function that has access to the variables in the outer (enclosing) functionās scope chain. The closure has access to variables in three scopes; specifically: (1) variable in its own scope, (2) variables in the enclosing functionās scope, and (3) global variables.
Here is a simple example:
var globalVar = "xyz";
(function outerFunc(outerArg) {
var outerVar = 'a';
(function innerFunc(innerArg) {
var innerVar = 'b';
console.log(
"outerArg = " + outerArg + "\n" +
"innerArg = " + innerArg + "\n" +
"outerVar = " + outerVar + "\n" +
"innerVar = " + innerVar + "\n" +
"globalVar = " + globalVar);
})(456);
})(123);
In the above example, variables fromĀ innerFunc
,Ā outerFunc
, and the global namespace areĀ allĀ in scope in theĀ innerFunc
. The above code will therefore produce the following output:
outerArg = 123
innerArg = 456
outerVar = a
innerVar = b
globalVar = xyz
The code sample shown willĀ notĀ display the values 0, 1, 2, 3, and 4 as might be expected; rather, it will display 5, 5, 5, 5, and 5.
The reason for this is that each function executed within the loop will be executedĀ afterĀ the entire loop has completed andĀ allĀ will therefore reference theĀ lastĀ value stored inĀ i
, which was 5.
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);
}
This will produce the presumably desired result of logging 0, 1, 2, 3, and 4 to the console.
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 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);
- Passing parameterised behaviour into an algorithm (classic higher-order programming)
- Simulating object oriented programming
- Implementing exotic flow control, such as jQuery's Event handling and AJAX APIs.
One example of closure that enforces public/private methods:
a = (function () {
var privatefunction = function () {
alert('hello');
}
return {
publicfunction : function () {
privatefunction();
}
}
})();
As you can see there,Ā a
Ā is now an object, with a methodĀ publicfunction
Ā (Ā a.publicfunction()
Ā ) which callsĀ privatefunction
, which only exists inside the closure. You canĀ NOTĀ callĀ privatefunction
Ā directly (i.e.Ā a.privatefunction()
Ā ), justĀ publicfunction()
.
the short and most important answer here is thatĀ use strict
Ā is a way to voluntarily enforce stricter parsing and error handling on your JavaScript code at runtime. Code errors that would otherwise have been ignored or would have failed silently will now generate errors or throw exceptions. In general, it is a good practice.
Some of the key benefits of strict mode include:
- Makes debugging easier.Ā Code errors that would otherwise have been ignored or would have failed silently will now generate errors or throw exceptions, alerting you sooner to problems in your code and directing you more quickly to their source.
- Prevents accidental globals.Ā Without strict mode, assigning a value to an undeclared variable automatically creates a global variable with that name. This is one of the most common errors in JavaScript. In strict mode, attempting to do so throws an error.
- EliminatesĀ thisĀ coercion. Without strict mode, a reference to aĀ
this
Ā value of null or undefined is automatically coerced to the global. This can cause many headfakes and pull-out-your-hair kind of bugs. In strict mode, referencing a aĀthis
Ā value of null or undefined throws an error. - Disallows duplicate property names or parameter values.Ā Strict mode throws an error when it detects a duplicate named property in an object (e.g.,Ā
var object = {foo: "bar", foo: "baz"};
) or a duplicate named argument for a function (e.g.,Āfunction foo(val1, val2, val1){}
), thereby catching what is almost certainly a bug in your code that you might otherwise have wasted lots of time tracking down. - Makes eval() safer.Ā There are some differences in the wayĀ
eval()
Ā behaves in strict mode and in non-strict mode. Most significantly, in strict mode, variables and functions declared inside of anĀeval()
Ā statement areĀ notĀ created in the containing scope (theyĀ areĀ created in the containing scope in non-strict mode, which can also be a common source of problems). - Throws error on invalid usage ofĀ delete.Ā TheĀ
delete
Ā operator (used to remove properties from objects) cannot be used on non-configurable properties of the object. Non-strict code will fail silently when an attempt is made to delete a non-configurable property, whereas strict mode will throw an error in such a case.
Surprisingly, these two functions willĀ notĀ return the same thing. Rather:
console.log("foo1 returns:");
console.log(foo1());
console.log("foo2 returns:");
console.log(foo2());
will yield:
foo1 returns:
Object {bar: "hello"}
foo2 returns:
undefined
Not only is this surprising, but what makes this particularly gnarly is thatĀ foo2()
Ā returns undefined without any error being thrown.
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.
No error is thrown since the remainder of the code is perfectly valid, even though it doesnāt ever get invoked or do anything (it is simply an unused code block that defines a propertyĀ bar
Ā which is equal to the stringĀ "hello"
).
This behavior also argues for following the convention of placing an opening curly brace at the end of a line in JavaScript, rather than on the beginning of a new line. As shown here, this becomes more than just a stylistic preference in JavaScript.
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.
An educated answer to this question would simply be: āYou canāt be sure. it might print out ā0.3ā and ātrueā, or it might not. Numbers in JavaScript are all treated with floating point precision, and as such, may not always yield the expected results.ā
The example provided above is classic case that demonstrates this issue. Surprisingly, it will print out:
0.30000000000000004
false
This may sound trivial and, in fact, it is trivial with ECMAscript 6 which introduces a newĀ Number.isInteger()
Ā function for precisely this purpose. However, prior to ECMAScript 6, this is a bit more complicated, since no equivalent of theĀ Number.isInteger()
Ā method is provided.
The issue is that, in the ECMAScript specification, integers only exist conceptually; i.e., numeric values areĀ alwaysĀ stored as floating point values.
With that in mind, theĀ simplest and cleanestĀ pre-ECMAScript-6 solution (which is also sufficiently robust to returnĀ false
Ā even if a non-numeric value such as a string orĀ null
Ā is passed to the function) would be the following:
function isInteger(x) { return (x^0) === x; }
The following solution would also work, although not as elegant as the one above:
function isInteger(x) { return Math.round(x) === x; }
Note thatĀ Math.ceil()
Ā orĀ Math.floor()
Ā could be used equally well (instead ofĀ Math.round()
) in the above implementation.
Or alternatively:
function isInteger(x) { return (typeof x === 'number') && (x % 1 === 0); }
One fairly commonĀ incorrectĀ solution is the following:
function isInteger(x) { return parseInt(x, 10) === x; }
While thisĀ parseInt
-based approach will work well forĀ manyĀ values ofĀ x
, onceĀ x
Ā becomes quite large, it will fail to work properly. The problem is thatĀ parseInt()
Ā coerces its first parameter to a string before parsing digits. Therefore, once the number becomes sufficiently large, its string representation will be presented in exponential form (e.g.,Ā 1e+21
). Accordingly,Ā parseInt()
Ā will then try to parseĀ 1e+21
, but will stop parsing when it reaches theĀ e
Ā character and will therefore return a value ofĀ 1
. Observe:
> String(1000000000000000000000)
'1e+21'
> parseInt(1000000000000000000000, 10)
1
> parseInt(1000000000000000000000, 10) === 1000000000000000000000
false
The values will be logged in the following order:
1
4
3
2
Letās first explain the parts of this that are presumably more obvious:
1
Ā andĀ4
Ā are displayed first since they are logged by simple calls toĀconsole.log()
Ā without any delay2
Ā is displayed afterĀ3
Ā becauseĀ2
Ā is being logged after a delay of 1000 msecs (i.e., 1 second) whereasĀ3
Ā is being logged after a delay of 0 msecs.
OK, fine. But ifĀ 3
Ā is being logged after a delay of 0 msecs, doesnāt that mean that it is being logged right away? And, if so, shouldnāt it be loggedĀ beforeĀ 4
, sinceĀ 4
Ā is being logged by a later line of code?
The answer has to do with properly understandingĀ JavaScript events and timing.
The browser has an event loop which checks the event queue and processes pending events. For example, if an event happens in the background (e.g., a scriptĀ onload
Ā event) while the browser is busy (e.g., processing anĀ onclick
), the event gets appended to the queue. When the onclick handler is complete, the queue is checked and the event is then handled (e.g., theĀ onload
Ā script is executed).
Similarly,Ā setTimeout()
Ā also puts execution of its referenced function into the event queue if the browser is busy.
When a value of zero is passed as the second argument toĀ setTimeout()
, it attempts to execute the specified function āas soon as possibleā. Specifically, execution of the function is placed on the event queue to occur on the next timer tick. Note, though, that this isĀ notĀ immediate; the function is not executed until the next tick. Thatās why in the above example, the call toĀ console.log(4)
Ā occurs before the call toĀ console.log(3)
Ā (since the call toĀ console.log(3)
Ā is invoked via setTimeout, so it is slightly delayed).
DOM elements can be nested inside each other. And somehow, the handler of the parent works even if you click on itās child.
The reason isĀ event bubbling.
For example, the followingĀ DIV
Ā handler runs even if you click a nested tag likeĀ EM
Ā orĀ CODE
:
<div onclick="alert('Div handler worked!')">
<em>Click here triggers on nested <code>EM</code>, not on <code>DIV</code></em>
</div>
The main principle of bubbling states: After an event triggers on the deepest possible element, it then triggers on parents in nesting order.
The bubbling goes right to the top. When an event occurs on an element - it will bubble up toĀ <HTML>
, triggering handlers on itās way.
But a handler may decide that event is fully processed and stop the bubbling.
- For W3C-compliant browsers:
event.stopPropagation()
- For IE<9:
event.cancelBubble =Ā true
In all browsers, except IE<9, there are two stages of event processing.
The event first goes down - thatās calledĀ capturing, and thenĀ bubblesĀ up. This behavior is standartized in W3C specification.
- Events first areĀ capturedĀ down to deepest target, thenĀ bubbleĀ up. In IE<9 they only bubble.
- All handlers work onĀ bubblingĀ stage exceptsĀ
addEventListener
Ā with last argumentĀtrue
, which is the only way to catch the event on capturing stage. - Bubbling/capturing can be stopped byĀ
event.cancelBubble=true
Ā (IE) orĀevent.stopPropagation()
Ā for other browsers.
There are (at least) two ways to do this:
METHOD 1
function sum(x) {
if (arguments.length == 2) {
return arguments[0] + arguments[1];
} else {
return function(y) { return x + y; };
}
}
In JavaScript, functions provide access to anĀ arguments
Ā object which provides access to the actual arguments passed to a function. This enables us to use theĀ length
Ā property to determine at runtime the number of arguments passed to the function.
If two arguments are passed, we simply add them together and return.
Otherwise, we assume it was called in the formĀ sum(2)(3)
, so we return an anonymous function that adds together the argument passed toĀ sum()
Ā (in this case 2) and the argument passed to the anonymous function (in this case 3).
METHOD 2
function sum(x, y) {
if (y !== undefined) {
return x + y;
} else {
return function(y) { return x + y; };
}
}
When a function is invoked, JavaScript does not require the number of arguments to match the number of arguments in the function definition. If the number of arguments passed exceeds the number of arguments in the function definition, the excess arguments will simply be ignored. On the other hand, if the number of arguments passed is less than the number of arguments in the function definition, the missing arguments will have a value ofĀ undefined
Ā when referenced within the function. So, in the above example, by simply checking if the 2nd argument is undefined, we can determine which way the function was invoked and proceed accordingly.
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
- **function Person() {}Ā **
Declares a function (but does not execute it). It will usually have some code between the curly brackets.
- var person = Person()
Declares a variable (person), invokes a function (Person) and sets the value ofĀ personĀ to the return of the function.
- var person = new Person()
Creates a new instance of an object based on the Person function. So the variable (person) is now anĀ Object, not just a string or a number.
The difference is thatĀ apply
Ā lets you invoke the function withĀ arguments
Ā as an array;Ā call
requires the parameters be listed explicitly. A useful mnemonic is "A for array and C for comma."
See MDN's documentation onĀ applyĀ andĀ call.
Pseudo syntax:
theFunction.apply(valueForThis, arrayOfArgs)
theFunction.call(valueForThis, arg1, arg2, ...)
There is also, as of ES6, the possibility toĀ spread
Ā the array for use with theĀ call
Ā function, you can see the compatibilitiesĀ here.
Sample code:
function theFunction(name, profession) {
console.log("My name is " + name + " and I am a " + profession + ".");
}
theFunction("John", "fireman");
theFunction.apply(undefined, ["Susan", "school teacher"]);
theFunction.call(undefined, "Claude", "mathematician");
theFunction.call(undefined, ...["Matthew", "physicist"]); // used with the spread operator
// Output:
// My name is John and I am a fireman.
// My name is Susan and I am a school teacher.
// My name is Claude and I am a mathematician.
// My name is Matthew and I am a physicist.
A traditional script tag will block the page while it is loading and executing. A script loaded with document.write will work asynchronously. That's why you see this on ads or analytics, as such scripts don't influence the page content directly.
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 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.
The code will output the following four lines:
0 || 1 = 1
1 || 2 = 1
0 && 1 = 0
1 && 2 = 2
In JavaScript, bothĀ ||
Ā andĀ &&
Ā are logical operators that return the first fully-determined ālogical valueā when evaluated from left to right.
The or (||) operator.Ā In an expression of the formĀ X||Y
,Ā X
Ā is first evaluated and interpreted as a boolean value. If this boolean value isĀ true
, thenĀ true
Ā (1) is returned andĀ Y
Ā is not evaluated, since the āorā condition has already been satisfied. If this boolean value is āfalseā, though, we still donāt know ifĀ X||Y
Ā is true or false until we evaluateĀ Y
, and interpret it as a boolean value as well.
Accordingly,Ā 0 || 1
Ā evaluates to true (1), as doesĀ 1 || 2
.
The and (&&) operator.Ā In an expression of the formĀ X&&Y
,Ā X
Ā is first evaluated and interpreted as a boolean value. If this boolean value isĀ false
, thenĀ false
Ā (0) is returned andĀ Y
Ā is not evaluated, since the āandā condition has already failed. If this boolean value is ātrueā, though, we still donāt know ifĀ X&&Y
Ā is true or false until we evaluateĀ Y
, and interpret it as a boolean value as well.
However, the interesting thing with theĀ &&
Ā operator is that when an expression is evaluated as ātrueā, then the expression itself is returned. This is fine, since it counts as ātrueā in logical expressions, but also can be used to return that value when you care to do so. This explains why, somewhat surprisingly,Ā 1 && 2
Ā returns 2 (whereas you might it expect it to returnĀ true
Ā orĀ 1
).
The code will output:
true
false
In JavaScript, there are two sets of equality operators. The triple-equal operatorĀ ===
Ā behaves like any traditional equality operator would: evaluates to true if the two expressions on either of its sides have the same type and the same value. The double-equal operator, however, tries to coerce the values before comparing them. It is therefore generally good practice to use theĀ ===
Ā rather thanĀ ==
. The same holds true forĀ !==
Ā vsĀ !=
.
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]
.
This is somewhat of a trick question since, in JavaScript, objects essentially are hashtables; i.e., collections of name-value pairs. In these name-value pairs, a crucial point to be aware of is that the names (a.k.a., keys) are always strings.
Both terms are defined in the ECMAScript specfication:
object in an ECMAScript implementation whose semantics are fully defined by this specification rather than by the host environment.
NOTE Standard native objects are defined in this specification. Some native objects are built-in; others may be constructed during the course of execution of an ECMAScript program.
Source:Ā http://es5.github.com/#x4.3.6
object supplied by the host environment to complete the execution environment of ECMAScript.
NOTE Any object that is not native is a host object.
Source:Ā http://es5.github.com/#x4.3.8
uilt-in objects:Ā String
,Ā Math
,Ā RegExp
,Ā Object
,Ā Function
Ā etc. - core predefined objects always available in JavaScript. Defined in the ECMAScript spec.
Host objects: objects likeĀ window
,Ā XmlHttpRequest
, DOM nodes and so on, which is provided by the browser environment. They are distinct from the built-in objects because not all environment will have the same host objects. If JavaScript runs outside of the browser, for example as server side scripting language like in Node.js, different host objects will be available.
User objects: objects defined in JavaScript code. So 'Bird' in your example would be a user object.
The JavaScript spec groups built-in objects and user objects together asĀ native objects. This is an unorthodox use of the term "native", since user objects are obviously implemented in JavaScript while the built-ins is most likely implemented in a different language under the hood, just as the host objects would be. But from the perspective of the JavaScript spec, both builtins and user objects are native to JavaScript because they are defined in the JavaScript spec, while host objects are not.
Visiting all elements in a tree (DOM) is a classicĀ Depth-First-Search algorithmĀ application. Hereās an example solution:
function Traverse(p_element,p_callback) {
p_callback(p_element);
var list = p_element.children;
for (var i = 0; i < list.length; i++) {
Traverse(list[i],p_callback); // recursive call
}
}
Given two trees which have identical structure, and a specified node within the first tree, locate the node in the second tree with the same position within the structure.
If we have no other information about the two trees then the position of each node can be characterized as a path from the root node where each step in the path is specified as an index into the childNode array.
function indexOf(arrLike, target) {
return Array.prototype.indexOf.call(arrLike, target);
}
// Given a node and a tree, extract the nodes path
function getPath(root, target) {
var current = target;
var path = [];
while(current !== root) {
path.unshift(indexOf(current.parentNode.childNodes, current));
current = current.parentNode;
}
return path;
}
// Given a tree and a path, let's locate a node
function locateNodeFromPath(root, path) {
var current = root;
for(var i = 0, len = path.length; i < len; i++) {
current = current.childNodes[path[i]];
}
return current;
}
function getDoppleganger(rootA, rootB, target) {
return locateNodeFromPath(rootB, getPath(rootA, target));
}
Although JavaScript is an object-oriented language, it is prototype-based and does not implement a traditional class-based inheritance system.
All JavaScript objects inherit the properties and methods from their prototype.
In JavaScript, each object internally references another object, called itsĀ prototype. That prototype object, in turn, has a reference to its prototype object, and so on. At the end of this prototype chain is an object with null as its prototype. The prototype chain is the mechanism by which inheritance āĀ prototypal inheritanceĀ to be precise ā is achieved in JavaScript. In particular, when a reference is made to a property that an object does not itself contain, the prototype chain is traversed until the referenced property is found (or until the end of the chain is reached, in which case the property is undefined).
Hereās a simple example:
function Animal() { this.eatsVeggies = true; this.eatsMeat = false; }
function Herbivore() {}
Herbivore.prototype = new Animal();
function Carnivore() { this.eatsMeat = true; }
Carnivore.prototype = new Animal();
var rabbit = new Herbivore();
var bear = new Carnivore();
console.log(rabbit.eatsMeat); // logs "false"
console.log(bear.eatsMeat); // logs "true"
There is more than one type of prototypal inheritance:
-
DelegationĀ (i.e., the prototype chain).
-
ConcatenativeĀ (i.e. mixins,Ā
Object.assign()
).-
Concatenative inheritance is the process of copying the properties from one object to another, without retaining a reference between the two objects. It relies on JavaScriptās dynamic object extension feature.
Cloning is a great way to store default state for objects: This process is commonly achieved usingĀ
Object.assign()
.Ā Prior to ES6, it was common to use similarĀ.extend()
Ā methods from Lodash, Underscore, or jQuery.
-
-
FunctionalĀ (Not to be confused with functional programming. A function used to create a closure for private state/encapsulation).
Each type of prototypal inheritance has its own set of use-cases, but all of them are equally useful in their ability to enableĀ composition,Ā which createsĀ has-aĀ orĀ uses-aĀ orĀ can-doĀ relationships as opposed to theĀ is-aĀ relationship created with class inheritance.
Bind creates a new function that will haveĀ this
Ā set to the first parameter passed toĀ bind()
.
Here's an example that shows how to useĀ bind
Ā to pass a member method around that has the correctĀ this
:
var Button = function(content) {
this.content = content;
};
Button.prototype.click = function() {
console.log(this.content + ' clicked');
}
var myButton = new Button('OK');
myButton.click();
var looseClick = myButton.click;
looseClick(); // not bound, 'this' is not myButton - it is the global object
var boundClick = myButton.click.bind(myButton);
boundClick(); // bound, 'this' is myButton
Which prints out:
OK clicked
undefined clicked
OK clicked
You can also add extra parameters after the 1st (this
) parameter andĀ bind
Ā will pass in those values to the original function. Any additional parameters you later pass to the bound function will be passed in after the bound parameters:
// Example showing binding some parameters
var sum = function(a, b) {
return a + b;
};
var add5 = sum.bind(null, 5);
console.log(add5(10));
Which prints out:
15
The following one line function will returnĀ true
Ā ifĀ str
Ā is a palindrome; otherwise, it returns false.
function isPalindrome(str) {
str = str.replace(/\W/g, '').toLowerCase(); //removes all non-word character
return (str == str.split('').reverse().join('')); //remove space, reverse, and check
}
For example:
console.log(isPalindrome("level")); // logs 'true'
console.log(isPalindrome("levels")); // logs 'false'
console.log(isPalindrome("A car, a man, a maraca")); // logs 'true'
function sqrt(number) {
for (let i = 0; i * i <= number; i++) {
if (i * i === number)
return i;
}
return number; // don't know if you should have this line in case nothing found
}
//@param number number to find the square root of
//@param guess number of guesses
function sqrt(number, guess) {
if (!guess) {
// Take an initial guess at the square root
guess = number / 2.0;
}
var d = number / guess; // Divide our guess into the number
var new_guess = (d + guess) / 2.0; // Use average of guess and d as our new guess
if (guess == new_guess) {
// The new guess is the same as the old guess; further guesses
// can get no more accurate so we return this guess
return guess;
}
// Recursively solve for closer and closer approximations of the square root
return sqrt(number, new_guess);
}
function flatten(input) {
let out = [];
let loop = function(arr) {
return arr.map(function(v) {
return Array.isArray(v)? loop(v) : out.push(v);
});
}
loop(input);
return out;
}
OR
var list1 = [[0, 1], [2, 3], [4, 5]];
var list2 = [0, [1, [2, [3, [4, [5]]]]]];
const flatten = arr => arr.reduce((a, b) => a.concat(Array.isArray(b) ? flatten(b) : b), []);
flatten(list1); // returns [0, 1, 2, 3, 4, 5]
flatten(list2); // returns [0, 1, 2, 3, 4, 5]
function sort(A, B) {
let result = [];
B.map((index, i) => {
result[index] = A[i];
})
return result;
}
var string = "ABCSC";Ā
return ((string.indexOf("ABC") != -1) ? (string.replace(/ABC/gm,"")) : (-1));
/**
* @param {number[]} nums
* @return {void} Do not return anything, modify nums in-place instead.
*/
var moveZeroes = function(nums) {
let j = 0;
nums.map((num, i) => {
if(num !== 0) { //if number is not 0
//swap the num[i] and num[j]
let temp = nums[j];
nums[j] = nums[i];
nums[i] = temp;
j++;
}
})
};
^= is a XOR bitwise operator. Find more information about XOR here
module.exports = {
//param A : array of integers
//return an integer
singleNumber : function(A){
var a;
A.forEach(function(item){
a ^= item;
});
return a;
}
};