The foundation is the foundation, the key to deeper exploration, the most important step on the road to progress, and every developer needs to pay attention to it. In today’s rapid development and iteration of front-end technology, in the “front-end market is saturated”, “front-end job search is extremely popular”, “front-end entry is simple, many people silly money” and other fickent environment, the training of basic internal skills is particularly important. It’s also key to how far and how long you can go on the front end. From the point of view of the interview, the interview question is in the final analysis to the basis of investigation, only to be thoroughly familiar with the foundation of the chest, in order to have a breakthrough interview basic conditions.

An array ofreduce

The array approach is important: arrays are data, data is state, and state reflects the view. We are familiar with array operations, and the reduce method is especially handy. I think this method is a good embodiment of the concept of “functional”, and it is one of the most popular research points at present.

Its usage syntax:

arr.reduce(callback[, initialValue])

Here we give a brief introduction.

  • The first reduce parameter, callback, is the core. It “stacks” each item of the array, and its last return value is the final return value of the Reduce method. It contains four arguments:

    • previousValueLast timecallbackThe return value of the function
    • currentValueThe element being processed in array traversal
    • currentIndexOptional: indicatescurrentValueCorresponding index in the array. If providedinitialValue, the start index is 0; otherwise, the start index is 1
    • arrayOptional, callreduce()An array of
  • InitialValue Is optional as the first argument when callback is first called. If no initialValue is provided, the first element in the array will be the first argument to the callback.

sum

[1.2.3.4].reduce((acc, cur) = > {
  return acc + cur
}, 10)
// 10 + 1 + 2 + 3 + 4
/ / 20
Copy the code

Convert a two-dimensional array to a one-dimensional array

const testArr = [[1.2], [3.4], [5.6]]
testArr.reduce((acc, cur) = > {
  return acc.concat(cur)
}, [])
/ / [6]
Copy the code

Count the number of occurrences of each element in the array

const testArr = [1.3.4.1.3.2.9.8.5.3.2.0.12.10]
testArr.reduce((acc, cur) = > {
  if(! (curin acc)) {
    acc[cur] = 1
  } else {
    acc[cur] += 1
  }
  return acc
}, {})

/ / {0, 2, 1, 3, 2, 3, 3, 4, 4, 2, 5:2, 8:2, 9:2, 10:2, 12:2}
Copy the code

Classify arrays by attributes

To classify an array by its attributes is to give it a basis and merge it together. Bills, for example, are grouped by type of consumption.

const bills = [
  { type: 'shop'.momey: 223 },
  { type: 'study'.momey: 341 },
  { type: 'shop'.momey: 821 },
  { type: 'transfer'.momey: 821 },
  { type: 'study'.momey: 821}]; bills.reduce((acc, cur) = > {
  // If the key does not exist, set it to an empty array
  if(! acc[cur.type]) { acc[cur.type] = []; } acc[cur.type].push(cur)return acc
}, {})
Copy the code

Array to heavy

I’m not going to explain this. I’m going to go to the code.

const testArr = [1.2.2.3.4.4.5.5.5.6.7]
testArr.reduce((acc, cur) = > {
  if(! (acc.includes(cur))) { acc.push(cur) }return acc
}, [])
// [1, 2, 3, 4, 5, 6, 7]
Copy the code

reduceimplementationrunPromiseInSequence

Let’s look at a typical use of this, running promises in order:

const runPromiseInSequence = (array, value) => array.reduce(

   (promiseChain, currentFunction) => promiseChain.then(currentFunction),

   Promise.resolve(value)

)

The runPromiseInSequence method will be called by an array that returns a Promise for each item and executes each Promise in turn. If you find this confusing, here’s an example:

const f1 = () => new Promise((resolve, reject) => {

   setTimeout(() => {

       console.log('p1 running')

       resolve(1)

}, 1000).

})



const f2 = () => new Promise((resolve, reject) => {

   setTimeout(() => {

       console.log('p2 running')

       resolve(2)

}, 1000).

})



const array = [f1, f2]



const runPromiseInSequence = (array, value) => array.reduce(

   (promiseChain, currentFunction) => promiseChain.then(currentFunction),

   Promise.resolve(value)

)



runPromiseInSequence(array, 'init')

reduceimplementationpipeFunctional granulation

Another typical use of reduce can be seen in the implementation of the functional method pipe: Pipe (f, g, h) is a curried function that returns a new function that completes (… args) => h(g(f(… Args))). That is, the function returned by the PIPE method receives an argument that is passed to the first argument of the pipe method for it to call

const pipe = (... functions) => input => functions.reduce(

   (acc, fn) => fn(acc),

   input

)

Consider the methods runPromiseInSequence and PIPE, which are typical scenarios for Reduce applications.

To implement areduce

So how do we implement a Reduce? Refer to Polyfill from MDN:

