preface

I recently found myself struggling with many JavaScript basics. In your spare time, tidy up the basics of JavaScript.

To the chase

The data type

There are 8 data types in JavaScript, 7 of which are basic data types: undefined, NULL, Boolean, Number, String, Symbol, BigInt (new in ES10). There is also a reference type Object (which includes Function, Date, Array, and so on). Primitive data types store their values directly in memory. Reference data types store Pointers to their addresses in memory

Js built-in object

Global objects, or standard built-in objects, are not to be confused with "global objects". When I say global objects, I mean objects in the global scope. Other objects in the global scope can be created by the user's script or provided by the host program. Class (1) value properties of standard built-in objects. These global properties return a simple value that has no properties or methods of its own. Such as Infinity, NaN, undefined, null literal (2) function properties, the global function can be called directly, do not need to specify the object when the call, the result will be directly returned to the caller after execution. Such as eval(), parseFloat(), parseInt(), etc. (3) Basic objects, which are the basis for defining or using other objects. Basic objects include generic objects, function objects, and error objects. For example, Object, Function, Boolean, Symbol, Error, etc. (4) number and date objects used to represent numbers, dates, and objects that perform mathematical calculations. Examples are Number, Math, Date (5) strings, objects that represent and manipulate strings. For example, String, RegExp (6) indexable collection objects, which represent collections of data sorted by index value, including arrays and type arrays, and objects with array like structures. Array (7), for example, uses collection objects that use keys when storing data, and supports iterating over elements in the order they are inserted. For example, Map, Set, WeakMap, WeakSet (8) vector Set, data in SIMD vector Set will be organized into a data sequence. For example, SIMD, etc. (9) structured data, these objects are used to represent and manipulate structured buffer data, or data encoded using JSON. (10) Controls abstract objects such as Promise, Generator, etc. (11) reflects internationalization such as Reflect, Proxy, etc. (12) Adds ECMAScript objects to support multilingual processing. For example, Intl and intl. Collator (13) WebAssembly (14) OthersCopy the code

Truly and Services variable

Variables whose Boolean(variables) === true become truly variables; A variable that is Boolean(variable) === false becomes a Service variable;

What is the difference between the TRULY variable and the Service variable?

The following are SERVICES variables and beyond that are TRULY variables:

  • Boolean(0) === false
  • Boolean(NaN) === false
  • Boolean(”) === false
  • Boolean(null) === false
  • Boolean(undefined) === false
  • Boolean(false) === false

So Boolean({}) === true; !!!!! {} === true so Boolean([]) === true;

Arrow function

  • This of the arrow function always points to this of the parent scope. It’s not called this. A normal function on a call determines that this refers to the object on which it was called.
  • Arrow functions cannot be constructors. You cannot use new(). Partly because this points to the problem. The other thing is that arrow functions don’t have Prototype
  • Arrow functions have no arguments, caller, callee
  • When the arrow function is called through call and apply, the this pointer does not change. Only arguments are passed in
  • Arrow functions have no prototype

Parasitic combinatorial inheritance

Parasitic combinatorial inheritance inherits properties by borrowing constructors and inherits methods in the form of stereotype chains.

function Person(name) {
 this.name = name;
}

Person.prototype.sayName = function() {
 console.log("My name is " + this.name + ".");
};

function Student(name, grade) {
 Person.call(this, name);
 this.grade = grade;
}

Student.prototype = Object.create(Person.prototype);
Student.prototype.constructor = Student;

Student.prototype.sayMyGrade = function() {
 console.log("My grade is " + this.grade + ".");
};
Copy the code

Differences between ES6 modules and CommonJS modules

  • The CommonJS module prints a copy of the value, the ES6 module prints a reference to the value. The CommonJS module outputs a copy of the value, meaning that once a value is output, changes within the module do not affect that value. ES6 modules operate differently from CommonJS. When the JS engine statically analyzes a script, it generates a read-only reference to the module load command import. When the script is actually executed, it will be evaluated in the loaded module based on the read-only reference.
  • The CommonJS module is run time loaded, and the ES6 module is compile time output interface. A CommonJS module is an object, which loads the entire module on input, generates an object, and then reads methods from that object. This loading is called “runtime loading.” An ES6 module is not an object, and its external interface is a static definition that is generated during the code static parsing phase.

