13

1 Statement

1-1 "Three ways of js function declaration:"

(1) Function() constructor

var f =new Function()

(2) Function declaration

function f (){
     console.log(2);
}

(3) Function expression

var f = function() {
      console.log(1);  
}

1-2 "js variable declaration:"

  • Variables declared by var will be mounted on the window, while variables declared by let and const will not
  • Var declared variables have variable promotion, let and const do not have variable promotion (strictly speaking, let also exists)
  • let and const declarations form block scope
  • let there is a temporary dead zone
  • const declaration must be assigned

(1) Variables declared by var will be mounted on the window, while variables declared by let and const will not:

var a = 100;
console.log(a,window.a);    // 100 100
let b = 10;
console.log(b,window.b);    // 10 undefined
const c = 1;
console.log(c,window.c);    // 1 undefined

(2) Var declared variables have variable promotion, let and const have no variable promotion

console.log(a); // undefined  ===>  a已声明还没赋值,默认得到undefined值
var a = 100;
console.log(b); // 报错:b is not defined  ===> 找不到b这个变量
let b = 10;
console.log(c); // 报错:c is not defined  ===> 找不到c这个变量
const c = 10;

(3) let and const declarations form block scope

if(1){
    var a = 100;
    let b = 10;
}
console.log(a); // 100
console.log(b)  // 报错:b is not defined  ===> 找不到b这个变量
//
if(1){
    var a = 100;     
    const c = 1;
}
 console.log(a); // 100
 console.log(c)  // 报错:c is not defined  ===> 找不到c这个变量

(4) Let and const cannot be declared repeatedly in the same scope, while var can

var a = 100;
console.log(a); // 100
var a = 10;
console.log(a); // 10
let a = 100;
let a = 10;
//  控制台报错:Identifier 'a' has already been declared  ===> 标识符a已经被声明了。

(5) Temporary dead zone

var a = 100;
if(1){
    a = 10;
    let a = 1;
    //在当前块作用域中存在a使用let/const声明的情况下,给a赋值10时,只会在当前作用域查找变量a,
    // 而这时,还未到声明时候,所以控制台Error:a is not defined
    // 即let 和 const 不会声明提前
}

(6) const

一旦声明必须赋值,不能使用null占位。
声明后不能再修改
如果声明的是引用类型数据,可以修改其属性
const a = 100; 
const list = [];
list[0] = 10;
console.log(list);  // [10]
const obj = {a:100};
obj.name = 'apple';
obj.a = 10000;
console.log(obj);  // {a:10000,name:'apple'}

2 Classification of data types:

2-1 Basic types:

  • string (string)-primitive type
  • boolean (Boolean)-primitive type
  • number (number)-primitive type
  • symbol-primitive type
  • null (empty value)
  • undefined
  • BigInt (The purpose of the BigInt data type is to have a larger range of integer values than the Number data type, the precision is in the range of (2^53-1), and the value of BigInt(10) is: 10n) New in ES2020

Among them, Symbol and BigInt are newly added data types ES6

  • Symbol represents a unique and immutable data type after creation. It is mainly used to solve possible global variable conflicts.
  • BigInt is a digital type of data, which can represent integers in arbitrary precision format. Using BigInt can safely store and manipulate large integers, even if the number has exceeded the safe integer range that Number can represent.

Note: NaN is not a data type

typeof NaN === 'number' //true
NaN==NaN  //false

2-2 Object types (reference types), there are the following 3 types:

A. Built-in objects/Native objects

String、Number、Boolean、Array、Date、RegExp、Math、 Error、 Object、Function、 Global

B. Host object

  • (1) BOM objects: Window, Navigator, Screen, History, Location
  • (2) DOM objects: Document, Body, Button, Canvas, etc.

C. Custom object-(refers to the object created by the user, compatibility issues need to be noted by the writer)

There are several ways to create custom objects:

(1) Object direct quantity:

var obj1 = {};
var obj2 = {x:0,y:0};
var obj3 = {name:‘Mary’,age:18}

(2) Factory mode-use functions to encapsulate the details of creating objects with specific interfaces:

function createPerson(name,age,job){
    var o = new Object();
    o.name = name;
    o.age = age;
    o.job = job;
    return o;
}
var person1 = createPerson('zhang',30,'java');

(3) Constructor mode:

function Person(name,age,job){
    this.name= name;
    this.age = age;
    this.job = job;
}
var person1 = new Person('zhang',30,'java');

(4) Prototype model:

function Person(){}
Person.prototype.name = 'zhang';
Person.prototype.age = '22';
Person.prototype.job = 'html5';
var person1 = new Person();

2-3 Judgment of data type:

2-3-1: typeof

Generally, the typeof operator is used to determine which basic type of a value belongs to.

Disadvantage : Cannot distinguish object type

typeof 'seymoe'    // 'string'
typeof true        // 'boolean'
typeof 10          // 'number'
typeof Symbol()    // 'symbol'
typeof null        // 'object' 无法判定是否为 null
typeof undefined   // 'undefined'
typeof {}           // 'object'
typeof []           // 'object'
typeof(() => {})    // 'function'

why typeof null is object:

When js stores variables in the bottom layer, it will store its type information in the low 1-3 bits of the machine code of the variable

  • 000: Object
  • 010: Floating point number
  • 100: string
  • 110: Boolean
  • 1: integer

However, for undefined and null, the information storage for these two values is a bit special.

  • null: all machine codes are 0
  • undefined: expressed as an integer of −2^30

Therefore, typeof has a problem when judging null. Since all machine codes of null are 0, it is directly treated as an object.

2-3-2:instanceof

Determine the object type: test whether the prototype of the constructor function appears on the prototype chain of the detected object.

Disadvantages: it is impossible to judge whether a value belongs to an array or an ordinary object

[] instanceof Array            // true
({}) instanceof Object         // true
(()=>{}) instanceof Function   // true
let arr = []
let obj = {}
arr instanceof Array    // true
arr instanceof Object   // true
obj instanceof Object   // true

