Translator: Xiao Sheng
The original link
1, What are the potential pitfalls when using typeof bar === “object” to determine if bar is an object? How can this trap be avoided?
Although typeof bar === “object” is a reliable way to check if a bar is an object, the surprising problem in JavaScript is that _NULl_ is also considered an object!
Therefore, the following code prints true instead of false to the console:
var bar = null;
console.log(typeof bar === ""object""); // logs true!
Copy the code
Knowing this, you can easily avoid the problem by checking if the bar is empty:
console.log((bar ! = =null) && (typeof bar === ""object"")); // logs false
Copy the code
To make our answer more complete, two other things are worth noting:
First, if bar were a function, the above solution would return false. In most cases, this is the expected behavior, but in cases where you want the function to return true, you can modify the above solution to read:
console.log((bar ! = =null) && ((typeof bar === ""object"") | | (typeof bar === ""function"")));
Copy the code
Second, the above solution will return true if bar is an array (for example, if var bar = [];) . In most cases, this is the desired behavior, since arrays are indeed objects, but in cases where you want to be false for arrays as well, you can change the solution above to:
console.log((bar ! = =null) && (typeof bar === ""object"") && (toString.call(bar) ! = =""[object Array]""));
Copy the code
However, there is an alternative method that returns false for null values, arrays, and functions, but true for objects:
console.log((bar ! = =null) && (bar.constructor === Object));
Copy the code
Or, if you use jQuery:
console.log((bar ! = =null) && (typeof bar === ""object"") && (! $.isArray(bar)));
Copy the code
ES5 makes the case for arrays very simple, including its own null checking:
console.log(Array.isArray(bar));
Copy the code
2. What does the following code output to the console and why?
(function(){ var a = b = 3; }) (); console.log(""a defined? "" + (typeof a ! == 'undefined')); console.log(""b defined? "" + (typeof b ! == 'undefined'));Copy the code
Because both A and B are defined within the closed scope of functions, and because the line they are in starts with the var keyword, most JavaScript developers would expect typeof A and Typeof B to be undefined in the example above.
However, this is not the case. The problem here is that most developers misunderstand the statement var a = b = 3; The following abbreviations are:
var b = 3;
var a = b;
Copy the code
But in fact, var a = b = 3; It’s shorthand:
b = 3;
var a = b;
Copy the code
So (if you don’t use strict mode), the output of the code snippet would be:
a defined? false
b defined? true
Copy the code
But how do you define b outside of the closed function? So, because we said var a = b = 3; Is short for the statement b = 3; And var a = b; B ends up being a global variable (because it’s not after the var keyword), so it’s still in scope, even outside of the enclosing function.
Note that in strict mode (that is, using strict), the statement var a = b = 3; A runtime error with a ReferenceError is generated: B is not defined, thus avoiding any headfakes/bugs that might result. (This is why you should use strict in your code, an important example!)
What does the following code output to the console? 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();
Copy the code
The above code will be printed to the console:
outer func: this.foo = bar
outer func: self.foo = bar
inner func: this.foo = undefined
inner func: self.foo = bar
Copy the code
In the external function, both this and self refer to myObject, and therefore both reference and access Foo correctly.
But in the inner function, this no longer points to myObject. Thus, this.foo is undefined in the inner function, while a reference to the local variable self is still in scope and accessible there.
4. What is the importance and reason for encapsulating the entire content of a JavaScript source file in a function block?
This is an increasingly common practice, adopted by many popular JavaScript libraries (jQuery, Node.js, etc.). This technique helps avoid potential name conflicts between different JavaScript modules and libraries by creating a closure around the entire contents of the file and, perhaps most importantly, a private namespace.
Another feature of this technique is to provide an easily referable (and possibly shorter) alias for global variables. This is typically used for jQuery plug-ins, for example. JQuery allows you to disable references to jQuery namespaces using jquery.noconflict (). If you do, your code can still use references. If you do, your code can still use references. If you do, your code can still use the closure technique, as shown below:
(function($) { /* jQuery plugin code referencing $ */ } )(jQuery);
Copy the code
5. What’s the point and benefit of including ‘use strict’ at the beginning of your JavaScript source file?
The simplest and most important answer here is that Use strict is _ a way to automate stricter parsing and error handling of JavaScript code at runtime _. If code errors are ignored or fail, an error or exception is thrown. Overall, this is a good practice.
Some of the key benefits of the strict model include:
- Makes debugging easier. If code errors would otherwise have been ignored or failed, errors or exceptions will now be raised, allowing problems in the code to be found more quickly and their source code to be directed more quickly.
- Prevent accidents globally. Without a strict schema, assigning a value to an undeclared variable automatically creates a global variable with that name. This is one of the most common mistakes in JavaScript. In strict mode, attempting to do so raises an error.
- ** Eliminate hidden threats. ** In the absence of a strict mode, a reference to the value of null or undefined is automatically enforced globally. This can lead to many errors of the _headfakes_ and _pull-out-your-hair_ types. In strict mode, referencing the value of null or undefined raises an error.
- Duplicate parameter values are not allowed.Strict mode throws errors when it detects duplicate named arguments to a function (for example, the function foo (val1, val2, val1) {}), catching errors that are almost certainly present in code that you might otherwise waste a lot of time tracking down.
- Note: it used to be (in ECMAScript 5) that strict mode would prohibit duplicate property names (e.g. Var object = {foo: “bar”, foo: “baz”};) But as of ECMAScript 2015, this is no longer the case.
- Make eval () more secure. Eval () behaves somewhat differently in strict mode than in non-strict mode. Most importantly, in strict mode, variables and functions declared inside an eval () statement are not created in an include scope (they are created in an include scope in non-strict mode, which can also be a common source of problems).
- Throws invalid use of the wrong strikeout. The delete operator (used to remove properties from an object) cannot be used for non-configurable properties of an object. Non-strict code automatically fails when attempting to remove a non-configurable property, in which case strict mode raises an error.
Consider the following two functions. Do they all return the same value? Why or why not?
function foo1()
{
return {
bar: ""hello""
};
}
function foo2()
{
return
{
bar: ""hello""
};
}
Copy the code
Surprisingly, these two functions do not return the same result. But:
console.log(""foo1 returns:"");
console.log(foo1());
console.log(""foo2 returns:"");
console.log(foo2());
Copy the code
Produce:
foo1 returns:
Object {bar: ""hello""}
foo2 returns:
undefined
Copy the code
Not only is this surprising, but what is particularly annoying is that foo2 () returns undefined without raising any errors.
The reason has to do with the fact that semicolons are technically optional in JavaScript (although ignoring them is usually a very bad form). Therefore, when a line containing a return statement is encountered in foo2 () (nothing else), the semicolon is automatically inserted immediately after the return statement.
Since the rest of the code is perfectly valid, even if it’s not called or doing anything (it’s just an unused block of code that defines a property bar, which is equal to the string “hello”), no errors are thrown.
This behavior is also believed to follow the JavaScript convention of placing the opening brace at the end of a line, rather than at the beginning of a new line. As you can see, this is not just a style preference in JavaScript.
7. What is NaN? What is its type? How can I reliably test whether a value is equal to NaN?
The NaN attribute represents a “not a number” value. This special value is either because an operand is non-numeric (such as “ABC” / 4) or because the result of the operation is non-numeric.
While this may seem simple enough, NaN has some surprising features that can lead to bugs if people aren’t aware of them.
On the one hand, although NaN means “not a number”, it is of type, number:
console.log(typeof NaN === ""number""); // logs ""true""
Copy the code
Besides, NaN is more than anything – even itself! – is false:
console.log(NaN === NaN); // logs ""false""
Copy the code
A semi-reliable way to test whether a number equals NaN is to use the built-in function isNaN (), but even using isNaN () is not a good solution. .
A better solution is either to use Value! == value, if it is equal to NaN, then only true is generated. In addition, ES6 provides a new number.isnan () function that is different and more reliable than the old global isNaN () function.
8. What does the following code output? Explain your answer.
console.log(0.1 + 0.2);
console.log(0.1 + 0.2= =0.3);
Copy the code
An educated answer to this question is: “You can’t be sure. It may print 0.3 and true, or it may not print. Numbers in JavaScript are all handled with floating-point precision, so they may not always yield the expected result. “
The example provided above is a classic example of this problem. Surprisingly, it will print:
0.30000000000000004
false
Copy the code
A typical solution is to compare the absolute difference between two numbers and the special constant number.epsilon:
function areTheNumbersAlmostEqual(num1, num2) {
return Math.abs( num1 - num2 ) < Number.EPSILON;
}
console.log(areTheNumbersAlmostEqual(0.1 + 0.2.0.3));
Copy the code
Discusses a possible way to write a function, isInteger (x), that determines whether x is an integer.
This sounds trivial, and in fact ECMAscript 6 introduces a new function called number.isINTEGER () for this purpose, which is trivial. However, prior to ECMAScript 6, this was a bit complicated because there was no equivalent provided to the number.isINTEGER () method.
The problem is that in the ECMAScript specification, integers exist only conceptually; That is, values are always stored as floating point values.
With this in mind, the simplest, cleanest pre-ECMAScript-6 solution (which is reliable enough to return false even if a non-numeric value (such as a string or null value) is passed to the function) will be used as bitwise xOR operators:
function isInteger(x) { return (x ^ 0) === x; }
Copy the code
The following solution also works, though not as elegantly
function isInteger(x) { return Math.round(x) === x; }
Copy the code
Note that math.ceil () or math.floor () could be used as well (instead of math.round ()) in the above implementation.
Or:
function isInteger(x) { return (typeof x === 'number') && (x % 1= = =0); }
Copy the code
A fairly common incorrect solution is as follows:
function isInteger(x) { return parseInt(x, 10) === x; }
Copy the code
While this parseint-based approach works well for many x values, it will not work properly once x becomes quite large. The problem is that parseInt () casts its first argument to a string before parsing a number. Therefore, once a number becomes large enough, its string representation is rendered as an exponential (for example, 1e + 21). Therefore, parseInt () will try to parse 1e + 21, but will stop parsing when it reaches the e character, so it will return the value 1. Observation:
> String(1000000000000000000000)
'1e+21'
Copy the code
> parseInt(1000000000000000000000.10)
1
Copy the code
> parseInt(1000000000000000000000.10) = = =1000000000000000000000
false
Copy the code
9. In what order are numbers 1-4 recorded to the console when executing the following code? Why is that?
(function() { console.log(1); setTimeout(function(){console.log(2)}, 1000); setTimeout(function(){console.log(3)}, 0); console.log(4); }) ();Copy the code
These values will be recorded in the following order:
4 3 2 1Copy the code
Let’s explain some of the more obvious parts first:
-
1 and 4 are shown first, because they are logged without any delay by a simple call to console.log ()
-
Display after 3 because 2 is recorded after a 1000 ms delay (that is, 1 second) and 3 after a 0 ms delay.
good However, if 3 is recorded after a delay of 0 ms, does that mean it is being recorded immediately? And, if so, shouldn’t it be logged before 4, because 4 is logged by the following line of code?
The answer has to do with understanding JavaScript events and times correctly. .
The browser has an event loop that checks the event queue and handles pending events. For example, if an event (such as a script onload event) occurs in the background while the browser is busy (for example, processing onclick), it is appended to the queue. When the onclick handler completes, the queue is checked and the event is processed (for example, the onload script is executed).
Similarly, if the browser is busy, setTimeout () puts the execution of its reference function into an event queue.
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, the execution of the function is placed in an event queue to occur when the next timer ticks. But notice that this is not direct; This function does not execute until the next tick. This is why, in the example above, the call to console.log (4) occurs before the call to console.log (3) (slightly delayed because the call to console.log (3) was made with setTimeout).
Write a simple function (less than 160 characters) that returns a Boolean indicating whether the string ispalindrome.
If STR is palindrome, the following line of functions returns true; Otherwise, it returns false.
function isPalindrome(str) {
str = str.replace(/\W/g.' ').toLowerCase();
return (str == str.split(' ').reverse().join(' '));
}
Copy the code
Such as:
console.log(isPalindrome(""level"")); // logs 'true'
console.log(isPalindrome(""levels"")); // logs 'false'
console.log(isPalindrome(""A car, a man, a maraca"")); // logs 'true'
Copy the code
Write a sum method that will work when called with the following syntax.
The console. The log (sum (2, 3)); // Outputs 5 console.log(sum(2)(3)); // Outputs 5Copy the code
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; }; }}Copy the code
In JavaScript, a function provides access to a parameter object that provides access to the actual parameters passed to the function. This allows us to use the Length attribute to determine the number of arguments passed to the function at run time
If we pass two arguments, we simply add them and return them.
Otherwise, we assume it is called as sum (2) (3), so we return an anonymous function that will pass the arguments to sum () (2 in this case) and the arguments 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; };
}
}
Copy the code
When a function is called, 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 are ignored. On the other hand, if the number of arguments passed is less than the number in the function definition, the missing arguments will have undefined values when referenced within the function. So, in the example above, by simply checking whether the second argument is undefined, we can determine how the function is called and proceed accordingly.
12. 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);
}
Copy the code
(a) What is recorded to the console when the user clicks button 4? Why is that?
(b) Provide one or more alternative implementations that work as intended.
A:
(a) No matter which button the user clicks, the number 5 will always be recorded to the console. This is because, by the time the onclick method is called (for any button), the for loop is complete and variable I has a value of 5. (Bonus points are awarded if respondents know enough about execution context, variable objects, active objects, and how the internal “scope” attribute affects closure behavior.)
(b) The key to making this work is to capture the value of I each time it passes through the for loop by passing it to the newly created function object. Here are four possible ways to do 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);
}
Copy the code
Alternatively, you can wrap the entire call in the new anonymous function as btn.addeventListener:
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);
}
Copy the code
Alternatively, we could replace the for loop by calling 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);
});
Copy the code
Finally, the simplest solution, if you are in the ES6 / ES2015 context, is to use let I instead of var I:
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);
}
Copy the code
13. Suppose d is an “empty” object in scope:
var d = {};
Copy the code
. What is accomplished with the following code?
[ 'zebra'.'horse' ].forEach(function(k) {
d[k] = undefined;
});
Copy the code
The code snippet shown above sets two properties on object D. Ideally, lookups performed on JavaScript objects with unset keys are evaluated as undefined. But running this code marks these properties as the object’s “own properties.”
This is a useful strategy for ensuring that an object has a given set of properties. Passing this Object to object.keys returns an array of these setting keys (even if their values are undefined).
14. The following code is printed to the console. 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));
Copy the code
The output of the record will be:
""array 1: length=5 last=j,o,n,e,s""
""array 2: length=5 last=j,o,n,e,s""
Copy the code
Arr1 and arr2 is the same (i.e., [‘ n ‘, ‘h’, ‘o’ and ‘j’ [‘ j ‘, ‘o’, ‘n’, ‘e’, ‘s’]]) the code and is carried out for the following reasons:
-
Calling the reverse () method on the array object not only returns the array in reverse order, it also reverses the order of the array itself (in this case, arr1).
-
The reverse () method returns a reference to the array itself (that is, arr1 in this case). Therefore, ARR2 is simply a reference (not a copy) to ARR1. So when we do anything with arr2 (that is, when we call arr2.push (arr3);) , arr1 is also affected because arR1 and ARR2 are only references to the same object.
Here are a few ideas to help people answer this question:
-
The push () method that passes an array to another array pushes the entire array as a single element to the end of the array. As a result, declare arr2.push (arR3); Add ARR3 as a whole to the end of ARR2 (that is, it does not concatenate two arrays, which is what the concat () method is for).
-
Like Python, JavaScript recognizes negative subscripts when calling array methods like slice () as a way of referring to elements at the end of the array; For example, the subscript -1 indicates the last element in the array, and so on.
15. The following code is printed to the console. 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);
Copy the code
The above code will be printed to the console:
""122""
""32""
""02""
""112""
""NaN2""
NaN
Copy the code
That’s why…
The basic problem here is that JavaScript (ECMAScript) is a loosely typed language that performs automatic type conversions on values to fit the operation being performed. Let’s see how this compares to each of the examples above.
Example 1:1 + 2 + 2 Output: 122 Description: The first operation is performed in 1 + 2. Since one of the operands (” 2 “) is a string, JavaScript assumes that string concatenation needs to be performed, so the type of 1 is converted to “1” and 1 + “2” is converted to “12”. Then, “12” + “2” produces “122”.
Example 2:1 + + “2” + “2” Output: “32” Description: Depending on the order of operations, the first operation to be performed is + “2” (the extra + before the first “2” is treated as a unary operator). So JavaScript converts the type of “2” to a number, and then applies the unary + symbol to it (that is, as a positive number). As a result, the next operation is now 1 + 2, which of course produces 3. However, we have an operation between a number and a string (that is, 3 and “2”), so JavaScript again converts the value to a string and performs a string concatenation, producing “32”.
Example 3:1 + – “1” + “2” Output: “02” Note: The interpretation is the same as in the previous example, except that the unary operator is – instead of +. Therefore, “1” becomes 1, then becomes -1 when applying -, then increses it to produce 0, then converts it to a string and concatenates with the final “2” operand to produce “02”.
Example 4: + “1” + “1” + “2” Output: “112” Description: Although the first “1” operand is based on the numeric type conversion of its preceding unary + operator, it returns a string when concatenated with the second “1” operand, and then concatenated with the final “2” operand, producing the string “112”.
Example 5: “A” – “B” + “2” Output: “NaN2” Description: Since the – operator cannot be applied to strings and neither “A” nor “B” can be converted to A value, “-” B “produces NaN, which is then concatenated with the string” 2 “to produce” NaN2 “.
Example 6: “A” – “B” +2 Output: NaN Description: In the previous example, “A” – “B” produced NaN. But any operator applied to NaN and other numeric operands still produces NaN.
16. If the arraylist is too large, the following recursive code will cause a stack overflow. How do you solve this problem and still keep the recursive pattern?
var list = readHugeList(); var nextListItem = function() { var item = list.pop(); if (item) { // process the list item... nextListItem(); }};Copy the code
Potential stack overflows 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); }};Copy the code
Stack overflows are eliminated because the event loop handles recursion rather than 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, causing the call stack to be cleared. When the event queue runs a timeout event, the next item is processed and a timer is set to call nextListItem again. Therefore, the method is processed from beginning to end without a direct recursive call, so the call stack remains clean regardless of the number of iterations.
17. What are JavaScript “closures”? Let me give you an example.
A closure is an internal function that accesses variables in the scope chain of an external (enclosing) function. Closures can access variables in three ranges; Specifically :(1) variables within their own scope, (2) variables within the scope of closed functions, and (3) global variables.
Here’s an 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);
Copy the code
In the example above, the innerFunc, outerFunc, and global namespace variables are all in innerFunc scope. The above code produces the following output:
outerArg = 123
innerArg = 456
outerVar = a
innerVar = b
globalVar = xyz
Copy the code
What is the output of the following code:
for (var i = 0; i < 5; i++) {
setTimeout(function() { console.log(i); }, i * 1000 );
}
Copy the code
Explain your answer. How do I use closures here?
The code sample shown does not show the values 0,1,2,3, and 4, as might be expected; It says 5,5,5,5.
This is because every function executed within the loop will be executed after the entire loop is complete, so all functions refer to the last value stored in I, which is 5.
Closures can be used to prevent this problem by creating a unique scope for each iteration and storing each unique value of the variable in its scope, as follows:
for (var i = 0; i < 5; i++) {
(function(x) {
setTimeout(function() { console.log(x); }, x * 1000 );
})(i);
}
Copy the code
This produces the possible result of logging 0,1,2,3, and 4 to the console.
In the context of ES2015, you can simply use let instead of var in the original code:
for (let i = 0; i < 5; i++) {
setTimeout(function() { console.log(i); }, i * 1000 );
}
Copy the code
19. How many lines of code are printed 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));
Copy the code
Explain your answer.
This code outputs the following four lines:
0 || 1 = 1
1 || 2 = 1
0 && 1 = 0
1 && 2 = 2
Copy the code
In JavaScript, is | | and && are logical operators, when calculated from left to right to return to the first entirely sure “logical value”.
Or (| |) operator. In form for X | | Y expressions, first calculate X and interpreted as Boolean value. If this Boolean value is true, true (1) is returned and Y is not evaluated because the or condition has already been satisfied. But, if the Boolean value is “false”, we still don’t know X | | Y is true or false, until we assess Y, and interpreted as Boolean value.
Therefore, 0 | | 1 assessment is true (1), as 1 | | 2.
And (&&) operators. In an expression of the form X && Y, X is first evaluated and interpreted as a Boolean value. If this Boolean value is false, false (0) is returned and Y is not evaluated because the “and” condition has failed. However, if this Boolean value is “true”, we still don’t know if X && Y is true or false until we evaluate Y and interpret it as a Boolean value.
The interesting thing about the && operator, however, is that when the expression is evaluated as “true,” it returns the expression itself. This is good because it is treated as “true” in logical expressions, but can also be used to return the value if you care. This explains why, somewhat surprisingly, 1 && 2 returns 2 (when you might expect it to return true or 1).
What is the output of the following code when executed? Instructions.
console.log(false= ='0')
console.log(false= = ='0')
Copy the code
This code will print:
true
false
Copy the code
In JavaScript, there are two sets of equality operators. The triple equality operator === behaves like any traditional equality operator: if two expressions on either side have the same type and the same value, it evaluates to true. However, the double equal operator tries to force these values before comparing them. Therefore, it is common to use === instead of ==. For! = = v! = The same is true.
21. What is the output 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]);
Copy the code
The output of this code will be 456 (not 123).
Here’s why: When setting object properties, JavaScript implicitly concatenates parameter values. In this case, since b and C are both objects, they will both be converted to “[Object Object]”. Therefore, both a [b] and a [c] are equivalent to [” [object object] “] and can be used interchangeably. Therefore, setting or referencing [c] is exactly the same as setting or referencing [b].
22. The following code will be printed to the console.
console.log((function f(n){return ((n > 1) ? n * f(n-1) : n)})(10));
Copy the code
This code prints the value of 10 factorial (that is, 10! Or 3628800).
Here’s why:
The named function f () calls itself recursively until it calls f (1), which simply returns 1. So, here’s what it 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
Copy the code
23. Consider the following code snippet. What is the output of the console and why?
(function(x) {
return (function(y) {
console.log(x);
})(2)
})(1);
Copy the code
The output will be 1, even if the value of x is never set in the inner function. Here’s why:
As explained in our JavaScript recruitment guide, a closure is a function and all the variables or functions that are in scope when the closure is created. In JavaScript, closures are implemented as “internal functions”; A function defined within the body of another function. An important feature of closures is that the inner function can still access the variables of the outer function.
Therefore, in this example, because x is not defined in the inner function, a defined variable x is searched in the scope of the outer function with a value of 1.
24. The following code will be printed 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());Copy the code
What’s wrong with this code, and how to fix it.
This code will print:
undefined
John Doe
Copy the code
The first console.log print is undefined because we extract the method from the Hero object, so stoleSecretIdentity () is called in the global context (that is, the window object) where the _NAME attribute does not exist.
One way to fix the stoleSecretIdentity () function is as follows:
var stoleSecretIdentity = hero.getSecretIdentity.bind(hero);
Copy the code
Create a function that, given a DOM element on a page, accesses the element itself and all of its descendants.Not just its immediate children). For each element accessed, the function should pass that element to the provided callback function.
The arguments to this function should be:
- A DOM element
- A callback function (taking a DOM element as an argument)
A depth-first-search algorithm is used to access all elements in the tree (DOM). Here is a sample 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
}
}
Copy the code
27. Test your knowledge in JavaScript: What is the output of the following code?
var length = 10;
function fn() {
console.log(this.length);
}
var obj = {
length: 5.method: function(fn) {
fn();
arguments[0]();
}
};
obj.method(fn, 1);
Copy the code
Output:
10
2
Copy the code
Why not 10 and 5?
First, since fn is passed as an argument to the function method, the scope of the function fn (this) is the window. var length = 10; Declared at the window level. It can also be accessed as window.length or length or this.length (when this === window).
Method is bound to Object obj, which is called with fn and 1. Although the method accepts only one argument, it is called with two arguments already passed; The first is a function callback, and the others are just numbers.
When fn () is called in an internal method, which is passed as an argument at the global level, this.length will have access to the var length = 10 (global declaration) defined in Object obj instead of length = 5.
We now know that we can use the arguments [] array to access any number of arguments in a JavaScript function.
So Arguments0 simply calls fn (). In fn, the scope of this function becomes an array of arguments, and the length of the argument [] returns 2.
So the output will look like this.
28. Consider the following code. What is the output and why?
(function () {
try {
throw new Error(a); }catch (x) {
var x = 1, y = 2;
console.log(x);
}
console.log(x);
console.log(y); }) ();Copy the code
1
undefined
2
Copy the code
Var statements are suspended (without their value initialized) to the top of the global or function scope to which they belong, even if they are inside a with or catch block. However, the wrong identifier is only visible inside the catch block. It is equivalent to:
(function () {
var x, y; // outer and hoisted
try {
throw new Error(a); }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); }) ();Copy the code
29. What is the output of this code?
var x = 21;
var girl = function () {
console.log(x);
var x = 20;
};
girl ();
Copy the code
Twenty-one, it’s not twenty, it’s undefined
This is because JavaScript initialization is not suspended.
(Why doesn’t it display the global value of 21? The reason is that when the function executes, it checks for the presence of a local x variable but has not yet declared it, so it does not look for global variables.
How do you clone an object?
var obj = {a: 1 ,b: 2}
var objclone = Object.assign({},obj);
Copy the code
Objclone now has the value {a: 1, b: 2}, but points to a different object than obj.
But be aware of a potential flaw: Object.clone () only performs shallow copies, not deep copies. This means that nested objects are not copied. They still refer to the same nested object as the original:
let obj = {
a: 1.b: 2.c: {
age: 30}};var objclone = Object.assign({},obj);
console.log('objclone: ', objclone);
obj.c.age = 45;
console.log('After Change - obj: ', obj); // 45 - This also changes
console.log('After Change - objclone: ', objclone); / / 45
Copy the code
for (let i = 0; i < 5; i++) {
setTimeout(function() { console.log(i); }, i * 1000 );
}
Copy the code
31. What does this code print?
for (let i = 0; i < 5; i++) {
setTimeout(function() { console.log(i); }, i * 1000 );
}
Copy the code
It prints 0, 1, 2, 3, 4, because we’re using let here instead of var. The variable I is only visible in the block scope of the for loop.
What do the following lines output, and why?
console.log(1 < 2 < 3);
console.log(3 > 2 > 1);
Copy the code
The first statement returns true, as expected.
The second one returns false because of how the engine works on operator affinity for < and >. It compares from left to right, so 3> 2> 1 JavaScript translates as true> 1. True has the value 1, so it compares 1> 1, which is incorrect.
33, How do I add an element to the beginning of an array? How do YOU finally add one?
var myArray = ['a'.'b'.'c'.'d'];
myArray.push('end');
myArray.unshift('start');
console.log(myArray); // [""start"", ""a"", ""b"", ""c"", ""d"", ""end""]
Copy the code
With ES6, you can use the extension operator:
myArray = ['start'. myArray]; myArray = [...myArray,'end'];
Copy the code
Or, to put it simply:
myArray = ['start'. myArray,'end'];
Copy the code
34. Imagine you have code like this:
var a = [1.2.3];
Copy the code
A) Will it cause a crash?
a[10] = 99;
Copy the code
B) What is the output?
console.log(a[6]);
Copy the code
A) It won’t collapse. The JavaScript engine will make array slots 3 through 9 “empty slots”.
B) Here, a [6] will output undefined values, but the timeslot remains empty rather than undefined. In some cases, this can be an important nuance. For example, when map () is used, empty slots in the output of map () will remain empty, 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]
Copy the code
35, undefined == typeof NULL
This expression will be evaluated to true because NULL will be treated as any other undefined variable.
Note: JavaScript is case sensitive and we use NULL instead of NULL here.
36. What happens when the code returns?
console.log(typeof typeof 1);
Copy the code
string
Typeof 1 returns “number”, and Typeof “number” returns a string.
What does the following code output? Why is that?
var b = 1;
function outer(){
var b = 2
function inner(){
b++;
var b = 3;
console.log(b)
}
inner();
}
outer();
Copy the code
The output to the console will be “3”.
There are three closures in this example, each with its own var b declaration. When a variable is called, the closures are checked from local to global until an instance is found. Since the inner closure has its own b variable, this is the output.
In addition, since the code inside the promotion will be interpreted as follows:
function inner () {
var b; // b is undefined
b++; // b is NaN
b = 3; // b is 3
console.log(b); // output ""3""
}
Copy the code
There are more interviews than tricky technical questions, so these are just a guide. Not every “A” candidate worthy of hiring can answer all the questions, and not all of them are guaranteed to have “A” candidates. At the end of the day, recruiting is still an art, a science — and a lot of work. .