Deep copy (circular references with special objects such as dates and regees in mind)

function deepClone(obj, hash = new WeakMap(a)) {
  if (obj == null) return obj; // If it is null or undefined, I will not copy it
  if (obj instanceof Date) return new Date(obj);
  if (obj instanceof RegExp) return new RegExp(obj);
  // May be objects or ordinary values if functions do not need deep copies
  if (typeofobj ! = ="object") return obj;
  // Make a deep copy of an object
  if (hash.get(obj)) return hash.get(obj);
  let cloneObj = new obj.constructor();
  // Find the constructor from the parent class stereotype, which points to the current class itself
  hash.set(obj, cloneObj);
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      // Implement a recursive copycloneObj[key] = deepClone(obj[key], hash); }}return cloneObj;
}
let obj = { name: 1.address: { x: 100}}; obj.o = obj;// The object has a circular reference
let d = deepClone(obj);
obj.address.x = 200;
console.log(d);
Copy the code

Parse (json.stringfy (obj)) is often used in our work, but there are some problems with using this method:

  • Fields whose value is undefined are ignored
  • Fields with values of type symbol are ignored
  • Fields whose values are functions are ignored
  • An error is reported for objects that cannot resolve a circular reference

Image stabilization function

function debounce(func, wait = 1000){
   let timer = null
   return function(. params){
       clearTimeout(timer)
       timer = setTimeout(() = >{
           timer = null
           func.call(this. params) },wait) } }const a = debounce(function(flag){
   console.log(flag)
},1000)
a(1)
a(2)
a(3)
a(4)
Copy the code

Throttling function

Use Date().now

function throttleWithDate(func, wait = 1000, immediate){
  letlimited = ! immediate;// Throttle flag
  let timer = null;
  let start = Date.now();
  return function (. args) {
    const current = Date.now();
    limited = limited && current - start < wait;
    if (limited) {
      clearTimeout(timer);
      timer = setTimeout(() = > {
        limited = true;
        func.apply(this, args);
        start = Date.now();
      }, wait);
    }else {
      limited = true;
      func.apply(this, args);
      start = Date.now(); }}; }Copy the code

Use setTimeout

function throttleWithTimeout(func, wait = 1000, immediate){
  let timer = null
  return function (. params){
    if(timer){ return }
    if(immediate){
      func.apply(this, params)
      immediate = false
    }else{
      timer = setTimeout(() = >{
        timer = null
        immediate = false
        func.apply(this, params)
      }, wait)
    }
  }
}

Copy the code

Array flattening using reduce

const arr = [123[123.12432[12321.1232123.12321421[1232123].12321[12321], [12321]],12321].1232123]
function myFlat (arr){
    return arr.reduce((pre, cur) = > {
        return pre.concat(Array.isArray(cur) ? myFlat(cur) : cur); } []); }console.log(myFlat(arr))
// [123, 123, 12432, 12321, 1232123, 12321421, 1232123, 12321, 12321, 12321, 1232123]
Copy the code

To realize the call

Function.prototype._call = function (context, ... args){
    // Context is window when null, undefined, and not passed
    context = context == null ? window : context;
    Context must be an object type
    let contextType = typeof context;
    if (!/^(object|function)$/i.test(contextType)) {
        // context = new context.constructor(context); // does not apply to Symbol/BigInt
        context = Object(context);
    }
  
    let result;
    context['fn'] = this; // Take a function as a member value of an object
    result = context['fn'] (... args);// Execute the function, in which case this is context
    delete context['fn']; // Delete the member attributes after setting them
    return result;
}
Copy the code

To realize the apply

Function.prototype._apply = function (context, args){
    // Context is window when null, undefined, and not passed
    context = context == null ? window : context;
    Context must be an object type
    let contextType = typeof context;
    if (!/^(object|function)$/i.test(contextType)) {
        // context = new context.constructor(context); // does not apply to Symbol/BigInt
        context = Object(context);
    }
  
    let result;
    context['fn'] = this; // Take a function as a member value of an object
    result = context['fn'] (... args);// Execute the function, in which case this is context
    delete context['fn']; // Delete the member attributes after setting them
    return result;
}
Copy the code

To realize the bind