if (!Array.prototype.reduce) {
  Object.defineProperty(Array.prototype, 'reduce', {
    value: function(callback /*, initialValue*/) {
      if (this= = =null) {
        throw new TypeError( 'Array.prototype.reduce ' + 
          'called on null or undefined')}if (typeofcallback ! = ='function') {
        throw new TypeError( callback +
          ' is not a function')}var o = Object(this)
      var len = o.length >>> 0
      var k = 0
      var value

      if (arguments.length >= 2) {
        value = arguments[1]}else {
        while(k < len && ! (kin o)) {
          k++
        }
        if (k >= len) {
          throw new TypeError( 'Reduce of empty array ' +
            'with no initial value' )
        }
        value = o[k++]
      }
      while (k < len) {
        if (k in o) {
          value = callback(value, o[k], k, o)
        }
        k++
      }

      return value
    }
  })
}
Copy the code

Value is used as the initial value in the above code, and the result of value is successively calculated and output through the while loop. However, compared with the above implementation of MDN, I prefer the following implementation scheme:

Array.prototype.reduce = Array.prototype.reduce || function(func, initialValue) {

   var arr = this

   var base = typeof initialValue === 'undefined' ? arr[0] : initialValue

var startPoint = typeof initialValue === 'undefined' ? 1:0

   arr.slice(startPoint)

       .forEach(function(val, index) {

           base = func(base, val, index + startPoint, arr)

       })

   return base

}

The core principle is to use forEach instead of while to accumulate results, which are essentially the same.

I also have a look at Pollyfill in ES5-SHIm, which is completely consistent with the above ideas. The only difference is that I used forEach iterations while ES5-Shim uses a simple for loop. In fact, if we were more careful, we would point out that the forEach method for arrays is also a new addition to ES5. Therefore, it makes little sense to use one ES5 API (forEach) to implement another ES5 API (Reduce) — in this case pollyfill is a simulated degradation solution in an ES5-incompatible situation. I will not go into details here, because the fundamental purpose is to give readers a thorough understanding of Reduce.

Through the Koa only module source codereduce

By understanding and implementing the Reduce approach, we already have a better understanding of it. Finally, let’s take a look at an example of reduce usage — via the ONLY module of the Koa source code to make a deeper impression:

var o = {

   a: 'a',

   b: 'b',

   c: 'c'

}

only(o, ['a','b'])   // {a: 'a',  b: 'b'}

This method returns a new object with the specified filter attribute. Only module implementation:

var only = function(obj, keys){

   obj = obj || {}

   if ('string' == typeof keys) keys = keys.split(/ +/)

   return keys.reduce(function(ret, key) {

       if (null == obj[key]) return ret

       ret[key] = obj[key]

       return ret

   }, {})

}

There’s a lot to be said for the little Reduce and its spin-off scenarios. By analogy, active learning and application is the key to technological advancement.

Recursively find id by name

    let str = "";
    var getNameById = (tempData, id) = > {
      for (let i = 0; i < tempData.length; i++) {
        let item = tempData[i];
        if (item.id == id) {
          str = item.name;
          return;
        }
        if (item.children.length > 0) { getNameById(item.children, id); }}return str;
    };
    console.log(getNameById(data, 4));
Copy the code

JavaScript types and their judgments

JavaScript has seven built-in data types, which are:

Basic type: null undefined Boolean number string object Symbol object: function, array, date

Use typeof to determine the type

Typeof applies to the judgment of the other 5 types of the above 7 data types except null and object:

typeof undefined;  // "undefined";
typeof 1;          // "number";
typeof '1';        // "string";
typeof true;       // "boolean";
typeof Symbol(a);// "symbol";
typeof  []    // "object";
Copy the code

How it works: in fact (one of the implementations of Typeof), js stores variable type information at the machine code level 1-3. These machine codes are the “type tags” mentioned above; Here are the following types of “type tags” :

  • 000: object
  • 010: a floating point number
  • 100: string
  • 110: a Boolean value
  • 1: the integer

All of the above are reliable, correct and easy to understand. Let’s look at a few examples that are true, but don’t seem to have the desired results:

  • typeof null === "object"; // true

Cause: Since null represents a null pointer (on most platforms, the value is 0x00), the type label of NULL also becomes 0. Typeof NULL returns “object” incorrectly.

var a = null; ! a &&typeof a === 'object' // true
Copy the code
  • typeof function () {} === "function"; // true

Because a function is a “special object,” it is special because it has a property [[call]] inside it that makes it a “callable object.”

Use instanceof to determine the type

Typeof can determine whether a data is an object, but it cannot determine which “subtype” of the object it is, such as whether it is an array or a date. At this point, instanceof can be used to determine. However, instanceof can only be used to determine if it is the type you expect and only for object subtypes.