在这个例子中,arr 数组相当于 new Array() 出的一个实例,
所以 arr.__proto__ === Array.prototype,
又因为 Array 属于 Object 子类型,
即 Array.prototype.__proto__ === Object.prototype,
所以 Object 构造函数在 arr 的原型链上

Can't judge the original type

console.log(true instanceof Boolean);// false
console.log(undefined instanceof Object); // false
console.log(arr instanceof Array);  // true
console.log(null instanceof Object); // false
console.log({} instanceof Object); // true
console.log(function(){} instanceof Function);// true

2-3-3: Object.prototype.toString.call()

Almighty, almost able to judge
Object.prototype.toString.call({})// '[object Object]'
Object.prototype.toString.call([])// '[object Array]'
Object.prototype.toString.call(() => {})// '[object Function]'
Object.prototype.toString.call('abc')// '[object String]'

The original type is passed in but the result can be determined because the value is wrapped.

"So, what is the packaging object:"

The so-called "packaged objects" refer to the three native objects of Number, String, and Boolean that correspond to numeric values, strings, and Boolean values, respectively. These three primitive objects can turn (wrap) primitive values into objects.

Click here for details

3 js operator:

3-1 delete operator

The delete operator is used to delete object attributes or array elements. If successfully deleted or the deleted target does not exist, delete will return true .
However, not all attributes can be deleted:

  • Some built-in core and client properties cannot be deleted
  • Variables declared by var statement cannot be deleted
  • The function defined by the function statement cannot be deleted.

E.g:

var o = { x: 1, y: 2};          // 定义一个对象
console.log(delete o.x);        // true,删除一个属性
console.log(delete o.x);        // true,什么都没做,x 在已上一步被删除
console.log("x" in o);          // false,这个属性在对象中不再存在
console.log(delete o.toString); // true,什么也没做,toString是继承来的
console.log(delete 1);          // true,无意义

var a = [1,2,3];                // 定义一个数组
console.log(delete a[2]);       // true,删除最后一个数组元素
console.log(2 in a);            // false,元素2在数组中不再存在
console.log(a.length);          // 3,数组长度并不会因 delete 而改变
console.log(a[2]);              // undefined,元素2所在的位置被空了出来
console.log(delete a);          // false,通过 var 语句声明的变量不能删除

function f(args){}              // 定义一个函数
console.log(delete f);          // false,通过 function 语句声明的函数不能删除

3-2 void operator

The void operator can be applied to any table type expression, the expression will be executed, but the result of the will be ignored and return undefined.

E.g:

void 0;
void "you are useless?";
void false;
void [];
void /(useless)/ig;
void function(){ console.log("you are so useless?"); }
void alert(1)
// always return undefined

3-3 ++ - operator

++ - Increment and decrement operators are borrowed from the C language. They are divided into pre-type and post-position, and their function is to change the value of a variable.

E.g:

var a = 5;
console.log(a++);   // 5   后加表不加
console.log(a);     // 6  
console.log(++a);   // 7   先加,都有加
console.log(a)      // 7
console.log(a--);   // 7
console.log(a)      // 6
console.log(--a);   // 5
console.log(a)      // 5

kinky skills : first family has a family, but the latter family does not show family (the plus sign is in the front, and the expression itself is added by 1; the plus sign is in the back, the expression does not add 1, and the expression itself is increased by 1), and the subtraction is the same Rationale.

3-4 valueOf

var a = '你好', b = 1, c = [], d = {}, e = function (){}
a.valueOf()  // '好'
b.valueOf()  // 1
c.valueOf()  //[]
d.valueOf()  // {}
e.valueOf()  //ƒ (){}

3-5 + and-

"+" operator, if one of them is a string, then all are converted to a string and then perform string splicing

"-" operator, conversion to number, subtraction (-a, a * 1 a/1) can be implicitly coerced

[] + {}     // "[object Object]"
{} + []     // 0
1 + true    //2
1 + false   //1

4 RAM

4-1 execution context

When the code is running, a corresponding execution environment will be generated. In this environment, all variables will be raised in advance (variable promotion), some are assigned directly, and some are the default value undefined, and the code starts to execute from top to bottom. It's called the execution context.

"There are three execution environments":

  • 1. Global environment: the environment where the code enters first
  • 2. Function environment: the environment in which the function is executed when it is called
  • 3.eval function

"Execution context features:"

  • 1. Single thread, running on the main process
  • 2. Synchronous execution, executed in order from top to bottom
  • 3. There is only one global context, and the stack will be popped up when the browser is closed
  • 4. There is no limit to the number of execution contexts of functions
  • 5. Each time the function is called, a new execution context will be generated

"Execute 3 stages:"

1. Creation phase

  • (1). Generate variable objects
  • (2). Establish a scope chain
  • (3). Make sure this points to

2. Execution stage

  • (1). Variable assignment
  • (2). Function reference
  • (3). Execute other codes

3. Destruction stage

  • (1). Pop out of the stack after execution, waiting for recovery to be destroyed

details Click here

4-2 Stack

"concept:"

  • Stack: The stack will automatically allocate , which is automatically released ; it stores the basic , a simple data segment, and occupies a fixed size space of
  • Heap: dynamically allocated memory, the size is variable and will not be automatically released. Store the reference objects that may be composed of multiple values, are stored in the heap memory

click here for details

5 Garbage collection mechanism

It is said on MDN: Since 2012, all modern browsers have used the mark-clear garbage collection algorithm. All improvements to the js garbage collection algorithm are based on the improvement of the mark-sweep algorithm

"What is garbage:" general, not object reference is rubbish, it is to clear. But there is an exception. If several objects refer to each other to form a ring, but the root cannot access them, they are also garbage (reference counting method cannot clear them)

``Several algorithms for garbage collection:''

5-1 Reference counting method

concept : Record how many "programs" are referencing itself, and when the referenced value is 0, start to clear it.

Advantage :

  • immediately reclaim garbage. When the referenced value is 0 , the object will immediately free space to the free list, that is to say. When it becomes garbage, immediately recycled.
  • Because it is instant recovery, then the 'program' does not pause to use the GC for a long time alone, then maximum pause time very short.
  • No need to traverse all active and inactive objects in the heap

