1. Data types

Js data types are divided into two categories, nine data types:

  1. Object type
  2. The original type

Primitive types are divided into seven basic types:

  1. string
  2. number
  3. boolean
  4. symbol
  5. null
  6. undefined
  7. bigInt

There are two types of objects:

  1. object
  2. function

Object is divided into:

  1. Array
  2. RegExp
  3. Date
  4. Map
  5. Set
  6. Math
  7. .

The primitive type is stored on the stack, and the object type is stored on the heap, but its reference is still on the stack

Variables in stack memory are usually of known size or upper bound, while objects stored in heap memory are usually of variable size. This is why NULL is stored in stack memory as an object variable.

Can we change the value of const?

The answer is partly yes and partly no. The basic type defined by const cannot be changed, but the defined object can be changed by, for example, modifying the object properties. When we define const objects, we mean Pointers. The heap pointer to a const object is fixed, but the size and properties of the heap are not fixed. For the underlying variable, const values are the same as Pointers to const objects. Each time a const or let is used to initialize a variable, the stack is first traversed to see if there is a variable with the same name. An error is returned if there isCopy the code

Initializations with the new keyword are not stored in stack memory, and new instances are generated based on the constructor, which generates objects instead of primitive types

var a = new String('123')
var b = String('123')
var c = '123'
console.log(a==b, a===b, b==c, b===c, a==c, a===c)	
>>> true false true true true false
console.log(typeof a)
>>> 'object'
Copy the code

We can see that new a String produces an object, whereas literal assignment and factory mode produce a String. But according to our analysis above, the size is relatively fixed and you can expect even objects to be stored on the stack, like NULL, so why isn’t this one

var a = new String('123')
var b = new String('123')
console.log(a==b, a===b)
>>> false false
Copy the code

Obviously, if a and B are stored in stack memory, they should be obviously equal, just as null === null is true, but they are not equal, indicating that both are stored in heap memory and pointer pointing is inconsistent.

Now, if you think about what we’re talking about when we talk about value types and reference types we’re talking about stack memory variables and heap memory variables, and if you think about value passing and reference passing, deep copy and shallow copy, they’re all centered around stack memory, one dealing with values, one dealing with Pointers.

2. Type judgment

2.1 typeof

All primitive types except null can be determined by typeof. For object types, typeof can only specify the typeof a function as function and all other types as object.

2.2 instanceof

Instanceof internally determines whether it is an instanceof a constructor function through a prototype chain, which is often used to determine specific object types.

// true
[].constructor === Array
Copy the code

2.3 the Object. The prototype. ToString

3.4 isXXX API

3. Type conversion

Type conversions fall into two categories: cast and implicit.

3.1 Forced Conversion

Number(false) // -> 0
Number('1') // -> 1
Number('zb') // -> NaN
(1).toString() // '1'
Copy the code

Boolean transfer rule:

  • Undefined, null, false, NaN, ”, 0, and -0 are all converted to false.
  • All other values are converted to true, including all objects.

Rules for transferring numbers:

  • True is 1 and false is 0
  • Null = 0, undefined = NaN, symbol error
  • String looks at the content, if it is a number or base value, normal, otherwise NaN
  • The rule of implicit conversions of objects

3.2 Implicit conversion

  1. If the types are the same, no type conversion is required
  2. If one of the operators is null or undefined, the other operator must be null or undefined to return true, otherwise false
  3. If one of them is of type Symbol, return false
  4. If both operation values are of type string and number. That will convert the string to a number
  5. If an operation value is Boolean, convert to number
  6. If an operation is object and the other object is string, number, or symbol, object is converted to its original type
Null == undefined // true Rule 2 NULL == 0 // False Rule 2 "== 0 // true Rule 4 '123' == 123 // true Rule 4 0 == false // true 1 == true // true var a = {value:0, valueOf:function(){ this.value ++ return this.value } } console.log(a==1 & a==2&&a==3) // trueCopy the code

4.this reference

  1. See where the function is called.
  2. Is there an object to the left of the dot? If so, it is a reference to “this”. If not, proceed to step 3.
  3. Is this function called with “call”, “apply”, or “bind”? If so, it explicitly specifies a reference to “this”. If not, proceed to Step 4.
  4. Is this function called with “new”? If so, “this” points to the newly created object of the JavaScript interpreter. If not, proceed to Step 5.
  5. Is it in strict mode? If so, “this” is undefined. If not, proceed to step 6.
  6. JavaScript is weird because “this” points to the “window” object.
  7. The arrow function does not have its own this in its scope; if this is used, it points to the value of this in the scope in which it was defined