** if a is an instanceof B, there is a B constructor ** on the prototype chain of a.

var a = []
a.__proto__=Array.prototype
Copy the code

We use the following code to simulate the Instanceof principle:

// L represents the left expression, R represents the right expression
const instanceofMock = (L, R) = > {
   if (typeofL ! = ='object') {
       return false
   }
   while (true) {
       if (L === null) {
           // Already traversed to the top
           return false
       }
       if (R.prototype === L.__proto__) {
           return true
       }
       L = L.__proto__
   }
}
Copy the code

Use the constructor

We found that for undefined and NULL, an error is reported if an attempt is made to read their constructor property. And constructor returns the constructor itself, which is rarely used to determine the type.

Object.prototype.toString

Use Object. The prototype. ToString judgment types, we call it the “universal method”, “the ultimate method”

The object. prototype property represents the prototype Object of Object; The toString() method returns a string representing the object; Call is used to specify this. So using Object. The prototype. ToString. Call (date) will return a said the date of the prototype Object string (if the date is not Object, will be transformed into Object, except null, and undefined)

Summary of JavaScript type judgment

To judge, so in daily work should be combined with the above several types of judgment method, choose the most simple and reliable.

To sum up, when you want to judge a basic typeof data, you can use typeof to judge, it is simple and reliable; When you want to determine which subtype an object belongs to, you can use the instanceof operator or the constructor property, but you need to have an expected type, or you’ll need to write a different if for each type. else… Statement. Another point to note is that the constructor property can be modified so it is not reliable; Capacity is much, if you don’t too code requires accurate and comprehensive, and then you can use the Object. The prototype. ToString. Call the judgement ().

JavaScript type conversion

console.log(1 + true)
/ / 2
console.log(1 + false)
/ / 1
Copy the code

Conclusion When the + operator is used, if a complex type exists, the complex type is converted to the primitive type and then the operation is performed

This involves the conversion of object types to primitive types. Specific rules:

Conclusion when an object is converted to a base type, two methods, valueOf or toString, are called on the object. The return valueOf this method is the result of the conversion to the base type

Does it call valueOf or toString? This is determined by the ES specification, and really depends on the result of the built-in toPrimitive call. Subjectively, whichever method is called takes precedence over the object’s inclination to be converted. If the conversion to Number is preferred, valueOf is called first. If you prefer to cast toString, just call toString. I recommend that you look at some common conversion results and look up the specification for other special cases.

In-depth understanding of prototypes and prototype chains

The relationship between them

  • Constructor property prototype: points to the prototype object
  • The prototype object constructor property refers back to the constructor.
  • Each constructor generates an instance object with a proto property that points to the prototype object.

What is the prototype chain

As the name implies, it must be a chain, and since every object has a _proto_ attribute pointing to the prototype object, the prototype object also has a prototype object pointing to the prototype object until it points to NULL in the figure above, which does not reach the top of the prototype chain.

