Scope and scope chain

A scope is essentially a rule by which a program stores and accesses variables, and a chain formed by looking up variables up the scope is a scope chain

JS scope is divided into: global scope, function scope, block – level scope

JS is lexical scoped (static scoped) not dynamic scoped

Features of lexical scope:

The scope is determined at the defined location, not the location of the call

What is a closure

A closure is a function that fetches free variables inside another function.

Closures: Return functions inside functions, call back functions (functions as arguments)

Advantages of closures:

① Preserve function variables from external pollution

② Save the values in the function and delay execution

Disadvantages of closures:

Overuse of closures can lead to excessive memory usage, so use closures with caution

Closure applications: stabilization, throttling, currification, encapsulating simulated private variables

Function foo(a,b){console.log(b); return { foo:function(c){ return foo(c,a); Var func1=foo(0); func1.foo(1); func1.foo(2); func1.foo(3); var func2=foo(0).foo(1).foo(2).foo(3); var func3=foo(0).foo(1); func3.foo(2); func3.foo(3); Function debunce (fn, time=500) {let timeout = null; function debunce (fn, time=500) {let timeout = null; return function(... args){ if(timeout) clearTimeout(timeout); timeout = setTimeout(() => { fn.call(this, ... args); }, time); }}} function throttle(fn, time=500) {let flag = true; return function(... args){ if(! flag) return; flag=false; setTimeout(() => { fn.call(this, ... args); flag=true; }, time); } } function sayHi(e) { console.log(e.target.innerWidth, e.target.innerHeight); } window.addEventListener('resize', throttle(sayHi));Copy the code

Currie,

Corrification is the process of transforming a function that takes n parameters into n nested functions that take only one parameter. Is the fn (a, b, c) fn (a, b, c) will become fn (a) (b) (c) fn (a) (b) (c); The purpose is to “remember” some of the parameters of a function;

Partial function

Fix one or more arguments to your function, and return a new function that accepts the rest of the arguments.

Variable promotion and temporary dead zones

Function declarations take precedence over variable declarations and are promoted to the top of the code block

The essence of variable promotion is that JS will find all variable declarations at compile time and make them effective in advance; The essence of a temporary dead zone is that js compilation detects the declaration of a variable, but the state is not accessible, so an error will be reported before the declaration is used.

(1) Variable promotion: variables declared with var will have variable promotion (declaration will be promoted, assignment will not)

Var a = []; for (var i = 0; i < 10; i++) { a[i] = function () { console.log(i); }; } a[6](); Var a = 1; function test(){ a = 2; return function(){ console.log(a); } var a = 3; } test()(); Var a = 0; if(true) { a = 1; function a() {}; a = 21; Console. log(' inside '+ a); } console.log(' outside '+ a); Chestnut 3: test(); console.log(test); Var test = 'I am a variable '; console.log(test); Var test = function (params) {console.log(' I am a function expression '); } console.log(test); Function test() {console.log(' I'm a function '); } console.log(test); test();Copy the code

(2) Temporary dead zone: there is a temporary dead zone with let and const life variables

var me = 'icon'; { me = 'lee'; let me; } // An error will be reportedCopy the code

What are the conditions that might cause a memory leak

1. Unexpected global variables;

2. Closures (older browser closures caused memory leaks and do not now cause memory leaks when used correctly);

3. The timer is not cleared.

4. Undestroyed event monitoring;

5. Uncleared DOM references;

5, JS memory management mechanism

The base type is stored in the stack, and the reference type is stored in the heap, and the address of the reference type is stored in the stack.

① Reference counting method (obsolete)

② Mark removal method

In the tag clearing algorithm, the criterion for determining whether a variable is needed is whether it is reachable.

This algorithm has two stages, marking stage and clearing stage respectively:

  • Marking phase: The garbage collector first finds the root object, which in the browser is Window; In Node, the object is Global. Starting from the root object, the garbage collector scans all variables that can be reached through the root object, and these objects are marked as “reachable.”
  • Cleanup phase: Variables that are not marked as “reachable” are considered unwanted and the wave variables are cleared

6. The orientation of this

(1) This in the arrow function refers to the object at the time of definition;

A normal function’s this refers to the object on which it was called;

(2) Non-strict mode, non-arrow function, this must point to window in the following three cases

  • Execute function immediately
  • setTimeout
  • setInterval

(3) In strict mode, this in the global scope refers to the window, and this in the function body or code block is undefined

'use stric' console.log(this); function showMine(){ console.log(this); } window undefined undefined 2: 'use strict' var name = 'BigBear' var me = {name: 'yeyong', hello: Function () {setTimeout(function() {console.log(' hello, I am ${this.name} ')}} me. Output: Hello, I'm BigBearCopy the code

(4) The arrow function’s this always points to the object at which it was defined

var a = 1
var obj = {
  a: 2,
  func2: () => {
    console.log(this.a)
  },
  
  func3: function() {
    console.log(this.a)
  }
}

// func1
var func1  = () => {
  console.log(this.a)
}

// func2
var func2 = obj.func2
// func3
var func3 = obj.func3

func1()
func2()
func3()
obj.func2()
obj.func3()
Copy the code

7, Change this to call/apply/bind

Function.prototype.call = function(context, ... args){ let fn = Symbol(); Context. fn = this; // Context. fn = this; // Now this function is called by context, so this inside this function refers to context context.fn(... args); delete context.fn; } Function.prototype.apply = function(context, args){ let fn = Symbol(); Context. fn = this; // Context. fn = this; // Now this function is called by context, so this inside this function refers to context context.fn(... args); delete context.fn; } Function.prototype.bind= function(context){ return function (.. args){ call(context, ... args); }}Copy the code

8. What is the difference between Call and apply, and which has better performance

The function is the same, but the difference is that the arguments passed in are different, so the first argument is to specify the point of this in the function,

  • The second argument starts differently. Apply passes a collection, array, or class array with a lower index. Apply passes it to a function as an argument.
  • Call performs better than Apply in that the format of the call parameter is the format required internally.

8. What is the difference between arrow functions and ordinary functions? Constructors can use new to generate instances, but can arrow functions? Why is that?

Arrow function is short for ordinary function, which can define a function more elegantly. Compared with ordinary function, there are the following differences:

  • The this object inside the function is the object at which it is defined, not used;
  • You cannot use the Arguments object, which does not exist in the function body. The rest argument can be used instead (… Args collection parameters);
  • Yield cannot be used, so arrow functions cannot be used as Generator functions;
  • The new command cannot be used because: A. Call and apply cannot be called without this; B. There is no prototype attribute, and the new command assigns the constructor’s prototype value to the __proto__ of the new object.

9. New Principle

What happened in New:

  • Create a new object (prototype from the constructor’s prototype)

  • Assigns the constructor’s scope to the new object (thus this refers to the new object)

  • Execute the code in the constructor (add new properties to this object)

  • Return a new object

    // new function new (fn,… args){ let object = Object.create(fn.prototype); let result = fn.call(object, … args); return result instanceof Object? result : object; } // object.create () creates a new Object, using an existing Object to provide the __proto_ of the newly created Object. //Instanceof returns true if both lines can find the same reference, i.e., the same object. //Instanceof returns true if both lines find the same reference, i.e. Return false if the ends are not found yet

10. Prototype and prototype chain

Prototype: Each function has a prototype property that points to the function’s prototype object. By default, all stereotype objects automatically acquire a constuctor (constructor) property that points to the constructor (or function) itself.

Each Object has a __proto__ that points to the prototype of the function that created the Object, namely fn.__proto__ === fn.prototype (except for objects created by object.create (null)).

function Foo(){} var f1 = new Foo(); f1 instanceof Foo; f1 instanceof Object; Function instanceof Object Function instanceof Function // both are trueCopy the code

Var A = function() {}; A.prototype.n = 1; var b = new A(); A.prototype = { n: 2, m: 3 } var c = new A(); console.log(b.n); console.log(b.m); console.log(c.n); console.log(c.m); // undefined 2 3 考题2: Function A() {this.name = 'A' this.color = ['green', 'yellow'] } function B() {} B.prototype = new A() var b1 = new B() var b2 = new B() b1.name = 'change' B2.color. push('black') console.log(b2.name) // 'a' console.log(b2.color) // ["green", "yellow", "black"] 考题3: Typeof null === 'object', then null instanceof object? Function Foo() {getName = function () {alert (1); }; return this; } Foo.getName = function () { alert (2); }; Foo.prototype.getName = function () { alert (3); }; var getName = function () { alert (4); }; function getName() { alert (5); } // Write the following output: foo.getName (); getName(); Foo().getName(); // This refers to window getName(); new Foo.getName(); / / with the new (Foo getName (); new Foo().getName(); / / with (new Foo ()). The getName () new new Foo (). The getName (); // same as new ((new Foo()).getName)(); // 2 4 1 1 2 3 3 new Foo().getName().getName(); / 1/3Copy the code

New (with argument list)

n/a

The new... (...).

New (no argument list)

From right to left

The new...

function Foo(){ Foo.a = function (){ console.log(1); } this.a = function(){ console.log(2) } } Foo.prototype.a = function(){ console.log(3); } Foo.a = function(){ console.log(4); } Foo.a(); let obj = new Foo(); obj.a(); Foo.a(); / / 4, 2, 1Copy the code

How to convert an array of classes to an array

Array.from({length: 3});

The […arrLike] extension operator, but the extension operator works only on iterable objects, that is, values that have the Symbol(symbol.iterator) attribute, and can be used for… Of traverse;

Array. The prototype. Slice. Call (arrayLike);

/ / similar with Array. Apply (null, arrayLike) Array. The prototype. Concat. Apply ([], ArrayLike) / / the following method to consider the sparse Array into an Array. The prototype. Filter. The call (divs, x = > 1) Array. The prototype. The map. The call (arrayLike, X = > x) Array. The prototype. The filter. The call (arrayLike, x = > 1) / / all the class arrays as this method will return a sparse Array, / / and the class arrays as parameters the arguments of the method will return dense ArrayCopy the code

A way to get rid of weight

Function unique(array) {return [...new Set(array)]; } // indexOf const a = [1,1,2,2,3,4,4,3,5] function unique(arr) {if (! Array.isArray(arr)) { console.log('type error! ') return } return arr.filter((item, index) => { return arr.indexOf(item) === index; }); Function distinct(array) {var obj = {}; return array.filter(function(item, index, array){ return obj.hasOwnProperty(typeof item + item) ? Var resources = [{id: 1, name: "typeof item ", age: "18"}, {id: 1, name:" typeof item ", age: "18"} 2, the name: "zhang", the age: "19"}, {id: 1, name: "zhang", the age: "20"}, {id: 3, name: "bill", the age: "19"}, {id: 3, name: "detective", the age: "20"}, {id: 2, id: 1, age: 1}]; Function unique(arr,uniId){let map = new map (); return arr.filter(item => { return ! map.has(item[uniId]) && map.set(item[uniId], true); }); Function unique1(arr, uniId){let map = new map (); return arr.reduce((total, item)=>{ map.has(item[uniId])? '': map.set(item[uniId], true) && total.push(item); return total; }}, [])Copy the code

Array flattening method

Function flatten(arr){var result = []; for(let i = 0; i< arr.length; i++){ if(Array.isArray(arr[i])){ result = result.concat(flatten(arr)); }else{ result = arr[i]; } } return result; } 2.toString() const flatten = arr => arr.toString().split(',').map((item) => +item); 3.reduce function flatten(arr) { return arr.reduce((pre, item)=>{ return pre.concat(Array.isArray(item)? flatten(item) : item) }, []); Function flatten(arr){while(arr.some(item => array.isarray (item))){arr = [].concat(... arr) } return arr; MyFlat = function(num){function(num) --; return num>=0? this.reduce((pre, item) => { return pre.concat(Array.isArray(item)? item.myFlat(num) : item); },[]) : this; } arr.myFlat(1);Copy the code

A method to merge two arrays

Let a = [1,2] let b = [3,4] let c = [...a,...b] let c = [...a,...b] let c = a.push. Apply (a,b) for(let I of b){a.push(I) }Copy the code

[‘1’, ‘2’, ‘3’].map(parseInt) what & why ?

[‘ 1 ‘, ‘2’, ‘3’). The map (parseInt) the output of the results of [1, NaN, NaN].

Because parseInt(String, radix) converts a string string into integers for radix radix, the radix is between 2-36.

Item and index are passed as the first two arguments in the map callback, so parseInt executes the corresponding three times

parseInt(1, 0)

parseInt(2, 1)

parseInt(3, 2)

The corresponding execution results are 1, NaN, and NaN.

If the radix is undefined, 0, or unspecified, JavaScript assumes the following:

If the input string begins with “0x” or “0x” (a zero followed by a lowercase or uppercase X), the radix is assumed to be 16 and the rest of the string is parsed as a hexadecimal number;

If the input string begins with “0” (0), the radix is assumed to be 8 (octal) or 10 (decimal). Which radix to choose depends on the implementation. ECMAScript 5 clarifies that 10 (decimal) should be used, but not all browsers support it.

Therefore, it is important to specify a radix when using parseInt. If the input string begins with any other value, the radix is 10 (decimal). If the first character cannot be converted to a number, parseInt returns NaN.

Introduce the difference between Set, Map, WeakSet and WeakMap?

Set:

1). Members cannot be repeated;

2). Only key values, no key names, kind of like array;

3). The method can be add, delete, has, clear

WeakSet:

1). Members are objects (references);

WeakSet can accept an array or array-like object as a parameter.

Var a = [[1,2], [3,4]]; Var ws = new WeakSet(a); var ws = new WeakSet(a);Copy the code

2). Members are weak references and can disappear at any time (not counted in the garbage collection mechanism). Can be used to save DOM nodes, will not cause memory leaks;

3). Cannot traverse, does not have the size attribute, cannot clear(), methods include add, delete, has;

The Map:

1). It is essentially a set of key-value pairs, similar to a set;

2). Can traverse, many methods, can be converted with a variety of data formats;

WeakMap:

1). Accept only objects as key names (except null), and do not accept values of other types as key names;

2). Objects pointed to by the key name are not included in the garbage collection mechanism; The special occasion of WeakMap is that the object corresponding to its key may disappear in the future;