5. Scopes and closures

5.1 Compilation Principles

There are three stages of compilation: word segmentation/lexical analysis, parsing/parsing, and code generation.

  1. Word segmentation/lexical analysis: Decompose a string of characters into meaningful code, var a = 2; Will be decomposed into var, a, =, 2,;
  2. Parsing/parsing: Converts lexical units into a hierarchical nested tree of elements that represents the syntax structure of the program. This tree is called an abstract syntax tree (AST), referring to the corresponding tree structure of source code syntax. That is, for the source code of a specific programming language, the statements in the source code are mapped to each node in the tree in the form of a syntax tree
  3. Code generation: Convert the AST into executable code

So let’s take var a = 2; Break it down to see how the engine and its friends work together:

Compiler will this program first broken down into a lexical units, then the lexical unit parsed into an object tree, in executing code phase, meet var. A, the compiler will ask scope if there is a this variable, if so, the compiler will ignore the statement to compile, if not, will demand scope statement this variable, named a, When a = 2, the scope is asked if a exists, and if so, the value is assigned. If not, the scope will throw an exception.

The engine performs an LHS query for variable A. The other type of lookup is called RHS. If the purpose of the lookup is to assign a value to a variable, an LHS query is used; If the goal is to get the value of a variable, RHS queries are used.

function foo(a) { var b = a; return a + b; } var c = foo( 2 ); // 1. Find all LHS queries (there are three!) c = .. ; , a = 2 (implicit variable assignment), b =.. // 2. Find all RHS queries (there are four!) foo(2.. , = a; , a.. ,.. bCopy the code

5.2 the precompiled

Function declarations are improved overall, variable declarations are improved

Function test(){console.log('a')} console.log(a) var a = 123Copy the code

There are four steps to precompiling:

  1. Creating an AO Object
  2. Find the parameter and variable declaration and use the variable declaration and parameter name as the AO property name with the value undefined
  3. Unify argument values and parameters
  4. Find the function declaration inside the function body and assign the value to the function body
function fn(a){ console.log(a) var a = 123 console.log(a) function a(){} console.log(a) var b = function b(){} Console.log (b) function d(){}} fn(1) prints the following: // function a(){} // 123 // 123 // function b(){} // Function declaration is improvedCopy the code

The precompilation process is as follows:

  • Creating an AO Object
  • Find the parameter and variable declaration and use the variable declaration and parameter name as the AO property name with the value undefined

AO:{ a:undefined b:undefined d:undefined }

  • Unify argument values and parameters

AO:{ a:1 b:undefined d:undefined }

  • Find the function declaration inside the function body and assign the value to the function body

AO:{ a:function a(){} b:undefined d:function d(){} }

Function execution: Execute in sequence

Example:

global = 100 function fn(){ console.log(global) global = 200 console.log(global) var global = 300 } fn() var global // The output is as follows: undefined 200Copy the code

When a function is executed, it will look for the global inside the function first. If there is no global inside the function, it will look for the higher level. The precompilation process inside a function:

  • Creating an AO Object
  • Find the parameter and variable declaration and use the variable declaration and parameter name as the AO property name with the value undefined

AO = {global: undefined}

  • Unify argument values and parameters

AO = {global: undefined}

  • Find the function declaration inside the function body and assign the value to the function body

AO = {global: undefined} is executed in order, so the first console.log() prints the underpay, and global will not be assigned until global = 200

5.3 scope

[[scope]] every JavaScript function is an object. Some properties of the object are accessible to us, but others are not. These properties are only accessible to the JavaScript engine. It stores a collection of run-time contexts.

JavaScript uses lexical scope (static scope), and the scope of a function is determined at function definition time (writing phase). The opposite of lexical scope is dynamic scope, where the scope of a function is determined at the time the function is called. JavaScript uses static scope, this uses dynamic scope:

var value = 1; function foo() { console.log(value); } function bar() { var value = 2; foo(); } bar(); / / print 1Copy the code

5.4 the closure

First, the correct definition of a closure is that a function is a closure if it can access external variables, not necessarily return a function.