disadvantage :

  • The counter needs occupy a large position, because the upper limit of being quoted cannot be estimated. For example, there may be 32-bit objects that are 2 to the 32th power referencing an object at the same time, then the counter needs 32 bits.
  • The biggest disadvantage is that cannot solve the problem that circular references cannot be recycled. This is the problem that occurred before IE9 in the previous article.

5-2 Mark removal method

The garbage collection process of GC is mainly divided into two stages

marking stage : all active objects marked with 160b3936909cd4.

Clear phase : without marking (that is, inactive object) .

advantage:

  • Simple to implement, marking means either marking or not marking, so only one binary digit can be expressed
  • Solved the circular reference problem

Disadvantages

  • Cause fragmentation (somewhat similar to disk fragmentation)
  • There are many passes during redistribution. If the appropriate memory block size has not been found, the free linked list (the linked list formed by the addresses of all the free address spaces in the heap) will be traversed to the end.

5-3 Copy Algorithm

  1. From a memory space into two parts, one part is 060b3936909dc7 space, the other part is To space
  2. Copy the activity object From space to the To space
  3. Free up the entire From space
  4. Then exchange From space and To space, and then complete a GC.

details click here 1

click here for details 2

6 memory leak

"concept:" application memory is not timely recovery of lost, resulting in system memory waste, causing the program speed slow down or even system crashes and other serious consequences

"Scenario where the memory leak occurred:"

(1) Unexpected global variable

function leaks(){  
  leak = 'xxxxxx';//leak 成为一个全局变量,不会被回收
}

(2) Forgotten timer

setTimeout and setInterval are dedicated threads to maintain its life cycle. If a timer is used on a page, when the page is destroyed, these timers are not manually released and cleared, then these timers are still alive. Written

(3) Improper use of closure

var leaks = (function(){  
    var leak = 'xxxxxx';// 被闭包所引用,不会被回收
    return function(){
        console.log(leak);
    }
})()

(4) Missing DOM element

<div id="container">  
</div>
$('#container').bind('click', function(){
    console.log('click');
}).remove();//dom移除了,但是js还持有对它的引用

solve:

$('#container').bind('click', function(){
    console.log('click');
}).off('click').remove();
//把事件清除了,即可从内存中移除

(5) Network callback

"How to monitor memory leaks"

  • Use the console
  • Click here for details

7 scope

extends :

JavaScript is a dynamic language. Unlike Java, JavaScript can define global variables and local variables at will. Each function is a scope. When the function is executed, it will look up the current scope first, and then step up.

JavaScript is a static scope. When querying a variable, the value of the variable is determined by the position of the function definition, and has nothing to do with the scope of execution.

ES6 already has block-level scope, and variables defined with let and const will not be promoted.

concept :

scope : the effective scope of the variable or function

scope chain : We need to find a variable value, we will first search in the current scope, if we can't find it, we will go to the upper level, if we find it, we will return to stop the search, return the searched value, this kind of upward The chain relationship to find is called scope

7-1 Related Cases

(1) Variable promotion/variable is determined by the position when the function is defined

var a = 1;
function fn() {
  console.log('1:' + a);
  var a = 2;
  bar()
  console.log('2:' + a)
}
function bar() {
  console.log('3:' + a)
}
fn()

Print separately: 1:undefined 3:1 2:2

"Analysis:"

The first a printed value is 1:undefined instead of 1. Because we defined the variable a in fn(), the variable defined with var will be promoted to the top of the current scope (that is, the top of the current function scope), but the assignment is still in place, so it is undefined.

The second a printed value is 3:1 instead of 2. Because the function bar is defined in the global scope, the scope chain is bar -> global. A is not defined in bar, so it will look up the scope chain and find a in global. Note : The search is performed in the execution context defined

The third a printed value is 2:2. The scope chain where this sentence is located is fn -> global. Executing console.log('2:' + a) will first search for a in the fn scope, find a, and it has been assigned a value of 2, so the result is 2. .

(2) Variable assignment

var a = 1;
function fn() {
  console.log('1:' + a);
  a = 2
}
a = 3;
function bar() {
  console.log('2:' + a);
}
fn();
bar();

Print separately: 1:3 2:2

"Analysis:"

The first printed value is 1:3. First of all, a = 2 in fn is to assign a value to the variable a, not to declare the variable. Then, execute the function fn. At this time, a has been assigned a value of 3. Note that fn() is executed after a=3.

The second printed value is 2:2. The scope chain that the function bar can access is bar->global. When the function bar is executed, since fn() is executed before bar to modify a to 2, so the a obtained at this time is 2.

(3) Global variable declaration in advance

if(!(a in window)){
    var a = 10;
}
console.log(a);

Print: undefined

"Analysis:"

Is equivalent to:

var a;
if(!(a in window)){
    a = 10;
}
console.log(a);

Variables defined with var will be promoted to the top of the current scope (that is, the current global scope), so a will be declared in advance to the window, but the value is still in place, that is, undefined. So if get is a in window is ture, so do not go inside the assignment console.log(a) == undefined

A variant of the previous example:

(function(){
 var  x = c =  b = {a:1}
})()
console.log(c,b) // {a: 1} {a: 1}
console.log(x.a); // error , x is not defined

Note : x is declared in the function and is a local variable. C and b are not declared and assigned directly, so they are global variables. The assignment process is from right to left, that is, b={a:1},c=b,x=c

( 4) Variable promotion/operator order

(function(){
  var a = b = 3;
})()
console.log(typeof a === "undefined"); // true
console.log(typeof b === "undefined"); // false
console.log(typeof b === "number" && b ===3); // true

// What is involved here is the issue of immediate execution and closure, as well as variable promotion, and the direction of operator execution (= sign from right to left)

// That function can be broken down like this

(function()
  var a; /* 局部变量,外部没法访问*/
  b = 3; /* 全局变量,so . window.b === 3 , 外部可以访问到*/
  a = b;
})()