Clear () can not be traversed, no size attribute, can not clear(), methods include get, set, has, delete;

= =”

Instances of the Set structure have the following properties.

  • Set. The prototype. The constructor: constructor, the default is Set function.
  • Set.prototype.size: Returns the total number of members of a Set instance.

The methods of a Set instance fall into two broad categories: operation methods (for manipulating data) and traversal methods (for traversing members). The following four operations are introduced.

  • Add (value) : Adds a value and returns the Set structure itself.
  • Delete (value) : deletes a value and returns a Boolean value indicating whether the deletion is successful.
  • Has (value) : Returns a Boolean value indicating whether the value is a member of Set.
  • Clear () : Clears all members with no return value

An instance of a Set structure has four traversal methods that can be used to traverse members.

  • Keys () : returns a traverser for key names
  • Values () : Iterator that returns key values
  • Entries () : Returns a traverser for key and value pairs
  • ForEach () : Iterates through each member using the callback function

Map operation method:

  • Set (key, value) : The set method sets the key value corresponding to the key and returns the Map structure. If the key already has a value, the key value is updated, otherwise the key is generated and can be chained
  • Get (key) : The get method reads the key corresponding to the key. If the key cannot be found, undefined is returned
  • Has (key) : The HAS method returns a Boolean value indicating whether a key is in the Map data structure
  • Delete (key) : The delete method deletes a key and returns true. If deletion fails, return false.
  • Clear () : Clears all members with no return value

