// Take some notes on the article can not be set to only visible and only published
// Original article address juejin.cn/post/684490…
First article: JS data type questions – concepts
1. What are the original JS data types? In JS, there are 7 primitive values, which are:
boolean null undefined number string symbol bigint
Reference data types: Object (including ordinary Object -Object, Array Object -Array, regular Object -RegExp, Date Object -Date, Math Function -Math, Function Object -Function)
//MDN is a collection of common JS objectsCopy the code
2. Say the result of the following operation and explain why.
person.age = 26
person = {
name: 'hzj',
age: 18
}
return person
}
const p1 = {
name: 'fyq',
age: 19
}
const p2 = test(p1)
console.log(p1) // -> ?
console.log(p2) // -> ?
Copy the code
Results:
P1: {name: "fyq", age: 26} p2: {name: "HZJ", age: 18}Copy the code
The reason: The person argument in test is the memory address of p1. Calling Person. age = 26 does change the value of P1, but then Person becomes the address of another memory space. And at the end, it returns the address of this other memory space, and assigns it to P2.
Person = {name: 'HZJ ', age: 18Copy the code
3. Is NULL an object? Why is that?
Conclusion: NULL is not an object.
Note: Typeof null outputs objects, but this is a long-standing JS Bug. In the original version of JS, the 32-bit system was used. For the sake of performance, the type information of the variable was stored at the low level. The beginning of 000 represents an object, while null represents all zeros, so it was wrongly judged as object.
4. Why can ‘1’.toString() be called? There are a few things you do with this statement:
var s = new Object('1');
s.toString();
s = null;
Copy the code
Step 1: Create an instance of the Object class. Notice why it’s not String? Because of Symbol and BigInt, calls to new give an error, and the ES6 specification currently does not recommend using new to create primitive wrapper classes. Step 2: Call the instance method. Step 3: Destroy the instance immediately after executing the method. The whole process reflects the nature of the basic wrapper types, which belong to the basic data types, including Boolean, Number, and String.
String Number Boolean has a wrapper object for the base typeCopy the code
Why doesn’t 5.0.1+0.2 equal 0.3?
0.1 and 0.2 will loop indefinitely after being converted to binary, truncating the extra bits due to the standard bit limit. This will already result in a loss of precision. The binary truncated by the floating-point decimal limit after being added will become 0.30000000000000004 when converted to decimal.
// Many decimals exceed the precision limit when convertingCopy the code
The second part: THE QUESTION of JS data type – inspection part
- Does typeOF determine the type correctly?
For primitive types, all but NULL can be called to display the correct type.
typeof 1 // 'number'
typeof '1' // 'string'
typeof undefined // 'undefined'
typeof true // 'boolean'
typeof Symbol() // 'symbol'
Copy the code
For reference data types, however, “object” is displayed except for functions.
typeof [] // 'object'
typeof {} // 'object'
typeof console.log // 'function'
Copy the code
Therefore, it is not appropriate to use typeof to determine the data typeof the object, but better to use instanceof, which is based on the principle of the prototype chain query, as long as the prototype chain, the judgment is always true
const Person = function() {}
const p1 = new Person()
p1 instanceof Person // true
var str1 = 'hello world'
str1 instanceof String // false
var str2 = new String('hello world')
str2 instanceof String // true
Copy the code
/ / Object. The prototype. ToString. Call () all types can be judged / / Array. The isArray ()Copy the code
- Can instanceof determine basic data types?
Can. For example:
class PrimitiveNumber {
static [Symbol.hasInstance](x) {
return typeof x === 'number'
}
}
console.log(111 instanceof PrimitiveNumber) // true
Copy the code
If you don’t know Symbol, look at the explanation of hasInstance on MDN.
This is a way of customizing the behavior of instanceof by redefining the original instanceof method as typeof so that you can determine the basic data types.
Static [symbol.hasInstance](x) can be defined as function methods on Object.prototype. InstanceOf is executed by defaultCopy the code
- Can you implement instanceof manually?
Core: The upward lookup of the prototype chain.
Function myInstanceof(left, right) {return false if(typeof left! == 'object' || left === null) return false; // Let proto = object.getProtoTypeof (left); // Let proto = object.getProtoTypeof (left); If (proto == null) return false; if(proto == null) return false; If (proto == right.prototype) return true; proto = Object.getPrototypeOf(proto); }}Copy the code
String
// The String global object is a constructor for a String or a sequence of charactersCopy the code
Article 3: THE QUESTION of JS data types – transformation
- [] = =! [] What was the result? Why is that?
==, the left and right sides need to be converted to numbers and then compared. [] converts to a number 0. ! [] is first converted to a Boolean. Since [] is a reference type converted to a Boolean value of true, therefore! [] is false, and then converted to a number, becomes 0. 0 == 0, the result is true
/ / there! Boolean == Convert type comparisonCopy the code
- What is the process by which objects are converted to primitive types?
Converting an object to a primitive type calls the built-in [ToPrimitive] function, for which the logic is as follows:
If the symbol.toprimitive () method is first called and then returns valueOf(), toString() is returned if converted to a primitive type, and an error is reported if neither method returns the primitive type
var obj = { value: 3, valueOf() { return 4; }, toString() { return '5' }, [Symbol.toPrimitive]() { return 6 } } console.log(obj + 1); / / output 7Copy the code
// Converting an object to a data type calls an object's built-in methodCopy the code
- If (a == 1 &&a == 2)
var a = {
value: 0,
valueOf: function() {
this.value++;
return this.value;
}
};
console.log(a == 1 && a == 2);//true
Copy the code
Talk about your understanding of closures
What is a closure?
A closure is a function that has access to variables in the scope of another function.Copy the code
MDN defines closures as: closures are functions that have access to free variables. (Arguments) Free variables refer to variables that are used in a function, but are neither function arguments nor local variables to the function.Copy the code
What causes closures? Must first understand the concept of the scope chain, actually very simple, there are only two kinds of scope in the ES5 — – the global scope and function scope, when to access a variable, the interpreter will first in the current scope find identifier, if not found, will go to the parent scope, until you find the variable identifier or not in the parent scope, this is the scope chain, Note that each subfunction copies the parent scope, forming a chain of scopes. Such as:
var a = 1; function f1() { var a = 2 function f2() { var a = 3; console.log(a); / / 3}}Copy the code
In this code, f1’s scope points to the global scope (Window) and itself, while F2’s scope points to the global scope (window), F1 and itself. In addition, the scope is searched from the bottom up until the global scope Window is found. If there is no global scope, an error is reported. It’s so simple! The essence of closures is that there are references to the parent scope in the current environment. Here’s another example:
function f1() { var a = 2 function f2() { console.log(a); //2 } return f2; } var x = f1(); x();Copy the code
Here x will take the variable in the parent scope and print 2. Because in the current environment, there is a reference to F2, which refers exactly to the scope of Window, F1, and F2. So F2 has access to the scoped variables of F1. Is it only the return function that generates a closure?
// The call produces a closure, and return is just a way of invoking itCopy the code
Going back to the essence of closures, we just need to make the reference to the parent scope exist, so we can also do this:
var f3;
function f1() {
var a = 2
f3 = function() {
console.log(a);
}
}
f1();
f3();
Copy the code
If f1 is executed and f3 is assigned a value, it is equivalent to saying that F3 now has access to the scope window, F1, and f3 itself. If f3 is searched from the bottom up, it recently found a in F1, so output 2.
In this case, there is a reference to the parent scope of the external variable F3, hence the closure, the form has changed, the essence has not changed. What are the representations of closures? Now that we understand the nature of this, let’s take a look at where in the real world closures can be represented.
1. Return a function. I just gave you an example.
2. Pass as a function parameter
var a = 1; function foo(){ var a = 2; function baz(){ console.log(a); } bar(baz); } function bar(fn){// this is the closure fn(); } // Print 2 instead of 1 foo();Copy the code
Whenever you use callbacks in timers, event listeners, Ajax requests, cross-window communication, Web Workers, or any asynchrony, you’re actually using closures.
The following closures hold only the window and the current scope.
// timer setTimeout(function timeHandler(){console.log('111'); }, 100) // Event Listener $('#app').click(function(){console.log('DOM Listener'); })Copy the code
IIFE(execute function expression immediately) creates a closure that holds both the global scope window and the scope of the current function, so variables can be global.
var a = 2; (function IIFE(){// Output 2 console.log(a); }) ();Copy the code
How to solve the following loop output problem?
for(var i = 1; i <= 5; i++){ (function(j){ setTimeout(function timer(){ console.log(j) }, 0) })(i) }Copy the code
Why print all 6’s? How can I improve it so that it prints 1,2,3,4,5? SetTimeout is a macro task. Due to the single-threaded eventLoop mechanism in JS, macro tasks are executed after the execution of the same step task in the main thread. Therefore, the callbacks in setTimeout will be executed successively after the loop ends. I found I, now the loop is over, I becomes 6. So it prints all 6’s. Solution: 1, use IIFE(execute function expression immediately) when each for loop, pass the I variable to the timer
for(var i = 1; i <= 5; i++){ (function(j){ setTimeout(function timer(){ console.log(j) }, 0) })(i) }Copy the code
2. Pass a third parameter to the timer as the first parameter of the timer function
for(var i=1; i<=5; i++){ setTimeout(function timer(j){ console.log(j) }, 0, i) }Copy the code
3. Use let in ES6
for(let i = 1; i <= 5; i++){
setTimeout(function timer(){
console.log(i)
},0)
}
Copy the code
Let revolutionizes JS, changing functional scope of JS into block-level scope, and scope chain no longer exists after let is used. The scope of the code is block-level, as shown in the code above:
// i = 1
{
setTimeout(function timer(){
console.log(1)
},0)
}
// i = 2
{
setTimeout(function timer(){
console.log(2)
},0)
}
// i = 3
...
Copy the code
Talk about your understanding of the prototype chain
1. What is the relationship between stereotype objects and constructors? In JavaScript, whenever you define a function data type (plain function, class), you are born with a prototype property that points to the function’s prototype object. When the function goes throughWhen new is called, this function becomes a constructorReturns a brand new instance object with a __proto__ attribute pointing to the constructor’s prototype object.2. Can you describe the prototype chain? JavaScript objects point to their parent class objects through __proto__ until they point to Object objects, thus forming a chain of prototype-pointing, known as a prototype chain.Object hasOwnProperty() to check whether the object itself contains the property. Using in to check whether the object contains a property, if not in the object but in the prototype chain, also returns true
Article 6: How to implement JS inheritance?
The ES6 extends
// This article lists other methodsCopy the code