(5) Variable promotion/operator order

var x = 1;
if (function f(){console.log(2)}) {
x += typeof f;  
}
console.log(x);  // 1undefined

//Because the function body will be run as an expression in (), the fn function does not work and the function will not be executed.

//Finally, the expression is converted to true, f is not declared (the above function does not work), the value is undefined

"Knowledge Points:"

(1) In JavaScript, variables defined by let and const have the characteristics of block-level scope.

(2) Variables defined by var will be promoted in its own scope, while variables defined by let and const will not.

(3) Every JavaScript program has a global scope, and every time a function is created, a scope is created.

(4) When creating functions, nest these functions, and their scopes will also be nested to form a scope chain. The child scope can access the parent scope, but the parent scope cannot access the child scope.

(5) When executing a function, if we need to find the value of a certain variable, we will search in the scope chain where the function was defined. Once we find the required variable, we will stop searching upwards.

(6) "The value of a variable is determined by the position when the function is defined" is ambiguous. To be precise, when looking for a variable, it is the scope chain where defined when the function is defined.

8 Closure

"Concept:"

Closure is a function that can be accessed other functions scope of variables

"Application scenario:"

  • Function stabilization
  • Encapsulate private variables

The entire execution process of JavaScript code is divided into two stages, the code compilation stage and the code execution stage. The compilation stage is completed by the compiler to translate the code into executable code. At this stage, the scope rules will be determined. The execution phase is completed by the engine. The main task is to execute executable code at . The execution context is created in this phase.

image.png

9 this

9-1 The point of this:

ES5:

this always points to the object that called it last

ES6 arrow function:

The this of the arrow function always points to the this function is defined not when it is executed.

9-2 How to change the point of this:

  • Use ES6 arrow functions
  • Use _this = this inside the function
  • Use apply, call, bind
  • new instantiates an object

Case 1:

var name = "windowsName";
    var a = {
        name : "Cherry",
        func1: function () {
            console.log(this.name)     
        },
        func2: function () {
            setTimeout(  function () {
                this.func1()
            },100);
        }
    };
    a.func2()     // this.func1 is not a function

If the arrow function is not used, an error will be reported, because the object that finally calls setTimeout is
window, but there is no func1 function in window. Can be seen as window.setTimeout

Case 2:

var webName="long";
let func=()=>{
  console.log(this.webName);
}
func();//long

//The arrow function is declared in the global scope, so it captures this in the global scope, and this points to the window object

Case 3:

var webName = "long";
function wrap(){
  let func=() => {
    console.log(this.webName);
  }
  func();
}
wrap();//long

//When the wrap function is executed, the arrow function func is defined in wrap, and func will find the this of the nearest non-arrow function

//That is the this of wrap, and this in the scope of the wrap function points to the window object.

9-3 Arrow function:

"Tips:" As we all know, the arrow function of ES6 can avoid the pitfall of using this in ES5. The this of the arrow function always points to the this when defined, and when not executed.

The arrow function needs to remember this sentence: "There is no this binding in the arrow function, and its value must be determined by looking up the scope chain (the arrow function itself does not have this, but it can capture other people's this for its own use when it is declared.) , If the arrow function is contained by a non-arrow function, this is bound to the this of the non-arrow function of the nearest layer, otherwise, this is undefined".

Features :

  • Without this
  • No arguments
  • Cannot be called by the new keyword
  • No new.target
  • No prototype
  • No super

click here for details

10 Prototypes and prototype chain

10-1 Background:

A function can be regarded as a class. The prototype is an attribute of all classes. The function of the prototype is to add a unified method to each object of this class.

10-2 Basic concepts

"prototype:" each function will have this property, to emphasize here that is a function, ordinary objects are do not have this property (Why here that ordinary objects, because the JS inside, everything is an object, so The ordinary objects here do not include function objects). It is the prototype object of the constructor;

"" proto ":" each object have this property, to emphasize here that the object is the same, because the function is an object, the function also has this property. It points to the prototype object of the constructor;

"constructor:" This is an attribute on the prototype object that points to the constructor.

var webName = "long";
// Pig的构造函数
function Pig(name, age) {
    this.name = name;
    this.age = age;
}
// 创建一个Pig的实例,小猪佩奇
var Peppa = new Pig('Peppa', 5);
Peppa.__proto__ === Pig.prototype。 //true
Pig.__proto__ === Function.prototype //true
Pig.prototype.constructor === Pig //true

kinky tricks: Han Xin pair drink (display prototype of function = hermit prototype of the object)
click here for details

10-3 What is prototypal inheritance

An object may be used another object of attributes or method, it is called inheritance.

Specifically, by setting the prototype this object to another object, so according to the rules of the prototype chain, if an object property is searched and it does not exist, another object will be searched, which is equivalent to one object can use another The properties and methods of the object are gone.

11 shades of copy

11-1 Shallow clone

function shallowClone(obj) {
  let cloneObj = {};
  
  for (let i in obj) {
    cloneObj[i] = obj[i];
  }
  
  return cloneObj;
}

11-2 Deep clone

Deep clone:

  • Consider the basic type
  • Reference type
  • RegExp, Date, and functions are not JSON safe
  • The constructor will be lost, all constructors point to Object
  • Cracking circular references
function deepCopy(obj) {
  if (typeof obj === 'object') {
    var result = obj.constructor === Array ? [] : {};
    
    for (var i in obj) {
      result[i] = typeof obj[i] === 'object' ? deepCopy(obj[i]) : obj[i];
    }
  } else {
    var result = obj;
  }
  
  return result;
}

click here for details

12 array

12-1 Array de-duplication

1. New Set of

let arr=[1,2,2,3]
let arrNew=[...new Set(arr)]
console.log(arrNew)//[1,2,3]

2. Traverse the old array to add a unique element to the new array