Map natively provides three traverser generating functions and one traversal method.

  • Keys () : returns a traverser for key names.
  • Values () : Iterator that returns key values.
  • Entries () : Returns a traverser for all members.
  • ForEach () : traverses all Map members.

Note in particular that the Map traversal order is the insertion order.

WeakSet application:

const foos = new WeakSet() class Foo { constructor() { foos.add(this) } method () { if (! Foos.has (this)) {throw new TypeError(' foo.prototype. method can only be called on instances of Foo! '); }}}Copy the code

The above code ensures that instance methods of Foo can only be called on instances of Foo. The advantage of using WeakSet here is that the reference to the instance by foos is not counted in the memory reclamation mechanism, so when deleting the instance, you do not need to consider foos and there is no memory leak.

WeakMap application:

WeakMap is designed so that the key name is a weak reference to the object (which is not taken into account by the garbage collection mechanism), so its corresponding object may be automatically reclaimed. When the object is reclaimed, WeakMap automatically removes the corresponding key-value pair. A typical application is a WeakMap structure corresponding to DOM elements. When a DOM element is cleared, its corresponding WeakMap record will be automatically removed. Basically, the special use of WeakMap is that the object to which its key corresponds may disappear in the future. The WeakMap structure helps prevent memory leaks.

Below is an example of WeakMap structure, you can see that the usage is almost the same as Map.

