1. Let, const, var

(1) Block-level scope: block scope is included by {}, let and const have block-level scope, var does not have block-level scope. Block-level scopes solve two problems in ES5:

  • Inner variables may override outer variables
  • Loop variables used to count are leaked as global variables

(2) Variable promotion: var has variable promotion, let and const have no variable promotion, that is, variables can only be used after the declaration, otherwise an error will be reported.

(3) Add global attribute: browser global object is window, Node global object is global. Var declares a global variable and adds it as a property of the global object, but let and const do not.

(4) Repeated declaration: when var declares a variable, it can repeat the declaration of the variable, and the variable with the same name declared after will overwrite the traversal declared before. Const and let do not allow variables to be declared twice.

(5) Temporary dead zone: a variable is not available until it is declared with let, const. This is grammatically called a temporary dead zone. Variables declared using VAR do not have temporary dead zones.

(6) Initial value setting: When declaring variables, var and let do not need to set initial values. A const declaration variable must have an initial value.

(7) Pointer to: let and const are new syntax for creating variables in ES6. Let creates variables that can be pointer pointed to (can be reassigned). But const variables are not allowed to change the pointer.

The difference between var let const
Whether there are block-level scopes x ✔ ️ ✔ ️
Whether there is variable promotion ✔ ️ x x
Whether to add global attributes ✔ ️ x x
Whether variables can be declared repeatedly ✔ ️ x x
Is there a temporary dead zone x ✔ ️ ✔ ️
Whether the initial value must be set x x ✔ ️
Can you change the pointer ✔ ️ ✔ ️ x

In the for loop