function unique(arr) {
   var newArr = []
   for (var i = 0; i < arr.length; i++) {
      f (newArr.indexOf(arr[i])===-1) {//方式1
          newArr.push(arr[i])
       }
       // if (!newArr.includes(arr[i])) {//方式2
         // newArr.push(arr[i])
       //}
    }
    return newArr
    }
   console.log(unique(arr))//[1,2,3]

3. Use Map data structure to remove

function unique(){
  let map =new Map()
  let arr=new Array()
  for(let i=0;i<arr.length;i++){
   if(map.has(arr[i])){//如果有key值,它是把元素值作为key
      map.set(arr[i],true)
   }else{
     map.set(arr[i],false)//如果没有该key值
     array.push(arr[i])
   }
 }
 return array
}
console.log(unique([1,2,2,3]))

resolution:

Store each element as a key value in the Map. Since the same key will not appear in the Map, the final result after deduplication is obtained.

12-2 Array expansion

1. flat method

  let arr = [1,2,[3,4],[5[6,7]]]
  let arr1 = arr.flat(Infinity)//[1,2,3,4,5,6,7]

2.join,split

let arr = [1,2,[3,4],[5[6,7]]]
let arr1 = arr.join().split(",")  //["1", "2", "3", "4", ""]

3.toString,split

let arr = [1,2,[3,4],[5[6,7]]]
let arr1 = arr.toString().split(",")   //["1", "2", "3", "4", ""]

12-3 Array merge

1. es6 expand and merge

  let arr1 = [1,2]
  let arr2 = [3,4]
  let arr = [...arr1,...arr2]//[1,2,3,4]

2. concat

  let arr = arr1.concat(arr2)

12-4 Judgment array

instanceof

   console.log(arr instanceof Array)

constructor

   console.log(arr.constructor === Array)

Array.isArray

   console.log(Array.isArray(arr))

toString

   console.log(Object.prototype.toString.call(arr) === "[object Array]")

Determine whether there is an array push method

   console.log(!!arr.push && !!arr.concat)

13 objects

13-1 How to determine whether an object is an empty object

1. Convert the json object into a json string, and then judge whether the string is "{}"

var data = {};

var b = (JSON.stringify(data) == "{}"); //true

2.for in loop judgment

var obj = {};
var b = function() {
    for(var key in obj) {
        return false;
    }
    return true;
}

b();//true

3.jquery's isEmptyObject method

This method is that jquery encapsulates 2 methods (for in), and it needs to rely on jquery when using it.

var data = {};

var b = $.isEmptyObject(data);

alert(b);//true

4.Object.getOwnPropertyNames() method

This method uses the getOwnPropertyNames method of the Object object to obtain the property names in the object, store them in an array, and return the array object. We can judge whether the object is empty by judging the length of the array

Note: This method is not compatible with ie8, other browsers have not been tested

var data = {};

var arr = Object.getOwnPropertyNames(data);

alert(arr.length == 0);//true

5. Use ES6's Object.keys() method

Similar to the 4 method, it is a new method of ES6, and the return value is also an array of attribute names in the object

var data = {};

var arr = Object.keys(data);

alert(arr.length == 0);//true

13 v8 engine

13-1 v8 garbage collection

"Background:"

V8's garbage collection strategy is based on the generational collection mechanism, which is based on the generation hypothesis.

This hypothesis has two characteristics :

  • Most newborn subjects tend to early at 160b393690a988;
  • immortal objects, will live too longer.

Based on this theory, modern garbage collection algorithms divide the memory into generations according to the survival time of objects, and use different efficient algorithms for garbage collection for different generations of memory.

"V8 memory generation"

In V8, the memory is divided into (new space) and old (old space).

Their characteristics are as follows:

Cenozoic : The object's survival time shorter. Newborn objects or objects that have been garbage collected .

Old generation : Object longer survival time 160b393690aa2d. experienced one or more garbage collections of 160b393690aa2e.

"V8 heap space"

The space of the V8 heap is equal to the space of the young generation plus the space of the old generation. We can use the --max-old-space-size command to set the maximum space of the old generation, and the --max-new-space-size command to set the maximum space of the young generation. The space size of the old generation and the generation is set when the program 160b393690aa51 is initialized, and cannot be changed dynamically once it takes effect.

  • node --max-old-space-size=1700 test.js // The unit is MB
  • node --max-new-space-size=1024 test.js // unit is KB

By default, the old generation size of 64-bit system is 1400M, and the size of 32-bit system is 700M.

For the new generation, it consists of two reserved_semispace_size. The size of each reserved_semispace_size is different on machines with different bits. The default settings are 16MB and 8MB for 64-bit and 32-bit systems, respectively. We summarize the space size of the young generation, the old generation, and reserved_semispace_size in the following table.

Type\System Digits64 bit32 bit
Old generation1400MB700MB
reserved_semispace_size16MB8MB
New generation32MB16MB

click here for details

14 event loop

14-1 What is the event loop

click here for details 1

details click here 2

15 Advantages and disadvantages of strict mode

15-1 Concept

ECMAScript a five-introduced to better method of error checking code is introduced, most browsers now been implemented. In this mode makes Javascript more stringent operated under conditions

15-2 Advantages

  • It is no longer possible to accidentally create global variables.
  • The assignment operation that causes silent failure (silently fail, that is, no error is reported and no effect) throws an exception.
  • An exception will be thrown when trying to delete a non-deletable attribute (the previous operation will not have any effect).
  • The parameter name of the function is required to be unique.
  • In the global scope, the value of this is undefined.
  • Some common coding errors are caught and exceptions are thrown.
  • Disable confusing or suboptimal features.

15-3 Disadvantages

  • Many features that developers have become accustomed to are missing.
  • Cannot access function.caller and function.arguments.
  • Combining scripts written in different strict modes may cause problems.

16 ES6

16-1 Background

EC versionrelease timeNew features
2009(ES5)November 2009Expanded the functions of Object, Array, Function and other new features
2015(ES6)June 2015Classes, modularity, arrow functions, default values of function parameters, etc.
2016(ES7)March 2016includes, exponential operator
2017(ES8)June 2017sync/await, Object.values(), Object.entries(), String padding, etc.