var wm = new WeakMap();
var element = document.querySelector(".element");

wm.set(element, "Original");
wm.get(element) // "Original"

element.parentNode.removeChild(element);
element = null;
wm.get(element) // undefined
Copy the code

In the above code, the variable WM is a WeakMap instance, we take a DOM node element as the key name, and then destroy this node, the corresponding key of Element will automatically disappear, and then reference this key name will return undefined.

What is the difference between ES5/ES6 inheritance other than the way it is written?

ES5 inheritance essentially creates an instance object of the subclass, this, and then adds the Parent class’s methods to this (parent.apply (this)). ES6 has a completely different inheritance mechanism, essentially adding the properties and methods of the superclass instance object to this (so the super method must be called first), and then modifying this with the constructor of the subclass.

class A {} class B extends A { constructor() { super(); }} / / super () is equivalent to Amy polumbo rototype here. The constructor. Call (this)Copy the code

Juejin. Cn/post / 684490…

SetTimeout, Promise, Async/Await

SetTimeout: The setTimeout callback is placed in the macro task queue until the execution stack is empty.

Promise:

Promise itself is a synchronous execute now function, with resolve and reject parameters representing the method if it succeeds and the method if it fails. If resolve or REJECT is encountered, it is not executed immediately and is put into the microtask queue.