Function.prototype._bind = function(context, ... params){
  if(typeof this! = ='function') {throw new Error('Binding must be a function')}const self = this
  // Declare a func to determine whether the bound function is called as constructor new
  const func = function(){}

  const resFunction = function(. args){
    // If the binding function is used as a constructor to new an object.
    // new creates a new empty object, obj
    // then add obj.__proto__ === constructor (this is the binding function resFunction).prototype
    // The binding function returned by the penultimate line of code is an instance of func
    / / so. When a binding function is used as a constructor to new an object, this must be an instance of func.
    // To make the instantiated object this point correctly. This is the generated empty object obj

    // When the binding function executes itself.
    // This refers to window. We bind the context.
    return self.apply(this instanceof func? this: context, params.concat(... args)) }if(this.prototype){
    func.prototype = this.prototype
  }
  resFunction.prototype = new func()
  return resFunction
}

function func(name) {
  this.name = name;
}
var obj = {};
var func1 = func._bind(obj);
func1('Jack');
console.log(obj.name);  // Jack
var obj1 = new func1('Alice');
console.log(obj.name);  // Jack
console.log(obj1.name); // Alice
Copy the code

To realize the map

Array.prototype._map = function(callback, context){
  const arr = this;
  const res = []
  for(let i = 0; i< arr.length; i++){
    res.push(callback.call(context, arr[i],i ,arr))
  }
  return res
}
Copy the code

Here’s an interesting interview question

// Return what?
['100'.'200'.'300'.'400'].map(Number) 
// Return what?
['100'.'200'.'300'.'400'].map(parseInt) 
// Why?
Copy the code

To realize the filter

Array.prototype._filter = function(callback, context){
  const arr = this;
  const res = []
  for(let i = 0 ; i< arr.length; i++){
    if(callback.call(context,arr[i], i ,arr)){
      res.push(arr[i])
    }
  }
  return res
}
Copy the code

To realize the reduce

Array.prototype._reduce = function(callback, inital){
  const arr = this;
  let prev = inital
  let initalKey= 0
  if(! inital){for(let i = 0; i<arr.length; i++){if(arr[i]){
        initalKey = i
        prev = arr[i]
        break}}}for(let i = initalKey; i< arr.length; i++){
    prev = callback.call(undefined, prev, arr[i], i, arr)
  }
  return prev
}
Copy the code

Realize the promise. All

Promise._all = function(promiseList){
  return new Promise((resolve, reject) = > {
    let flag = 0
    const result = []
    promiseList.forEach(promise= > {
      promise.then(res= > {
        result.push(res)
        flag++
        if(flag === promiseList.length){
          resolve(result)
        }
      }).catch(err= > {
        reject(err)
      })
    })
  })
}
Copy the code

Here’s an interesting interview question that asks for a handwritten promise.all with a concurrency of 3

Promise._allWithLimit3 = function(promiseList){
  return new Promise((resolve, reject) = >{
    const len = promiseList.length
    const taskList = promiseList.splice(0.3)
    const otherList = promiseList.splice(0)
    const result = []
    let total = 0;
    taskList.forEach(promise= >{
      singleTaskRun(promise)
    })
    function singleTaskRun (promise){
      promise.then(res= >{
        result.push(res)
        total++
        if(otherList.length > 0) {const task = otherList.shift()
          singleTaskRun(task)
        } 
        if(total === len){
          resolve(result)
        }
      }).catch(err= >{
        reject(err)
      })
    }
  })
}
// Test the code
let p1 = new Promise((resolve, reject) = > {
  setTimeout(() = > {
    resolve("1");
  }, 1000);
});
let p2 = new Promise((resolve, reject) = > {
  setTimeout(() = > {
    resolve("2");
  }, 1500);
});
let p3 = new Promise((resolve, reject) = > {
  setTimeout(() = > {
    resolve("3");
  }, 2000);
});
let p4 = new Promise((resolve, reject) = > {
  setTimeout(() = > {
    resolve("4");
  }, 2500);
});
let p5 = new Promise((resolve, reject) = > {
  setTimeout(() = > {
    resolve("5");
  }, 5000);
});

let all = Promise._allWithLimit3([p1, p3, p2, p4, p5]);
all.then(
  data= > {
    console.log("data", data); 
  }
).catch(err= > {
  console.log('err',err)
})
Copy the code

Follow public account

Like the students can pay attention to the public account