16-2 Common Features

  • class
  • Modular
  • Arrow function
  • Function parameter default value
  • Template string
  • Destructuring assignment
  • Spread operator
  • Object property shorthand
  • Promise
  • Let and Const

"(1) class"

In traditional javascript, there are only objects and no concept of classes.

It is an object-oriented language based on prototypes. The characteristic of the prototype object is to share its own properties with the new object.
Compared with other traditional object-oriented languages, this kind of writing is very unique! It's very confusing!
If you want to generate an object instance, you need to define a constructor first, and then complete it through the new operator.

The following example demonstrates the evolution from constructor to class:

constructor -

function Person(name,age) {
    this.name = name;
    this.age=age;
}
Person.prototype.say = function(){
    return "我的名字叫" + this.name+"今年"+this.age+"岁了";
}
var obj=new Person("laotie",88);
//通过构造函数创建对象,必须使用new 运算符
console.log(obj.say());//我的名字叫laotie今年88岁了

ES6 introduces the concept of Class (class), and classes can be defined through the class keyword.

The appearance of this keyword makes it clearer in object writing, more like an object-oriented language.

If you change the previous code to ES6, it will look like this:

class--

class Person{//定义了一个名字为Person的类
    constructor(name,age){//constructor是一个构造方法,用来接收参数
        this.name = name;//this代表的是实例对象
        this.age=age;
    }
    say(){//这是一个类的方法,注意千万不要加上function和逗号
        return "我的名字叫" + this.name+"今年"+this.age+"岁了";
    }
}
var obj=new Person("laotie",88);
console.log(obj.say());//我的名字叫laotie今年88岁了
console.log(typeof Person);//function--类实质上就是一个函数
console.log(Person===Person.prototype.constructor);//true
//类自身指向的就是构造函数。所以可以认为ES6中的类其实就是构造函数的另外一种写法!

Note:

  1. When declaring a method in a class, do not add the function keyword to the method
  2. Do not use commas to separate methods, otherwise an error will be reported
  3. There is no variable promotion for class, so it needs to be defined before use. Because ES6 does not promote the declaration of the class to the head of the code, but ES5 is not the same, ES5 has variable promotion, you can use it first, and then define it.
//ES5可以先使用再定义,存在变量提升
new A();
function A(){
}
//ES6不能先使用再定义,不存在变量提升 会报错
new B();//B is not defined
class B{
}

"(2) Module"

background

In the previous javascript, there was no concept of modularity. If you want to perform modular operations, you need to introduce a third-party class library. With the development of technology, the front-end and the back-end are separated, and the front-end business becomes more and more complicated. It was not until ES6 brought modularity that javascript supported modules for the first time. ES6 modularity is divided into two modules export and import.

The usage of export

In each ES6 module that is a files, variables defined in file, function, object outside is can not be obtained. If you want the content of the module to be read externally, you must use export to expose it (output)

Let's first look at an example to modularize a variable.

//我们先来创建一个test.js文件,来对这一个变量进行输出:
export let myName="laowang";
//然后可以创建一个index.js文件,以import的形式将这个变量进行引入:
import {myName} from "./test.js";
console.log(myName);//laowang

If you want to output multiple variables of you can package these variables into objects for modular output:

let myName="laowang";
let myAge=90;
let myfn=function(){
    return "我是"+myName+"!今年"+myAge+"岁了"
}
export {
    myName,
    myAge,
    myfn
}

******************************接收的代码调整为********************* 

import {myfn,myAge,myName} from "./test.js";
console.log(myfn());//我是laowang!今年90岁了
console.log(myAge);//90
console.log(myName);//laowang

If you don't want to expose the variable name in the module, you can do it through as:

let myName="laowang";
let myAge=90;
let myfn=function(){
    return "我是"+myName+"!今年"+myAge+"岁了"
}
export {
    myName as name,
    myAge as age,
    myfn as fn
}
/******************************接收的代码调整为**********************/
import {fn,age,name} from "./test.js";
console.log(fn());//我是laowang!今年90岁了
console.log(age);//90
console.log(name);//laowang

You can also directly import the entire module and modify the above receiving code to:

import * as info from "./test.js";//通过*来批量接收,as 来指定接收的名字
console.log(info.fn());//我是laowang!今年90岁了
console.log(info.age);//90
console.log(info.name);//laowang

Default export (default export) A module can only have one default export. For the default export, the name of the import can be inconsistent with the name of the export.

/******************************导出**********************/
export default function(){
    return "默认导出一个方法"
}
/******************************引入**********************/
import myFn from "./test.js";//注意这里默认导出不需要用{}。
console.log(myFn());//默认导出一个方法

You can put all the variables that need to be exported into an object, and then export through default export

/******************************导出**********************/
export default {
    myFn(){
        return "默认导出一个方法"
    },
    myName:"laowang"
}
/******************************引入**********************/
import myObj from "./test.js";
console.log(myObj.myFn(),myObj.myName);//默认导出一个方法 laowang

Also supports mixed export

/******************************导出**********************/
export default function(){
    return "默认导出一个方法"
}
export var myName="laowang";
/******************************引入**********************/
import myFn,{myName} from "./test.js";
console.log(myFn(),myName);//默认导出一个方法 laowang

Renaming export and import If the variable names in multiple imported files are the same, there will be a naming conflict problem. To solve this problem, ES6 provides a renaming method. You can do this when importing names:

/******************************test1.js**********************/
export let myName="我来自test1.js";
/******************************test2.js**********************/
export let myName="我来自test2.js";
/******************************index.js**********************/
import {myName as name1} from "./test1.js";
import {myName as name2} from "./test2.js";
console.log(name1);//我来自test1.js
console.log(name2);//我来自test1.js

"(3) Arrow function"

Check the 1-5-3 arrow function section:

The this of the arrow function always points to the this when the function was defined, not when it was executed. The arrow function needs to remember this sentence: "There is no this binding in the arrow function, and its value must be determined by looking up the scope chain. If the arrow function is contained by a non-arrow function, then this is bound to the nearest non-arrow function The this, otherwise, this is undefined".