Catch (err)

Async/await:

Async /await is the syntactic sugar of Genenrator, adding self-executing functions on top of generator;

An async function returns a Promise object. When the function executes, it returns an await and waits until the triggered asynchronous operation is complete before executing the following statement in the function body. It can be understood as giving up the thread and jumping out of the async function body;

Normally, the await command is followed by a Promise object (which is converted to a Promise object when it is a Thenable object) and returns the result of that object. If it is not a Promise object, the corresponding value is returned;

Error capture with try… catch…

See asynchrony for details:

Implicit conversion rules

  • ValueOf is called to get the original value. If the original value is not of number type, toString is called to convert it toString and then number to number.

  • There are eight types that return false when converted to a Boolean, and all the others return true:

0, -0, null, undefined, false, “(empty string), NaN, document.all()

Boolean([]), Boolean({}) are both true

Number([]) = 0, Number({}) = NaN (+[] = 0, +{} = NaN)

Reference types are not equal []! = [] {}! = {}

  • Number() +, ==, >=,! =… With logical operators &&, | |,! , conditional operators? Convert to Boolean Boolean()

Under what circumstances does a print 1 in the following code?

var a = ? ; if(a == 1 && a == 2 && a == 3){ console.log(1); Var a = {value: 0, valueOf() {return ++this.value; }};Copy the code