var a = []; for (var i = 0; i < 10; i++) { a[i] = function () { console.log(i); }; } a[5](); / / 10Copy the code

A [0] =function(){console.log(I)},a[1]=function(){console.log(I)},a[1]=function(){console.log(I)},… Console.log () is only executed when a5 is called, and I has already changed to 10, so whatever I is in a[I] will print 10

The title

// 1 for ( var i = 0 ; i < 5; i++ ) { setTimeout(function(){ console.log(i); }, 0); } // 5 5 5 5 5 // 2 for ( var i = 0 ; i < 5; i++ ) { (function(j){ setTimeout(function(){ console.log(j); }, 0); })(i); // setTimeout(function(j) {// console.log(j); // }, 0, i); } // 0 1 2 3 4 setTimeout(function(j) { console.log(j); }, 0, i); // 3 for ( let i = 0 ; i < 5; i++ ) { setTimeout(function(){ console.log(i); }, 0); } // 0 1 2 3 4 // 4 var scope = 'global scope'; function checkscope(){ var scope = 'local scope'; console.log(scope); } // local scope // 5 var scope = 'global scope'; function checkscope(){ var scope = 'local scope'; return function f(){ console.log(scope); }; } var fn = checkscope(); console.log(fn()); // local scope // 6 var scope = 'global scope'; function checkscope(){ var scope = 'local scope'; return function f(){ console.log(scope); }; } checkscope()(); // local scope var obj = { name: 'tom', sayName() { console.log(this.name); } } obj.sayName(); // tom var obj = { name: 'tom', sayName() { var name = 'alan'; console.log(this.name); } } obj.sayName(); // 'tom' var name = 'jerry'; var obj = { name : 'tom', sayName(){ return function(){ console.log(this.name); }; }}; obj.sayName()(); SayName = 'jerry'; // jerry = 'jerry'; var obj = { name: 'tom', sayName() { var name = 'alan'; console.log(this.name); }}; var sayName = obj.sayName; The sayName function assigned to obj is not executed. When executed, the scope is changed. This points to window, and window.name is the empty string sayName(); // '' // jerry function fun(a,b) { console.log(b) return { fun: function(c) { return fun(c,a); }}; } var d = fun(0); // undefined d.fun(1); // 2 0 d.fun(2); // 2 0 d.fun(3); // 2 0 var d1 = fun(0).fun(1).fun(2).fun(3); // 2 undefined 2 0 // 2 1 // 2 2 var d2 = fun(0).fun(1); d2.fun(2); // 2 undefined // 2 0 // 2 1 // 2 1 d2.fun(3); / / {fun: ƒ}Copy the code

6.new

Process of new:

  1. The freshman became an object
  2. Object attached to the constructor prototype and bound to this
  3. Execute the constructor code
  4. Return a new object

The examination site:

  • What did New do?
  • What happens when new returns different types?
  • The implementation process of handwriting new

7. The prototype

  • All objects have a property proto that points to an object, the prototype
  • Each object’s prototype can be found by constructor, and the constructor can be found by prototype
  • All functions can find Function objects via proto
  • All objects can be found through proto
  • Objects are connected by PROTO, which is called a prototype chain. Properties that do not currently exist on an Object can be searched up the prototype chain until the top Object is null

Inherited 8.

8.1 Inheritance of prototype chain

Each constructor has a prototype object, which in turn contains a pointer to the constructor, and an instance contains a pointer to the prototype object. (Memory is shared; when one changes, the other changes, and the pointer to the constructor changes.)

Function Parent1(){this.name = 'Parent1' this.play = [1,2,3]} function Child1(){this.type = 'child2'} Child1.prototype = new Parent1() console.log(new Child1()) var s1 = new Child1() var s2 = new Child1() s1.play.push(4) The console. The log (s1) play, s2. Play) / / [1, 2, 3, 4] [1, 2, 3, 4]Copy the code

8.2 Constructor Inheritance (with call)

The prototypical methods of the parent class are not inherited, only the attributes and methods

function Parent1(){ this.name = 'parent1' } Parent1.prototype.getName = function(){ return this.name } function Child1(){ Parent1.call(this) this.type = 'child1' } let child = new Child1() console.log(child) // {name:'parent1',type:'child1'} console.log(child.getname ()) // ErrorCopy the code

8.3 Combination Inheritance