for (var i = 0; i < 5; ++ I) {// loop logic} console.log(I); // 5 This happens because the iteration variable holds the value that caused the loop to exit when exiting the loop. This problem does not occur with letCopy the code

2. Can properties of const objects be modified

What const guarantees is not that the value of a variable cannot be changed, but that the memory address to which the variable refers cannot be changed. For data of primitive types (values, strings, booleans), the value is stored at the memory address to which the variable points and is therefore equivalent to a constant.

But in the case of reference types (mainly objects and arrays), a variable points to a memory address and holds only a pointer. Const guarantees that the pointer is fixed, and that the data structure it points to is mutable.

3. What happens if you create a new arrow function

Arrow functions are New to ES6. They don’t have a prototype, don’t have their own this pointer, and can’t use arguments.

The implementation of the new operator is as follows:

  1. Create an object
  2. Assign the constructor’s scope to the new object (that is, point the object’s __proto__ attribute to the constructor’s Prototype attribute)
  3. Refers to the code in the constructor, where this refers to the object (that is, to add properties and methods to the object)
  4. Return a new object

Therefore, the second and third steps above, the arrow function is impossible to execute.

4. Difference between arrow function and ordinary function

(1) Arrow functions are more concise than ordinary functions

  • If there are no arguments, just write an empty parenthesis
  • If you have only one argument, you can omit the parentheses for the argument
  • If there are multiple arguments, separate them with commas
  • If the function body returns only one sentence, you can omit the braces
  • If the function body does not require a return value and is a one-sentence statement, you can prefix the statement with the void keyword. The most common is to call a function:
let fn = () => void doesNotReturn();
Copy the code

(2) Arrow functions do not have their own this

The arrow function doesn’t create its own this, so it doesn’t have its own this, it just inherits this at the level above its scope. So the orientation of this in the arrow function is already defined when it is defined, and will not change after that.

(3) The this pointer inherited from the arrow function never changes

var id = 'GLOBAL'; var obj = { id: 'OBJ', a: function(){ console.log(this.id); }, b: () => { console.log(this.id); }}; obj.a(); // 'OBJ' obj.b(); // 'GLOBAL' new obj.a() // undefined new obj.b() // Uncaught TypeError: obj.b is not a constructorCopy the code

The object obj’s method B is defined using the arrow function. This in this function always refers to this in the global execution environment in which it was defined. Even though this function is called as a method on obj, this still refers to the Window object. Note that the curly braces {} that define the object do not form a single execution environment; it is still in the global execution environment.

(4) Call (), apply(), bind() and other methods cannot change the direction of this in the arrow function

var id = 'Global';
let fun1 = () => {
    console.log(this.id)
};
fun1();                     // 'Global'
fun1.call({id: 'Obj'});     // 'Global'
fun1.apply({id: 'Obj'});    // 'Global'
fun1.bind({id: 'Obj'})();   // 'Global'
Copy the code

(5) Arrow functions cannot be used as constructors

The constructor in the new step was mentioned above, but in fact the second step is to point this in the function to the object. However, arrow functions cannot be used as constructors because they do not have their own this, and this refers to the outer execution environment and cannot be changed.

(6) Arrow functions have no arguments of their own

Arrow functions have no arguments objects of their own. Calling Arguments in the arrow function actually gets the arguments value for its outer function.

Arrow function has no prototype

(8) Arrow functions cannot be used as Generator functions and the yeild keyword cannot be used

5. Arrow functionthisWhere does it point?

Unlike traditional JavaScript functions, arrow functions do not have their own this. This captures the value of this in their context as their own this, and is not called by new because it does not have its own this. This so-called this is not going to change.

You can use Babel to understand the arrow function:

// ES6 const obj = { getArrow() { return () => { console.log(this === obj); }; }}Copy the code

After the transformation:

Var object = {getArrow: function getArrow() {var _this = this; return function () { console.log(_this === obj); }; }};Copy the code

6. Extend the functions and usage scenarios of operators

(1) Object extension operator

Object extension operator (…) Retrieves all traversable properties from the parameter object and copies them to the current object.

let bar = { a: 1, b: 2 }; let baz = { ... bar }; // { a: 1, b: 2 }Copy the code

The above method is actually equivalent to:

let bar = { a: 1, b: 2 };
let baz = Object.assign({}, bar); // { a: 1, b: 2 }
Copy the code

The Object.assign method is used to merge objects. It copies all the enumerable attributes of the source Object to the target Object.

The object. assign method takes the first argument to the target Object and the rest to the source Object. If the target object has an attribute with the same name as the source object, or if multiple source objects have an attribute with the same name, the later attribute overrides the previous one.

Similarly, if a user-defined attribute is placed after an extension operator, the attributes of the same name inside the extension operator will be overwritten.

let bar = {a: 1, b: 2}; let baz = {... bar, ... {a:2, b: 4}}; // {a: 2, b: 4}Copy the code

Using the above features, you can easily modify some attributes of an object. The Reducer function in REdux must be a pure function. The state object requirements in reducer cannot be directly modified. We can copy all the objects in the modified path through the extension operator and then return a new object.

Note that the extension operator is a shallow copy of an object instance.

(2) Array extension operator

The array extension operator converts an array into a comma-separated sequence of arguments, expanding only one layer at a time.

console.log(... [1, 2, 3]) // 1 2 3 console.log(... [1, [2, 3, 4], 5]) // 1 [2, 3, 4] 5Copy the code

Here is an extension operator for arrays:

  • Converts an array to a sequence of parameters
function add(x, y) { return x + y; } const numbers = [1, 2]; add(... numbers) // 3Copy the code
  • Copy the array
const arr1 = [1, 2];
const arr2 = [...arr1];
Copy the code

Remember: Extension operators (…) It is used to copy all traversable properties of the parameter object into the current object, where the parameter object is an array, and all the objects in the array are the base data types, and copy all the base data types into the new array.

  • Merge array

If you want to merge an array within an array, you can do this:

const arr1 = ['two', 'three']; const arr2 = ['one', ...arr1, 'four', 'five']; // ["one", "two", "three", "four", "five"]Copy the code
  • The extension operator is used in combination with destruct assignment to generate arrays
const [first, ...rest] = [1, 2, 3, 4, 5];
first // 1
rest  // [2, 3, 4, 5]
Copy the code

Note: If an extension operator is used for array assignment, it must be placed in the last bit of the argument, otherwise an error will be reported.

const [...rest, last] = [1, 2, 3, 4, 5]; / / error const [first, the rest of..., the last] = [1, 2, 3, 4, 5]. / / an errorCopy the code
  • Turn a string into a real array
[...'hello']    // [ "h", "e", "l", "l", "o" ]
Copy the code
  • Any object of the Iterator interface can be converted to a true array using the extension operator

A common use is to convert certain data structures into arrays:

// arguments object function foo() {const args = [...arguments]; }Copy the code

Used to replace the es5 Array. Prototype. Slice. The call (the arguments) writing.

  • useMathThe getvalue () function gets a specific value from an array
const numbers = [9, 4, 7, 1]; Math.min(... numbers); // 1 Math.max(... numbers); / / 9Copy the code

7. What functions can Proxy achieve?

In Vue3.0, the original Object. DefineProperty is replaced by Proxy to achieve data responsiveness.

Proxy is a new feature in ES6 that allows you to use operations in custom objects.

let p = new Proxy(target, handler)
Copy the code

Target represents the object to which the agent is to be added. The handler uses custom operations in the object, such as custom set or get functions.

The following uses Proxy to implement a data response:

let onWatch = (obj, setBind, getLogger) => { let handler = { get(target, property, receiver) { getLogger(target, property) return Reflect.get(target, property, receiver) }, set(target, property, value, receiver) { setBind(value, property) return Reflect.set(target, property, value) } } return new Proxy(obj, handler) } let obj = { a: 1} let p = onWatch(obj, (v, property) => {console.log(' listen to ${property} change to ${v} ')}, (target, Property) = > {the console. The log (` '${property}' = ${target [property]} `)}) p.a = 2 / / listen to attribute a change p.a / / 'a' = 2Copy the code

In the above code, we inserted our function logic into the original logic by customizing the set and get functions to notify when we read or write any property of the object.

8. Understanding object and array deconstruction

Deconstruction is a new pattern for extracting data from objects or arrays.

1) Array deconstruction In array deconstruction, to extract the desired data with the position of the element as the matching condition:

const [a, b, c] = [1, 2, 3]
Copy the code

