Preliminary analysis

function fn(a,c){ console.log(a) //f a(){} var a = 123 console.log(a) //123 console.log(c) //f c(){} function a(){} if(false){ var d=678 } console.log(d)//undefined console.log(b)//undefined var b =function() {} console.log(b)//f(){} Function c(){} console.log(c)//f c(){}} fn(1,2) // precompile // precompile phase // precompile phase // what is done when precompile //js variable object AO object for js engine to access //1 Create ao object 2 find the parameter and variable declaration as the ao object attribute name value undefined 3 find the argument and parameter consistent 4 find the function declaration will override the variable declaration ao: { a:undefined 1 function a(){} c:undefined 2 function c(){} d:undefined b:undefined }Copy the code
  • Lexical scope: The scope of a variable is determined at definition time, not at execution time. That is, the lexical scope depends on the source code and can be determined by static analysis. Therefore, lexical scope is also called static scope. With and eval are the exceptions, so JS’s scoping mechanism is very close to Lexical scope.

Why is JS single threaded

The single thread of JavaScript, relative to its purpose. As a browser scripting language, JavaScript’s primary purpose is to interact with users and manipulate the DOM. This means that it has to be single-threaded, which can cause complex synchronization problems. For example, if there are two threads of JavaScript at the same time, one thread adds content to a DOM node, and the other thread removes that node, which thread should the browser use? So, to avoid complexity, JavaScript has been single-threaded since its inception.

In order to make use of the computing power of multi-core CPU, HTML5 proposes the Web Worker standard, which allows JavaScript scripts to create multiple threads, but the child threads are completely controlled by the main thread and cannot operate DOM. So, this new standard doesn’t change the single-threaded nature of JavaScript.

JS event loop mechanism

  • Asynchronous operations in JS, such as fetch setTimeout setInterval, are pushed into the call stack and the callback function inside will be put into the message queue. The message queue will be executed after the call stack is empty

  • Asynchronous operations of promise async await will be added to the microtask, will be executed immediately when the call stack is empty, and the microtask added to the call stack will be executed immediately (microtask: Promise Process.nexttick).

The following code executes

setTimeout(()=>{
    console.log(1)
},0)
setInterval(() => {
    console.log('interval')
}, 1000);
new Promise(resolve=>{
    console.log(2)
    resolve()
}).then(res=>{
    console.log(3)
})
new Promise(resolve=>{
    console.log(5)
    resolve()
}).then(resolve=>{
    console.log(6)
})
console.log(4)
​
/*
2
5
4
3
6
1
interval
*/
​
Copy the code

Execute priority call stack > Microtask Queue > Message Queue

Which are asynchronous tasks

  • SetTimeout and setInterval
  • DOM events
  • Promise
  • Network request
  • I/O

JS language features

  • Runs in the client browser
  • Parsing execution code directly without precompiling (with preparsing)
  • Is a weakly typed language, more flexible
  • Operating system independent, cross-platform language
  • Scripting languages, interpreted languages

JS data type

Basic data types:

String, Number, Boolean, Null, Undefined, Symbol

Reference data types:

Object, Array, Function.

Front-end event flow

Event capture phase

In the target stage

Event bubbling phase

arguments

Function get(){console.log(arguments)} get(1,2,3) //arguments is an array object / / by Array. Prototype. Slice. The call (the arguments) is transformed into an Array / / but can be by an operator to be converted into an Array of es6 / / forCopy the code

Why does b in the code become a global variable when this function is called

 function func(){
            let a=b=3
        }
        func()
        console.log(b)//3
        console.log(a)//error
Copy the code

Because let a=b=3 is equivalent to let a=(b=3), b is not declared, so it will become a global variable when it is created. After func() is executed, b is a global variable, so it can be accessed, but a is in func() scope and cannot be accessed externally

This points to the problem

How many ways does this point to

  • Default binding: This is bound to window by default in the global environment

  • Implicit binding: When called by a function contained in a direct object, that is, when a method is called, this is implicitly bound to that object

  • Implicit loss: Implicitly bound functions that lose bound objects are bound to Windows by default

    var name='window'
    var person={
        name:'zs',
        getName:function(){
            return this.name
        }
    }
    console.log(person.getName())//zs
    let getName2=person.getName
    console.log(getName2())//window
    Copy the code
  • Show bindings: Bind objects to this using the call(), apply(), bind() methods

  • New binding: A function or method call preceded by the keyword new constitutes a constructor call, which in the case of this is called a new binding

Used directly in functions

Function get(content){console.log(content)} get(' hello ')//Copy the code

A function is called as a method of an object (to whom it is called).

Var person = {name:' name ', }} person. Run :function(time){console.log(' ${this.name} ')}} person person.run.call(person,30)Copy the code