Function Parent3 () {enclosing name = 'Parent3' this. Play = [1, 2, 3]} Parent3. Prototype. GetName = function () {return this.name } function Child3(){ Parent3.call(this) this.type = 'child3' } Child3.prototype = new Parent3() Child3.prototype.constructor = Child3 var s3 = new Child3() var s4 = new Child3() s3.play.push(4) Console. log(s3.play,s4.play) // [1,2,3,4] [1,2,3] console.log(s3.getname ()) // parent3 console.log(s4.getname ()) // parent3Copy the code

8.4 Original type inheritance (it may be tampered with if it has the same properties)

let parent4 = {
    name:'parent4',
    friends:["p1","p2","p3"],
    getName:function(){
        return this.name    
    }
}
let person4 = Object.create(parent4)
person4.name = "tom"
person4.friends.push("jerry")
let person5 = Object.create(parent4)
person5.friends.push("lucy")
console.log(person4.name) // "tom"
console.log(person4.name === person4.getName()) // true
console.log(person5.name) // parent4
console.log(person4.friends) // ["p1","p2","p3","jerry","lucy"]
console.log(person5.friends)//  ["p1","p2","p3","jerry","lucy"]
Copy the code

8.5 Parasitic inheritance

Using primitive inheritance, you can get a shallow copy of the target object, and then use this shallow copy to enhance it by adding methods

let parent5 = {
    name:'parent5',
    friends:["p1","p2","p3"],
    getName:function(){
        return this.name    
    }
}
function clone(original){
    let clone = Object.create(original)
    clone.getFriends = function(){
        return this.friends    
    }
    return clone
}
let person5 = clone(parent5)
console.log(person5.getName())  // parent5
console.log(person5.getFriends()) // ["p1","p2","p3"]
Copy the code

8.6 Parasitic combination inheritance

function clone(parent,child){ child.prototype = Object.create(parent.prototype) child.prototype.constructor = child } The function Parent6 () {enclosing name = 'Parent6' this. Play = [1, 2, 3]} Parent6. Prototype. GetName = function () {return this. The name  } function Child6(){ Parent6.call(this) this.friends = 'child5' } clone(Parent6,Child6) Child6.prototype.getFriends = function(){ return this.friends } let person6 = new Child6() console.log(person6) // {name: "parent6", play: [1, 2, 3], friends: "child5}" the console. The log (person6. The getName ()) / / parent6 console.log(person6.getFriends()) // child5Copy the code

8.7 Holy Grail Mode

function inherit(Target,Origin){ function F(){} F.prototype = Origin.prototype Target.prototype = new F() Target. The prototype. The constuctor = Target Target. The prototype. Uber = Origin. The prototype} / / the above function can write var inherit = (function () {  var F = function (){} return function(Target,Origin){ F.prototype = Origin.prototype Target.prototype = new F() Target. The prototype. The constuctor = Target Target. The prototype. Uber = Origin. The prototype}} ()) / / write, Function Father(){} function Son(){} inherit(Son,Father) var Son = new Son() var Father = new Father()Copy the code

If you want to call a function continuously, you can write it like this

var obj = {
    add:function(){
        console.log('add')
        return this
    },
    push:function(){
        console.log('push')
        return this
    },
    slice:function(){
        console.log('slice')
        return this
    }
}

obj.add().push().slice()
Copy the code
var obj = {
    fn1:{name:'fn1'},
    fn2:{name:'fn2'},
    fn3:{name:'fn3'},
    output:function(num){
        return this['fn' + num]
    }
}  
obj.output(1)
//{name: "fn1"}
Copy the code

Lift to ask:

Var num = 123 num.tostring () //"123" true.tostring () //"true" '123'.tostring () //"123" [].tostring () // {} obj.toString() "[object Object]"Copy the code

Because of the String, Number, Boolean, Array on the prototype has rewritten the toString method, the Object without rewriting, so the priority calls itself the prototype method, if you want to call without rewriting method, can use a call to change this point, Object. The prototype. ToString. Call (toSting value)

Object.create() differs from new