「(4) Default value of function parameters」

ES6 supports setting default values when defining functions:

function foo(height = 50, color = 'red')
{
    // ...
}

Do not use the default value:

function foo(height, color)
{
    var height = height || 50;
    var color = color || 'red';
    //...
}

This is generally no problem, but when the Boolean value of the parameter is false, there will be a problem.
For example, we call the foo function like this: foo(0, "") Because the Boolean value of 0 is false, the value of height will be 50. Similarly, the value of color is'red'. So, the default value of function parameters can not only make the code more concise but also avoid some problems.

「(5) Template String」

ES6 supports the definition of function ES6 supports template strings, making the splicing of strings more concise and intuitive.

Do not use template strings:

var name = 'Your name is ' + first + ' ' + last + '.'

Use template strings:

var name = `Your name is ${first} ${last}.`

In ES6 by ${} can be completed string concatenation, simply variables in large brackets in.

「(6) Deconstruction Assignment」

Deconstruction assignment syntax is an expression of JavaScript, it can easily from array or fast object extract the value assigned to the defined variables.

Get the value in the array

//从数组中获取值并赋值到变量中,变量的顺序与数组中对象顺序对应。
var foo = ["one", "two", "three", "four"];
var [one, two, three] = foo;
console.log(one); // "one"
console.log(two); // "two"
console.log(three); // "three"
//如果你要忽略某些值,你可以按照下面的写法获取你想要的值
var [first, , , last] = foo;
console.log(first); // "one"
console.log(last); // "four"
//你也可以这样写
var a, b; //先声明变量
[a, b] = [1, 2];
console.log(a); // 1
console.log(b); // 2
//如果没有从数组中的获取到值,你可以为变量设置一个默认值。
var a, b;
[a=5, b=7] = [1];
console.log(a); // 1
console.log(b); // 7
//通过解构赋值可以方便的交换两个变量的值。
var a = 1;
var b = 3;
[a, b] = [b, a];
console.log(a); // 3
console.log(b); // 1

Get the value in the object

const student = {
  name:'Ming',
  age:'18',
  city:'Shanghai'  
};
const {name,age,city} = student;
console.log(name); // "Ming"
console.log(age); // "18"
console.log(city); // "Shanghai"

"(7) Extension Operator"

In ECMAScript 2018, the extension operator adds support for objects for the disassembly of objects and arrays

var obj1 = { foo: 'bar', x: 42 };
var obj2 = { foo: 'baz', y: 13 };
var clonedObj = { ...obj1 };
// 克隆后的对象: { foo: "bar", x: 42 }
var mergedObj = { ...obj1, ...obj2 };
// 合并后的对象: { foo: "baz", x: 42, y: 13 } 相同属性会进行覆盖
//我们可以这样合并数组:
var arr1=['a','b','c'];
var arr2=[...arr1,'d','e']; //['a','b','c','d','e']
//展开运算符也可以用在push函数中,可以不用再用apply()函数来合并两个数组:
var arr1=['a','b','c'];
var arr2=['d','e'];
arr1.push(...arr2); //['a','b','c','d','e']
//用于解构赋值
let [arg1,arg2,...arg3] = [1, 2, 3, 4];
arg1 //1
arg2 //2
arg3 //['3','4']
//展开运算符既然能合并数组,自然也能解构数组,不过要注意,解构赋值中【展开运算符】只能用在【最后】:
let [arg1,...arg2,arg3] = [1, 2, 3, 4]; //报错

「(8)

ES6 allows us to not specify the property name when setting the properties of an object.

Does not use ES6

const name='Ming',age='18',city='Shanghai';
const student = {
    name:name,
    age:age,
    city:city
};
console.log(student);//{name: "Ming", age: "18", city: "Shanghai"}
//对象中必须包含属性和值,显得非常冗余。

Use ES6

const name='Ming',age='18',city='Shanghai'; 
const student = {
    name,
    age,
    city
};
console.log(student);//{name: "Ming", age: "18", city: "Shanghai"}
//对象中直接写变量,非常简洁。

「(9) Promise」 What is Promise

Promise is a solution for asynchronous programming, which is more reasonable and more powerful than the traditional asynchronous solution callback function and event. It has now been incorporated into the specification by ES6.

Here are a few cases to deepen the understanding of promises:

(1) The Promise constructor is executed synchronously. Then is asynchronous

const promise = new Promise((resolve, reject) => {
  console.log(1)
  resolve()
  console.log(2)
})
promise.then(() => {
  console.log(3)
})
console.log(4)
//运行结果:1 2 4 3

Analysis: The Promise constructor is synchronously by promise.then , and the function in is executed asynchronously by 160b393690b300.

(2) Once the promise status is changed, it cannot be changed again

const promise = new Promise((resolve, reject) => {
  resolve('success1')
  reject('error')
  resolve('success2')
})
promise
  .then((res) => {
    console.log('then: ', res)
  })
  .catch((err) => {
    console.log('catch: ', err)
  })
//运行结果:then: success1

Resolution: The resolve or reject in the constructor is only the first execution of Calling multiple times by 160b393690b337 has no effect on . Once the promise state changes, it cannot be changed.

(3) .then or .catch will return a new promise

Promise.resolve(1)
  .then((res) => {
    console.log(res)
    return 2
  })
  .catch((err) => {
    return 3
  })
  .then((res) => {
    console.log(res)
  })
//运行结果:1 2

Resolution: Promises can be chained. When it comes to chain calls, we usually think of implementing it through return this, but Promise is not implemented in this way. Every time a promise is called .then or .catch, a new promise is returned, thus realizing a chain call.

(4) The Promise constructor is executed only once

const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    console.log('once')
    resolve('success')
  }, 1000)
})
const start = Date.now()
promise.then((res) => {
  console.log(res, Date.now() - start)
})
promise.then((res) => {
  console.log(res, Date.now() - start)
})
//运行结果:once
          success 1005
          success 1007