Finally, a, B, and C are assigned the value of the 0, 1, and 2 index bits of the array respectively:

The values of the 0, 1, and 2 index bits in the array are mapped exactly to the 0, 1, and 2 variables on the left. This is how array deconstruction works. You can also achieve accurate extraction of several elements in the array by setting empty placeholders for the left variable array:

Const [a, c] = [1, 2, 3]Copy the code

By leaving the middle bit blank, we can smoothly assign the first and last bits of the array to variables A and C:

Object deconstruction is slightly more complex and powerful than array structures. When deconstructing an object, the name of the attribute is used as the matching condition to extract the desired data. Now define an object:

const stu = {
  name: 'Bob',
  age: 24
}
Copy the code

If you want to deconstruct its two properties, you can do this:

const { name, age } = stu
Copy the code

This gives us name and age, which are at the same level as stu:

Note that object deconstruction is based strictly on the attribute name, so the result is the same even if the name and age are swapped:

const { age, name } = stu
Copy the code

9. How do I extract specified attributes from highly nested objects?

Sometimes you encounter objects that are very deeply nested:

const school = {
   classes: {
      stu: {
         name: 'Bob',
         age: 24,
      }
   }
}
Copy the code

The name variable here has four nested layers, so if you still try to extract it the old way:

const { name } = school
Copy the code

This does not work because the school object itself does not have a name property. Name is in the “son’s son” object of the school object. A clumsy way to extract the name is to deconstruct it layer by layer:

const { classes } = school
const { stu } = classes
const { name } = stu
name // 'Bob'
Copy the code

But there is a more standard way to solve this problem with a single line of code:

const { classes: { stu: { name } }} = school
       
console.log(name)  // 'Bob'
Copy the code

To the right of the deconstructed variable name, further deconstruct it with the colon +{target attribute name} until the target data is available.

10. Rest parameters

When used with function parameters, the extension operator can also consolidate a separate sequence of arguments into an array:

function mutiple(... args) { let result = 1; for (var val of args) { result *= val; } return result; } mutiple(1, 2, 3, 4) // 24Copy the code

Here, we pass in four separate arguments to mutiple, but if we try to print the value of args in mutiple, we’ll see that it’s an array:

function mutiple(... args) { console.log(args) } mutiple(1, 2, 3, 4) // [1, 2, 3, 4]Copy the code

This is… The rest operator adds another layer of power by converging multiple input arguments to a function into an array. This is often used to get extra arguments to a function, or to deal with an indeterminate number of arguments, as above.

Template syntax and string handling in ES6

ES6 introduces the concept of “template syntax”. Before ES6, concatenating strings was cumbersome:

var name = 'css'   
var career = 'coder' 
var hobby = ['coding', 'writing']
var finalString = 'my name is ' + name + ', I work as a ' + career + ', I love ' + hobby[0] + ' and ' + hobby[1]
Copy the code

Just a few variables, so many plus signs, and always be careful about spacing and punctuation in the wrong place. But with template strings, concatenation difficulty plummets:

var name = 'css'   
var career = 'coder' 
var hobby = ['coding', 'writing']
var finalString = `my name is ${name}, I work as a ${career} I love ${hobby[0]} and ${hobby[1]}`
Copy the code

Strings are not only easier to spell, they are also easier to read, and the overall quality of the code is better. This is the first advantage of template strings — they allow variables to be embedded as ${}. But that’s not the point. Template strings have two key advantages:

  • In template strings, whitespace, indentation, and newlines are preserved
  • Template strings fully support “operation” expressions, which can be evaluated in ${}

Based on the first point, you can write HTML code directly in template strings without any problems:

Let the list = ` < ul > < li > list item 1 < / li > < li > list item 2 < / li > < / ul > `; console.log(message); // Correct output, no errorCopy the code

Based on the second point, we can do some simple calculations and calls by dropping ${} :

Function add(a, b) {const finalString = '${a} + ${b} = ${a+b}' console.log(finalString)} add(1, 2)Copy the code

In addition to template syntax, a series of string methods have been added to ES6 to improve development efficiency:

(1) Existence check: In the past, only indexOf > -1 was used to determine whether a character/string was in a string. ES6 now provides three methods: includes, startsWith, and endsWith, all of which return a Boolean value to tell you if they exist.

  • Includes: Determines the relationship between strings and substrings.
const son = 'haha' 
const father = 'xixi haha hehe'
father.includes(son) // true
Copy the code
  • StartsWith: Determines whether a string begins with a/string character:
const father = 'xixi haha hehe'
father.startsWith('haha') // false
father.startsWith('xixi') // true
Copy the code
  • EndsWith: checks whether a string endsWith a string or not:
const father = 'xixi haha hehe'
father.endsWith('hehe') // true
Copy the code

(2) Automatic repetition: You can repeat the same string multiple times by using the repeat method:

const sourceCode = 'repeat for 3 times; ' const repeated = sourceCode.repeat(3) console.log(repeated) // repeat for 3 times; repeat for 3 times; repeat for 3 times;Copy the code