// new function Parent(){this.name = 'Parent' this.play = [1,2,3]} function Child(){this.type = 'Child'} var Parent = new Parent() Child.prototype = parent Child.prototype.constructor = Child let child = new Child(); Console. log(parent. Constructor === child.constructor) parent. Constructor === child.constructor // true both point to child // Object.create() function Parent(){this.name = 'Parent' this.play = [1,2,3]} function Child(){this.type = 'Child'} let parent = new Parent(); Child.prototype = Object.create(new Parent()) Child.prototype.constructor = Child let child = new Child(); Console. log(parent. Constructor === child.constructor) // native constructor function parent (){this.name = 'parent' this.play = [1,2,3]} function Child(){this.type = 'Child'} let parent = new parent (); Child.prototype = parent var F = function() {} // let f = new F(); Create Child. Prototype = new F(); // Child.prototype.constructor = Child; // let child = new Child(); // console.log(parent. Constructor === child.constructor) // false points to their respective constructorsCopy the code

Common test

  • How to implement inheritance in JS
  • How inheritance through stereotypes is different from class
  • Handwriting any kind of prototype inheritance

9. Dark and light copy

9.1 shallow copy

We can implement shallow copies by assigning, extending operators, and so on:

let a = { age: 1 } let b = Object.assign({}, a) a.age = 2 console.log(b.age) // 1 b = {... a} a.age = 3 console.log(b.age) // 2Copy the code

The second kind of handwriting:

function clone(origin,target){
    var target = target || {}
    for(var prop in origin){
        target[prop] = origin[prop]
    }
    return target
}
Copy the code

9.2 deep copy

Parse (json.stringify (object)) The simplest way to deep-copy is using json.parse (json.stringify (object))

function deepClone(origin,target){ var target = target || {} for(var prop in origin){ if(origin.hasOwnProperty(prop)){ if(origin[prop] ! == null && typeof(origin[prop]) === 'object'){ if(Object.prototype.toString.call(origin[prop]) == '[object Array]'){ target[prop] = [] }else{ target[prop] = {} } deepClone(origin[prop],target[prop]) }else{ target[prop] = origin[prop] } }  } return target }Copy the code

10. Task queue

/** * Macro tasks are executed in the macro task, and the next macro task will start only after all the micro tasks in one macro task have been executed. This process is called event-loop **/ macro tasks include: Through setTimeout, I/O, setTimeout, setInterval, setImmediate, requestAnimationFrame, etc. Completely browser dependent) microtasks include: NextTick, MutationObserver, promise. then catch finally, Promise before then/catch/finally, console.log('1'); setTimeout(function () { console.log('2'); process.nextTick(function () { console.log('3'); }) new Promise(function (resolve) { console.log('4'); resolve(); }).then(function () { console.log('5') }) }) process.nextTick(function () { console.log('6'); }) new Promise(function (resolve) { console.log('7'); resolve(); }).then(function () { console.log('8') }) setTimeout(function () { console.log('9'); process.nextTick(function () { console.log('10'); }) new Promise(function (resolve) { console.log('11'); resolve(); }).then(function () { console.log('12') }) }) //1 7 6 8 2 4 3 5 9 11 10 12Copy the code
  1. When a setTimeout is encountered, its callback function is dispatched to the macro task Event Queue
  2. When process.nexttick () is encountered, its callback function is dispatched to the microtask Event Queue
  3. If a Promise is encountered, new Promise is executed directly, printing 7. Then is distributed to the microtask Event Queue
  4. A setTimeout is encountered, whose callback function is dispatched to the macro task Event Queue, and the first loop ends and the second loop is similar
async function async1() { console.log('async1 start') await async2() console.log('async1 end') } async function async2()  { console.log('async2') } console.log('script start') setTimeout(function () { console.log('setTimeout') }, 0) async1() new Promise(function (resolve) { console.log('promise1') resolve() }).then(function () { console.log('promise2') }) console.log('script end') // script start // async1 start // async2 // promise1 // script end  // async1 end // promise2 // setTimeoutCopy the code
  1. The monolithic script enters the main thread as the first macro task, and the code executes from top to bottom, executing the synchronized code and printing Script start
  2. When setTimeout is encountered, join the macro task queue
  3. Execute async1() and print async1 start; Then we get await async2(),await is actually a sign of giving up the thread, first async2() is executed and async2 is output; Add console.log(‘async1 end’) after async2() to the microtask queue, jumping out of the whole async function. Async and await themselves are syntactic sugars of promise+ Generator. So the code after await is a microtask.)
  4. Go ahead and hit a new Promise, print promise1, and add the code after.then() to the microtask queue
  5. Go ahead and print script end. Then read the microtask queue and print async1 end, promise2 to complete the macro task of this round. Continue with the code for the next macro task, printing setTimeout