Resolution: The .then or .catch of a promise can be called multiple times, but here the Promise constructor is only executed once. In other words, once the internal state of the promise changes (the first call to .then changes), and there is a value, then each subsequent call to .then or .catch will get the value directly.

(5) .then or .catch will return a new promise

Promise.resolve()
  .then(() => {
    return new Error('error!!!')
  })
  .then((res) => {
    console.log('then: ', res)
  })
  .catch((err) => {
    console.log('catch: ', err)
  })
//运行结果:then: Error: error!!!
    at Promise.resolve.then (...)
    at ...

Analysis: Returning an error object in .then or .catch will not throw an error, so it will not be caught by subsequent .catch, and it needs to be changed to one of them:

  1. return Promise.reject(new Error('error!!!'))
  2. throw new Error('error!!!')

Because returning any non-promise value will be wrapped into a promise object, that is, return new Error('error!!!') is equivalent to return Promise.resolve(new Error('error!!!')).

(6) The value returned by .then or .catch cannot be the promise itself

const promise = Promise.resolve()
  .then(() => {
    return promise
  })
promise.catch(console.error)
//运行结果:TypeError: Chaining cycle detected for promise #<Promise>
    at <anonymous>
    at process._tickCallback (internal/process/next_tick.js:188:7)
    at Function.Module.runMain (module.js:667:11)
    at startup (bootstrap_node.js:187:16)
    at bootstrap_node.js:607:3

Resolution: The value returned by .then or .catch cannot be the promise itself, otherwise it will cause an endless loop.

(7) .then function return value type and parameter passing

Promise.resolve(2) // resolve(2) 函数返回一个Promise<number>对象
.then(x=>{
   console.log( x ); // 输出2, 表示x类型为number且值为2,也就是上面resolve参数值
   return "hello world"; // 回调函数返回字符串类型,then函数返回Promise<string>
}) // then函数返回Promise<string>类型
.then(x=>{
   console.log( x ); // 输出hello world,也就是上一个then回调函数返回值,表明上一个then的返回值就是下一个then的参数
}) // then函数回调函数中没有返回值,则为Promise<void>
.then(x=>{ // 前面的then的回调函数没有返回值所以这个x是undefined
   console.log( x ); // undefined
}) // Promise<void>
.then(()=>{ // 前面没有返回值,这里回调函数可以不加返回值
   return Promise.resolve("hello world"); // 返回一个Promise<string>类型
}) // 这里then的返回值是Promise<string>
.then(x=>{ // 虽然上面的then中回调函数返回的是Promise<string>类型但是这里x并不是Promise<string>类型而是string类型
   console.log(x); // hello world
   return Promise.resolve(2); // 返回一个Promise<number>类型对象
}) // 返回Promise<number>类型

(8) The parameter of .then or .catch is expected to be a function, passing in a non-function will cause value penetration.

Promise.resolve(1)
  .then(2)
  .then(Promise.resolve(3))
  .then(console.log)  //1

Analysis: The parameter of .then or .catch is expected to be a function, and value penetration occurs when a non-function is passed in.

(9) .catch is equivalent to shorthand for .then (the second parameter of .then is omitted)

Promise.resolve()
  .then(function success (res) {
    throw new Error('error')
  }, function fail1 (e) {
    console.error('fail1: ', e)
  })
  .catch(function fail2 (e) {
    console.error('fail2: ', e)
  })
//运行结果:fail2: Error: error
          at success (...)
          at ...

Analysis: .then can receive two parameters, the first is a function that handles success, and the second is a function that handles errors. .catch is also equivalent to a .then, except that the second parameter of .then is omitted, but there is one point to note in their usage: the second error handling function of .then cannot capture the first successfully processed function The error thrown, and the subsequent .catch can catch the previous error.

(10) Micro task macro task execution order

process.nextTick(() => {
  console.log('nextTick')
})
Promise.resolve()
  .then(() => {
    console.log('then')
  })
setImmediate(() => {
  console.log('setImmediate')
})
console.log('end')
//运行结果:end
          nextTick
          then
          setImmediate

Analysis: process.nextTick and promise.then both belong to microtask , and setImmediate belongs macrotask in the check phase of the event loop. The microtask is executed between each stage of the event loop (macrotask), and the microtask is executed once at the beginning of the event loop.

「(10) let and const」

View 1-1js variable declaration

17 Event stream

The event flow is the order in which webpage elements receive events. The event flow specified by "DOM2 Level Events" includes three stages: event capture stage, in the target stage, and event bubbling stage.

  • The capture of the first event provides an opportunity to intercept the event.
  • Then there is the actual target acceptance event.
  • The last stage is the time bubbling stage, where you can respond to events.

Although the capture phase stipulates that it is not allowed to respond to events in the specification, it will actually be executed, so there are two opportunities to obtain the target object.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>事件冒泡</title>
</head>
<body>
    <div>
        <p id="parEle">我是父元素    
            <span id="sonEle">我是子元素</span>
        </p>
    </div>
</body>
</html>
<script type="text/javascript">
var sonEle = document.getElementById('sonEle');
var parEle = document.getElementById('parEle');

parEle.addEventListener('click', function () {
    alert('父级 冒泡');
}, false);
parEle.addEventListener('click', function () {
    alert('父级 捕获');
}, true);

sonEle.addEventListener('click', function () {
    alert('子级冒泡');
}, false);
sonEle.addEventListener('click', function () {
    alert('子级捕获');
}, true);

</script>

When container elements and nested elements call event handlers in the capturing phase and in the bubbling phase: the events execute the event handlers in the order of the DOM event stream:

Parent capture="child capture="child bubbling="parent bubbling

  • Click [I am the parent element], and pop up in turn ('parent capture'="'parent bubbling')
  • Click [I am the parent element] and pop up in turn ('parent capture'="child capture'="'child bubbling'="'parent bubbling')

kinky skills : three stages can be remembered this 160b393690b61e catching a female cat (capture, target, bubbling)

18 new

Construct call:

  • Create a brand new object
  • This o

子树
448 声望129 粉丝

[链接]