sample

var name=222 var a ={ name:111, say:function(){ console.log(this.name) } } var fun = a.say fun() //fun,call(window) 222 a.say()//a.say.call(a) 111 var b={ name:333, Say :function(fun){fun()}} b.say(a.say)// if fun()=a.say = console.log(this.name) is copied to b's say method 333Copy the code

This in the arrow function

  • The this in the arrow function is bound when the function is defined, not when the function is executed
  • In the arrow function, the this point is fixed, not because the arrow function has a mechanism to bind this. The actual reason is that the arrow function does not have its own this, so the internal this is the this of the outer code block. Because it does not have this, it cannot be used as a constructor
     var x =11
        var obj={
            x:22.say:() = >{
                console.log(this.x)
            }
        }
        obj.say()   // The output is 11
Copy the code
     var obj={
               birth:1990.getAge:function(){
                   var b=this.birth
                   var fn=() = >new Date().getFullYear()-this.birth
                   return fn()
               }
           }
           console.log(obj.getAge())// Output is 2021-1990=31
Copy the code

Since the arrow function is defined in getAge() and its parent is the obj inner scope, the this in its arrow function points to the parent OBj object, this.birth is 1990

There are three ways to change the direction of this

  • call
  • apply
  • bind
let obj = {
    name:'hututu'
}
function Child(name){
    this.name = name
}
Child.prototype = {
    constructor:Child,
    showName:function(){
        console.log(this.name)
    }
}
var child = new Child('little beauty')
child.showName()/ / little beauty

child.showName.call(obj)/ / hu Desmond tutu
child.showName.apply(obj)/ / hu Desmond tutu
let bind = child.showName.bind(obj)/ / hu Desmond tutu
bind()
Copy the code

Call and apply execute immediately, not bind, which takes the same arguments as call, except that it returns a function. The call parameter is separated by commas, while the apply parameter is an array

let arr = [1.2.3.4.5.6]
console.log(Math.max.call(null.1.2.3.4.5.6))/ / 6
console.log(Math.max.call(null,arr))//NaN
console.log(Math.max.apply(null,arr))/ / 6
Copy the code

Depth and light copy in JS

Assignment: when we put an object is assigned to a new variable, assign a is actually the addresses of objects in the stack, rather than a pile of data, namely two object point to the same storage space, no matter which object changed, actually is to change the content of the storage space, so the two objects are linked

Shallow copy: The basic data types of objects before and after the copy do not affect each other. However, the reference types of objects before and after the copy do affect each other because they share the same memory block

Deep copy: to create a new area of the heap to store objects, the original object and the new object are not affected by each other