setTimeout(function () { console.log('timer1') }, 0) requestAnimationFrame(function () { console.log('requestAnimationFrame') }) setTimeout(function () { console.log('timer2') }, 0) new Promise(function executor(resolve) { console.log('promise 1') resolve() console.log('promise 2') }).then(function () {console.log('promise then')}) console.log('end') // Google Browser Promise 1 Promise 2 end Promise then RequestAnimationFrame Timer1 Timer2 Firefox Promise 1 Promise 2 End Promise then timer1 timer2 requestAnimationFrameCopy the code
  1. The whole script code is executed, and three new macro tasks, two setTimeout and a requestAnimationFrame are added
  2. Promise1, promise2, and then callback to the microtask queue.
  3. Go ahead and print end
  4. Execute the PROMISE’s THEN callback to print the Promise then
  5. There are three macro tasks left, and we know that Timer1 will execute before Timer2. What about requestAnimationFrame?

What is requestAnimationFrame

Tell the browser window. RequestAnimationFrame () – you want to perform an animation, and required the browser until the next redraw calls the specified callback function to update the animation. This method takes as an argument a callback function that is executed before the browser’s next redraw. RequestAnimationFrame basic idea is to allow the page to redraw the frequency and refresh rate, compared with setTimeout, requestAnimationFrame’s biggest advantage is decided by the system to the execution time to the callback function.

11. Call, apply, bind

11.1 the call

function a(){ console.log(this,'a') }; ƒ b(b){console.log(b)} a.call(b,' I am a parameter of B 'Copy the code

Handwriting: 1. Set the function as an object property. 2

Function.prototype.myCall = function (context) { var context = context || window context.fn = this // let arr = [] // for (let i = 1; i < arguments.length; i++) { // arr.push(arguments[i]) // } let arg = [...arguments].slice(1) var result = context.fn(... arg) delete context.fn return result } var foo = { value: 1 } function bar(name) { console.log(name) console.log(this.value) } bar.myCall(foo, 2)Copy the code

11.2 the apply

Function.prototype.myApplay = function (context, arr) { var context = Object(context) || window; context.fn = this; var result; if (! arr) { result = context.fn(); } else { result = context.fn(... arr) } delete context.fn return result; } var foo = { value: Function bar(name,age) {console.log(name,age) console.log(this.value)} bar.myapplay (foo, [2,5])Copy the code

11.3 the bind

12. The enumeration

12.1 the for… in

Var obj = {name:' LJL ', age:22, sex:' male ', Tel :15959172873} for(var key in obj){console.log(obj[key]) {console.log(obj[key]) // LJL 22 male 15959172873 // obj --> obj['key'];Copy the code

12.2 hasOwnProperty

for… The in loop allows you to iterate over properties in the prototype. If you don’t want to access properties in the prototype, you can use hasOwnProperty

Var obj = {name:' LJL ', age:22, sex:' male ', tel:15959172873, __proto__:{type: 'proto' } } for(var key in obj){ if(obj.hasOwnProperty(key)){ console.log(obj[key]) } }Copy the code

12.3 in

Property returns true, both in itself and in the stereotype

12.4 instanceof

A instanceof B, A is constructed by the B constructor, to see if the prototype of A has the prototype of B

An array of 13.

13.1 push

Implementation:

Array.prototype.push = function(){ for(var i = 0; i<arguments.length; i++){ this[this.length] = arguments[i] } return this.length }Copy the code

13.2 Class Array Arguments

Attribute is index (number) attribute, must have length attribute, preferably with push method

Var obj = {" 0 ", "a", "1", "b", "2" : "c", "length" : 3, "push" : Array. The prototype. Push} obj. Push (" d ") / / print {0: "a", 1: "B ", 2: "c", 3:" D ", length: 4, push: ƒ}Copy the code

Topic:

var obj = { "2":"a", "3":"b", "length":2, "Push" : Array. Prototype. Push} obj. Push (" c ") obj. Push (" d ") / / print out the var obj = {" 2 ":" c ", "3" : "d", "length" : 4, "Push ": array.prototype. push} select * from length where id = 2 and id = 4Copy the code

14 Execute the function immediately

var fn = (function(){
    console.log(111)
}())
Copy the code

Run auto recycle