The relationship between Function and Object in the prototype chain

  • [^](#ref_1_0) or Object and Function are instances of the Function class. Function’s parent is Object. Object has no parent.

  • [^](#ref_2_0) indicates whether A is an instance of class B. If B has no Symbol. HasInstance interference. Tc39. Es/ecma262 / # se…

Object.__proto__===Function.prototype 
Function.__proto__===Function.prototype
Array.__proto__===Function.prototype
Function.prototype.__proto__===Object.prototype
Array.prototype.__proto__===Object.prototype

Function.prototype.__proto__===Object.prototype
Copy the code

Implement new

function newFunc(. args) {
 // Take the first args argument, the target constructor
 const constructor = args.shift(// Create an empty object that inherits from the constructorprototypeThe attribute // is the implementationobj.__proto__= = =constructor.prototype
 const obj = Object.create(constructor.prototype// The constructor returns the resultapply, will be inside the constructorthisPointing toobj
 const result = constructor.apply(obj, argsIf the result is the type of the object, it is returned, otherwise it is returnedobjobjectreturn (typeof result === 'object'&& result ! =null)?result : obj
}
Copy the code

The code above is not complicated, with a few key points:

  • Use object. create to convert obj’s__proto__Points to the prototype as a constructor
  • Use the apply method to point this inside the constructor to obj
  • When newFunc returns, the trinary operator is used to determine the return result

Implement inheritance in JavaScript

  • The most critical points of prototype chain implementation inheritance are:

Child.prototype = new Parent()

  • The main points of constructor implementation inheritance are:

function Child (args) {  Parent.call(this, args) }

  • The implementation of composite inheritance is basically available, and the key points are:
function Child (args1, args2) {
   // ...
   this.args2 = args2
   Parent.call(this, args1)
}
Child.prototype = new Parent()
Child.prototype.constrcutor = Child
Copy the code

The problem is that Child instances have Parent instance attributes. Because we execute the Parent constructor in the Child constructor. __proto__ also has the same Parent instance attribute, and __proto__ points to the same memory address for all Child instances.

Coust and let, heap and stack memory

Several schemes of digital deweighting

return Array.from(new Set(arr))

var arr=[1.2.13.1.2.1.2.1]
var newArr = [];
for(var i=0; i<arr.length; i++){if(newArr.indexOf(arr[i]) == -1){ newArr.push(arr[i]); }}console.log(newArr);
Copy the code
let newArr = arr.reduce((prev, cur) = > {
    prev.indexOf(cur) === -1 && prev.push(cur);
    return prev;
},[]);
console.log(newArr)
Copy the code

Why do microtasks execute earlier than macro tasks

  1. Macro tasks: setTimeout, setInterval, Ajax, DOM events
  2. Microtasks: Promise, async/await
  3. Microtasks are executed earlier than macro tasks

Why do microtasks execute earlier than macro tasks: Because of the different trigger times

  • Macro task: triggered after DOM rendering, as specified by the browser, called at render time
  • Microtasks: Triggered before DOM rendering, which is specified by ES6 syntax and invoked at compile time

Stack memory and heap memory

Why is there stack memory and heap memory? When we create an object in a program, the object is stored in the runtime data area for reuse (because objects are usually expensive to create), and this runtime data area is heap memory. Will not end with the method of objects in the heap memory and destruction, even after the method, the object may also be another reference variables referenced (method of parameter passing is common), then the object is not destroyed, only when there is no reference to an object variables refer to it, the system of garbage collection will check the recycling it.

Copy the code

Stack (operating system) : automatically allocated by the compiler to hold function parameter values, local variable values, etc. Its operating mode is similar to the stack stack data structure using the first-level cache, they are usually in the storage space is called call to complete the immediate release of heap (OS) : generally allocated by the programmer to release, if the programmer does not release, at the end of the program may be recycled by the OS, distribution is similar to the list. The heap is stored in a level 2 cache, and its lifetime is determined by the virtual machine’s garbage collection algorithm (objects are not recycled once orphaned). So these objects are called relatively slowly. Heap (data structure) : heap can be thought of as a tree, such as heap sort stack (data structure) : a lifO (last in, first out) data structure

Why can’t let be variable promoted

  • The reasons for the variable promotion in VAR are as followsfooWhen a function is executed, for variablesbThe declared or read value case is in its upper functionbarObtained in scope. At the same time, the “upper scope” can also spread out along the scope until it finds the global scope. As we can see, the search of the variable scope is a diffusion process, just like a chain linked by each link, which is progressive step by stepThe scope chainThe origin of the saying.
  • So there is a “dead zone” in the scope formed by the corresponding curly braces, starting at the beginning of the function and ending on the line of the related variable declaration.

coust

First, we declare a “constant” with const, essentially creating an immutable pointer to an area of memory. The content we give const “constant” is in this area.

Const A = 1 // const B = '1' // const C = true // 1} // Properties can actually change e.g. d.d1 = 2 const E = ['e1'] // item can actually change e.g. E[0] = 'e2'Copy the code

Thus, the underlying data type violates the principle that const constants cannot be modified as Pointers because their values are stored on the stack.

Reference data types, on the other hand, can change in value because modifying their properties does not affect the corresponding address change in the heap. However, in the following example, an error will be run if the reference address is actually changed:

Const D = {d1:1} const E = [' e1] D = {d1, 2} / / error E = [' e2 '] / / errorsCopy the code

Anti-shake and throttling

Image stabilization

Cancels the previous delayed call method each time the event is emitted

  debounce(fn) {
    let timeout = null
    return function () {
      clearTimeout(timeout)
      timeout = setTimeout(() = > {
        fn.apply(this.arguments)},500)}},Copy the code

The throttle

Each time an event is triggered, it determines whether there is currently a delay function waiting to be executed

  throttle(fn) {
    let canRun = true // Save a tag through a closure
    return function () {
      if(! canRun)return
      canRun = false
      setTimeout(() = > {
        fn.apply(this.arguments)
        canRun = true
      }, 500)}}Copy the code

Browser cache

We need to add md5 hash suffixes for static resources to avoid synchronization problems caused by resource updates.

ES6 arrow function with this pointing to

Developers are used to using arrow functions to interfere with this pointing, so conversely, “arrow functions are not appropriate when this pointing is not needed”. To sum up, there are:

  • Which scenarios are inappropriate to use ES6 arrow functions
  • This refers to all the problems at once

Closures and garbage collection mechanisms

Closure of the interview large rollover scene

Promise you don’t know

Understanding promise in depth

JS event bubbling and event proxy (delegate)

JS event bubbling and event proxy (delegate)

Tree Shaking Modularity

Tree shaking Modularity