operation And whether the original data points to the same object The first layer of data is of general data type Layer 1 data is not a generic data type
The assignment is Change changes the raw data Change alters the raw data
Shallow copy no Change doesn’t change the raw data Change alters the raw data
Deep copy no Change doesn’t change the raw data Change doesn’t change the raw data
  • Assignment code

    Var person = {name:" ", Var person1 = person person1.name = "person1.hobby[0]=' play ' Console. log(person)// Console. log(person)// Console. log(person)// Console. log(person)// Console. log(person)// Console. log(person)Copy the code
  • Shallow copy code (base data types are not affected, reference data types are changed at the same time)

    Var person = {name:" ", Hobby :[' learn ',' write ',' write ']} function shallowCopy(obj){var target = {} for(var I in obj){if(obj. HasOwnProperty (I)){ Target [I]=obj[I]}} return target} var person1 = shallowCopy(person) person1.name='王二' person1.hobby[0]=" play" Console. log(person1) console.log(person1) console.log(person1Copy the code
  • Deep-copy code (data is not affected before and after copying)

    Var person = {name:" ", } function deepClone(obj){var cloneObj = new obj.constructor() if(obj===null) return obj if(obj)  instanceof Date) return new Datr(obj) if(obj instanceof RegExp) return new RegExp(obj) if(typeof obj ! == 'object') return obj for(var i in obj){ if(obj.hasOwnProperty(i)){ cloneObj[i]=deepClone(obj[i]) } } return cloneObj } // var person1 = json.parse (json.stringify (person)) Var person1 = deepClone(person) person1.name=" hutograph "person1.hobby[0]=" play mahjong" Console. log(person1)// Both have no effect on console.log(person)Copy the code

Shallow copy implementation:

  • CloneObj in Lodash
  • . Expansion operator
  • Array.prototype.concat()
  • Array.prototype.slice()

Deep copy implementation:

  • Json.parse (json.stringify ()) will raise an exception if there are regular expressions, Date objects, regular objects, and Promises in the object
  • Recursive implementation (as in the code above)
  • CloneDeep () in loadsh
  • jquery.extend()

closure

What is a closure? What are closures good for?

Closure: A function that can access variables in the scope of other functions

Application: Imitate block-level scope; Save external function variables; Encapsulating private variables (singleton pattern)

Closures versus heap memory: Variables in a closure are not stored in stack memory, but in heap memory, so the closure can refer to variables in the function after a function call

Image stabilization

You can use closures

 var input = document.querySelector('input')
      function debounce(delay){
          let timer
          return function(value){
              clearTimeout(timer)
              timer=setTimeout(function(){
                  console.log(value)
                  
              },delay)
          }
      }
      var debounceFunc = debounce(1000)
      input.addEventListener('keyup',function(e){
          debounceFunc(e.target.value)
      })
Copy the code

Using closures, the return function can also use a timer, which is generated only once when debounce is called

The throttle

Do one thing at a time, no matter how many clicks, and wait until the second thing is done. Closures solve throttling

document.querySelector('button').addEventListener('click',thro(handle,2000)) function thro(func,wait){ let timeout return function(){ if(! timeout){ timeout = setTimeout(function(){ func() timeout=null },wait) } } } function handle(){ console.log(Math.random()) }Copy the code

The underlying principles of closures

Function b(){var bb = 234 console.log(aa)} return b} var res = a() res(Copy the code

After a() is executed, the corresponding scope chain of A will be broken, but B can access the scope chain of A when defining. This scope chain will not be broken, so res() can still access aa=123, which can output 123. The closure can keep the variable in memory all the time.

Closures implement the singleton pattern

Var createLogin = function () {var div = document.createElement('div') div.innerhtml = "I am the popup div" div.style.display = 'none' document.body.appendChild(div) return div } var getSingle = function(fn){ var result return function(){ return result || (result=fn.apply(this,arguments)) } } var create = getSingle(createLogin) document.querySelector('button').onclick=function(){ var loginLay = create() loginLay.style.display = "block" }Copy the code

Create only one div, no matter how many times you click

Which operations cause memory leaks

  • closure

  • Unexpected global variables

    } function fn(){this.a=1} function fn(){this.a=1} function fn(){this.a=1} function fn(){this.a=1} This will only be destroyed when the page is closed}Copy the code
  • The forgotten timer

  • An out-of-dom reference (for example, var div=document.querySelector(‘div’) is then removed, but the reference to div is not removed, and the reference to div remains in memory)

    var elements = { txt: document.getElementById("test") } function fn() { elements.txt.innerHTML = "1111" } function removeTxt() { document.body.removeChild(document.getElementById('test')); } fn(); <div id="test">1111</div>Copy the code

Higher-order functions

A function that takes a function as an argument or return value

function highOrder(params,callback){
    return callback(params)
}
Copy the code

An array of operating

Array flattening

  • Arrays come with flattening methods

    Const arr = [1, 2, 3, 4, 5]]], 6]. The console log (arr. Flat (Infinity))Copy the code
  • Regular add JSON. Parse (JSON. Stringify (arr))

    let arr=[1,[2,[3,[4,[5]]]]]
    let newarr=JSON.parse('['+JSON.stringify(arr).replace(/[|]/g,'')+']')
    console.log(newarr)
    Copy the code
  • recursive

    const array=[] const fn=(arr)=>{ for(let i=0; i<arr.length; i++){ if(Array.isArray(arr[i])){ fn(arr[i]) } else{ array.push(arr[i]) } } }Copy the code
  • reduce

arr.reduce(function(prev,cur,index,arr){})

Arr represents the primitive array to be used

Prev represents the return value or initial value of the last call init

Cur represents the array element currently being processed

Index represents the index of the array currently being processed, 0 if init is provided, 1 otherwise

Init represents the initial value

let arr=[1[2[3[4[5]]]]]
const fn=(arr) = >{
 return   arr.reduce((pre,cur) = >{
        return pre.concat(Array.isArray(cur)? fn(cur):cur) },[]) }let newarr=fn(arr)
console.log(newarr)
Copy the code

Array to heavy

Set to heavy

Let arr=[1,1,2,3,4,4,5,6] let newarr=[...new Set(arr)] console.log(newarr)Copy the code

Deduplicates the array IndexOf

Let arr=[1,1,2,3,4,4,5,6] function unique(arr){let newarr=[] for(var item of arr){if(newarr.indexof (item)==-1){ newarr.push(item) } } return newarr } console.log(unique(arr))Copy the code

Reduce the use of

Count the number of occurrences of each element in the array

Let person=[' cur ',' cur '] let nameNum = person.reduce((cur)=>{if(cur in pre){pre[cur]++}else{ pre[cur]=1 } return pre },{}) console.log(nameNum)Copy the code

Array to heavy

Var arr = [1,2,3,4,5,1,2,3,4,5] let newArr = arr.reduce((pre,cur)=>{if(pre. Includes (cur)){return pre} else{return Pre. Concat (cur)}// Pre becomes 1},[]) console.log(newArr)Copy the code

Array traversal

for(let i=0; i<arr.length; I ++){} for(var I in arr){// I is the index arr[I]} for(var value of arr){//value is the value of each item traversed. Value} arr.map((item)=>{} Arr.foreach ((item)=>{})// No return valueCopy the code

The constructor creates the object

ES5 There are three ways to create objects

Create an Object with new Object()

var obj = new Object()
Copy the code

Create objects using object literals

var obj = {}
Copy the code

Use constructors to create objects

Function Star(name,age){this.name = name this.age = age this.sing = function(){console.log(' I can sing ')}} var LDH = new Star(' Lau ',12)// Constructor is different from normal function, use newCopy the code

This refers to the instance object only after new, and there is no return in the constructor

The members created by this are called instance members and only instance members can access them

Members not created through this are called static members and can be accessed directly through Star, not through instances

Function Star(name,age){this.name = name this.age = age this.sing = function(){console.log(' I can sing ')}} star.sex =' male ' Star.play=function(){console.log(star.sex) star.play () let LDH = new Star(' dev ',12) The console. The log (LDH. Sex) / / undefined LDH. The play () / / an errorCopy the code

Prototype chain

Let’s start with the following code

Function Star(name,age){this.name = name this.age = age this.sing = function(){console.log(' I can sing ')}} var LDH = new Star(' Andy ',12) var zxy = new Star(' Jacky ',34) console.log(ldh.sing===zxy.sing)//Copy the code

Note Creating two objects creates two different memory Spaces, but the same part still occupies different memory space, resulting in memory waste

Use the console. Dir (Star)

Star has a Prototype property that points to an object, the prototype object. So consider adding the common parts to the constructor’s prototype object, rewritten as follows

Function Star(name,age){this.name = name this.age = age} star.prototype. Sing = function(){console.log(' I can sing ')} var LDH = new Star(' Andy ',12) var zxy = new Star(' Jacky ',34) console.log(ldh.sing===zxy.sing ldh.sing() Star.prototype.sing()Copy the code

The object prototype

If (sing() is added to star.prototype, LDH can access this function

LDH has one__ proto __Object will have one__ proto __Property, which points to the constructor’s Prototype object, LDH’s__ proto __It points to Star’s prototype, so you can use the sing() method mounted to Star’s Prototype

The following code can be used to test whether the following two are equal, and the result is true, which also verifies the above statement

console.log(ldh.__proto__===Star.prototype)//true
Copy the code

Use pictures to talk directly (I recommend Teacher Pink from station B, this part is very clear, and the pictures are also taken from his video)

The Construtor in Star that prototype points to

console.log(Star.prototype)
console.log(ldh.__proto__)
Copy the code

Constructor is used to record the Star itself, and as long as constructor is used to record which constructor the object references, it can redirect the prototype object to the original constructor

If we want to attach a lot of public properties to prototype, star.prototype. XXXX = XXXX would be too cumbersome, so consider encapsulating what we want to add as an object

Star.protoype={
    sing:function(){},
    movie:function(){},
    play:function(){}
    
}
Copy the code

But using this method our object overwrites some of Prototype’s properties without knowing where it came from, so constructor comes into play

Star. Protoype ={constructor:Star,// add constructor to point it back to Star sing:function(){}, movie:function(){}, play:function(){} }Copy the code

Constructor instance and prototype object triangulation

Prototype chain

console.log(Star.prototype.__proto__===Object.prototype)//true
console.log(Object.prototype.__proto__)//null
Copy the code

Constructor inheritance + prototype object inheritance

function Parent(name){ this.name = name } Parent.prototype.getName = function(){ return this.name } function Child(name){ Parent.call(this,name) } Child.prototype = new Parent() Child.prototype.construcor = Child const parent = New Parent(' huhuibin ') const child = new Child(' huhuibin ') console.log(parent.name)// huhuibin console.log(child.name)// Huhuibin console.log(child.name)// Huhuibin console.log(child Console. log(parent.getname ())// Console. log(child.getname ())// HutuituCopy the code

Disadvantages of combinatorial inheritance (creating a Parent instance object every time a Child instance object is created)

Parasitic combination (adding stuff to child.prototype affects parent. Prototype)

//Child.prototype = new Parent()
Child.prototype = Parent.prototype
Copy the code

Solution, shallow copy

Child.prototype = Object.create(Parent.prototype)
Copy the code

Object literals instead of switch methods

const fruitsColor={
    red:['apple'],
    yellow:['banana']
}
function printFruits(color){
    return fruitsColor[color] || []
}
console.log(printFruits('y'))
Copy the code

JS type judgment

  • typeof

    Typeof can identify the basic types of Boolean, number, undefined, string, symbol. But null is not recognized, and null returns type Object. For reference types, array and object are classified as object, but function is recognized.

  • instanceof

    The result shows that Instanceof does not recognize the basic data types number, Boolean, string, undefined, NULL, and symbol. However, reference types such as array, Object, and function can be detected.

  • Object.prototype.toString.call

    This method can judge the js data type relatively completely.

What is an immediate function? What are the characteristics? What’s the use?

(function(){// execute statement})()Copy the code

Features: Execute the code in the function immediately without leaving a reference to the function in memory. All variables inside the function are destroyed immediately (unless they are assigned to variables in the include scope).

Function: Implements block-level scope

JS garbage collection mechanism

JS garbage collection mechanism is mainly a background process called garbage collector (GC) responsible for monitoring, cleaning objects, and timely reclaim free memory.

The GC’s primary responsibility is to monitor the reachability of data, and “reachability” values are those that are accessible or available in some way. Such as direct access or chain access, etc., when no entry to access it, the data will become rubbish are cleared away (generally does not have the referenced object is rubbish, is to be cleared, there is an exception, several objects refer to each other to form a ring, but actually there is no access, this a few objects and garbage)

How to remove garbage

  • Mark clear

    Function func3() {const a = 1 const b = 2} func3() {const a = 1 const b = 2Copy the code
  • Reference counting

    Function func4 () {const c = {} // The reference count of the type variable c is 0 let d = c // the reference count of c is 1 let e = c // the reference count of C is 2 d = {} // d no longer references c, c's reference count is reduced to 1, e = null // E no longer references C, c's reference count is reduced to 0, will be reclaimed}Copy the code

    Disadvantages of reference counting (circular references)

    Function func5 () {let f = {} let g = {} f.p = g g.p = f // Because f and g reference each other, count can never be 0}Copy the code

    In this case we need to manually free the memory of the variable

    f.prop = null
    g.prop = null
    Copy the code

    In modern browsers, JavaScript uses tag clearing, so we don’t have to worry about circular references

    == differs from ===, object. is

console.log(""==0)//true
console.log("0"==0)//true
console.log(123=="123")//true
console.log(null==undefined)//true
console.log(NaN==NaN)//false
Copy the code
      console.log(""===0)//false
      console.log("0"===0)//false
      console.log(123==="123")//false
      console.log(null===undefined)//false
      console.log(NaN===NaN)//false
Copy the code

NaN felt like a stranger…

If the value types on both sides of == are different, the force is cast to number for comparison

Object. Is (+0,-0) false; Object is (NaN NaN) true)

What is the eval

Its function is to parse the corresponding string into JS and execute it. Js should be avoided as it is very performance expensive (2 times, once parsed into JS and once executed).