Sorted out the front end test questions, share with everyone to study together. If you have any questions, please point out!

directory

  • Handwritten new function
  • Handwritten instanceof
  • Handwritten call function
  • Handwritten Apply function
  • Handwritten bind
  • Handwriting Debounce anti – shake function
  • Handwritten throttle throttling function
  • Hand-written array object deduplicating
  • Handwriting array flattening
  • Handwritten deep copy

1. Write new functions by hand

What new does:

  • An empty object is created.
  • Empty objectprotoPoint to the prototype of the constructorprototype.
  • makethisPoint to the newly created object and execute the constructor.
  • The result of execution has a return value and is an object. Returns the result of execution, otherwise returns the newly created object.
// Create a new constructor -- a function for new
// Constructor is a special method used to assign initial values to object member variables when an object is created
function Cat(name){
  // This refers to the window, so we need to redirect this to itself to mount the property successfully
  this.name = name
  this.say = function() {
    console.log("my name is" + this.name); }}// Write the new function
function sd_new(fn,... arg){
  const obj = {};
  // Mount the constructor prototype to the new object
  Object.setPrototypeOf(obj, fn.prototype)
  // Point this to the new object and execute the constructor
  let result = fn.apply(obj, arg);
  return result instanceof Object ? result : obj
}

/ / verification
var cat = sd_new(Cat, "shamao")
cat.say();// my name is shamao
Copy the code

2. The handwritten instanceof

The advantages and disadvantages:

  • Advantages: Can distinguish Array, Object, and Function, suitable for judging custom class instance objects
  • Disadvantages: Number, Boolean, String Basic data types cannot be determined

Implementation steps:

  • The arguments passed in are instance L on the left, and constructor R on the right
  • Handles bounds, and returns false if you want to detect an object of primitive type
  • Take the prototype of the passed parameters, respectively
  • Check whether the left prototype is null, if null returns false; Return true if both archetypes are equal, otherwise continue with the left archetype.
function sd_instanceof(L,R){
    // Verify that if it is a basic data type, return false directly, because instanceof can only determine the reference type
  const baseType = ['string'.'number'.'boolean'.'undefined'.'symbol'];
  if(baseType.includes(typeof(L)) || L === null) { return false };
  
  let Lp = L.__proto__;
  let Rp = R.prototype; // The function has the prototype attribute
  
  while(true) {if(Lp === null) {return false;
      }
      if(Lp === Rp){
          return true; } Lp = Lp.__proto__; }}/ / test
const flag = sd_instanceof([], Array);
Copy the code

3. Write the call function

Implementation steps:

  • Processing boundaries:
    • Object does not exist, this refers to window;
  • Will “call function”Mount to theOn the FN property of the object to which this points.
  • Execute the fn function on “the object to which this points”, pass in the argument, and return the result.
Function.prototype.sd_call = function (context, ... args) {
    //obj does not point to window
    if(! context || context ===null) {
      context = window;
    }
    // Create a unique key value for the internal method name of the context we construct
    let fn = Symbol(a);// This refers to the function that calls call
    context[fn] = this;

    // Executing the function and returning the result is equivalent to calling itself as a method of the passed context
    returncontext[fn](... args); };/ / test
  var value = 2;
  var obj1 = {
    value: 1};function bar(name, age) {
    var myObj = {
      name: name,
      age: age,
      value: this.value,
    };
    console.log(this.value, myObj);
  }
  bar.sd_call(null); // print 2 {name: undefined, age: undefined, value: 2}
  bar.sd_call(obj1, 'tom'.'110'); {name: "top", age: "110", value: 1}
Copy the code

Write the Apply function by hand

Implementation steps:

  • In line with the call
  • As distinct from the form of parameters
Function.prototype.sd_apply = function (context, args) {
    //obj does not point to window
    if(! context || context ===null) {
      context = window;
    }
    // Create a unique key value for the internal method name of the context we construct
    let fn = Symbol(a);// This refers to the function that calls call
    context[fn] = this;

    // Executing the function and returning the result is equivalent to calling itself as a method of the passed context
    returncontext[fn](... args); };/ / test
  var value = 2;
  var obj1 = {
    value: 1};function bar(name, age) {
    var myObj = {
      name: name,
      age: age,
      value: this.value,
    };
    console.log(this.value, myObj);
  }
  bar.sd_apply(null[]);// print 2 {name: undefined, age: undefined, value: 2}
  bar.sd_apply(obj1, ['tom'.'110']); {name: "top", age: "110", value: 1}
Copy the code

5. Write bind

Function.prototype.sd_bind = function (context, ... args) {
    if(! context || context ===null) {
      context = window;
    }
    // Create a unique key value for the internal method name of the context we construct
    let fn = Symbol(a); context[fn] =this;
    let _this = this;
    // bind is a bit more complicated
    const result = function (. innerArgs) {
      // In the first case, if you use the new operator as a constructor after bind, instead of binding this passed in, you point this to the instantiated object
      // Since the new operator calls this to the result instance, which in turn inherits from _this, we can draw the following conclusions from our knowledge of the prototype chain
      // this.__proto__ === result.prototype //this instanceof result =>true
      // this.__proto__.__proto__ === result.prototype.__proto__ === _this.prototype; //this instanceof _this =>true
      if (this instanceof _this === true) {
        // This points to an instance of result
        this[fn] = _this;
        this[fn](... [...args, ...innerArgs]);// Es6 methods are used here to enable bind to support parameter merging
        delete this[fn];
      } else {
        It would be easy to change this to refer to the context passed in if it was just called as a normal functioncontext[fn](... [...args, ...innerArgs]);deletecontext[fn]; }};// If you bind to a constructor, you need to inherit the constructor prototype properties and methods
    // Implement inheritance by using object.create
    result.prototype = Object.create(this.prototype);
    return result;
  };
  function Person(name, age) {
    console.log(name); //' I am the name of the parameter passed in '
    console.log(age); //' I am the age passed in '
    console.log(this); // The constructor this points to the instance object
  }
  // The method to construct the prototype
  Person.prototype.say = function () {
    console.log(123);
  };

  // A normal function
  function normalFun(name, age) {
    console.log(name); //' I am the name of the parameter passed in '
    console.log(age); //' I am the age passed in '
    console.log(this); // The normal function this points to the first argument to the bind, which in our example is obj
    console.log(this.objName); //' I am the name of obj '
    console.log(this.objAge); //' I am an age from obj '
  }

  let obj = {
    objName: 'I'm the name that OBj passed in.'.objAge: 'I'm the age that OBj sent in.'};// Test as constructor call first
  // let bindFun = person.sd_bind (obj, 'I am the name of the parameter ');
  // let a = new bindFun(' I am an age');
  //   a.say(); //123

  // retest as a normal function call a;
  let bindFun = normalFun.sd_bind(obj, 'I'm the name that was passed in as a parameter');
  bindFun('I'm the age that the parameter is passed in.');
Copy the code

6. Handwritten Debounce anti-shake function

Function stabilization is to execute the callback n seconds after the event is triggered. If the event is triggered again in n seconds, the timer is reset.

function debounce(fn, wait) {
    let timer = null;
    return function () {
      if(timer ! =null) {
        clearTimeout(timer);
      }
      timer = setTimeout(() = > {
        fn();
      }, wait);
    };
  }
  / / test
  function handle() {
    console.log(Math.random());
  }
  // If the window size changes, handle is triggered
  window.addEventListener('resize', debounce(handle, 1000));
Copy the code

7. Handwritten throttle functions

When an event is triggered, only a certain period of time is specifiedOne callFunction. For example, send requests every once in a while while the page is scrolling

Implementation steps:

  • The argument passed is to execute the function fn and wait time wait.
  • Save the initial time now.
  • Returns a function that updates now to the current time if the wait time is exceeded.
function throttle(fn, wait, ... args) {
    var pre = Date.now();
    return function () {
      // The function may have input parameters
      var context = this;
      var now = Date.now();
      if (now - pre >= wait) {
        // Will execute the function this to the current scope
        fn.apply(context, args);
        pre = Date.now(); }}; }/ / test
  var name = 'mu';
  function handle(val) {
    console.log(val + this.name);
  }
  // Roll the mouse to trigger the handle
  window.addEventListener('scroll', throttle(handle, 1000.'4'));
Copy the code

8. Hand-write array objects for deduplication

Keys using map cannot be duplicated, removing items with the same attributes

function uniqBy(arr, key) {
    return [...new Map(arr.map((item) = > [item[key], item])).values()];
  }
  const list = [
    { id: 1.name: 'tom' },
    { id: 1.name: 'jey' },
    { id: 2.name: 'joy'},];console.log(uniqBy(list, 'id')); // [{id:1,name:"jey"},{id:2,name:"joy"}]
Copy the code

9. Handwriting array flattening

flat

let arr = [1.2[3.4], [5.6[7.8.9]]]
console.log(arr.flat(Infinity))//[1, 2, 3, 4, 5, 6, 7, 8, 9]
Copy the code

join/ split

console.log(arr.toString().split(",").map(Number))//[1, 2, 3, 4, 5, 6, 7, 8, 9] 
console.log(arr.join().split(",").map(Number))//[1, 2, 3, 4, 5, 6, 7, 8, 9]
Copy the code

Functional version

function flatter(arr) {
     if(! arr.length)return;
        while (arr.some((item) = > Array.isArray(item))) { arr = [].concat(... arr); }return arr;
 }
// console.log(flatter([1, 2, [1, [2, 3, [4, 5, [6]]]]]));
Copy the code

10. Deep copy by hand

A deep copy of an object is essentially a recursive method of deep cloning: iterating through the object and array until it contains all the basic data types, and then copying.

Simple version of

function deepCopy(obj){
    // Check if it is a simple data type,
    if(typeof obj == "object") {// Complex data types
        var result = obj.constructor == Array ? [] : {};
        for(let i in obj){
            result[i] = typeof obj[i] == "object"? deepCopy(obj[i]) : obj[i]; }}else {
        // Assign to simple data types directly ==
        var result = obj;
    }
    return result;
}
Copy the code

premium

function deepClone(obj, hash = new WeakMap(a)) {
  // If it is null or undefined, I will not copy it
  if (obj === null) return obj;

  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);

  // Find the constructor from the parent class stereotype, which points to the current class itself
  let cloneObj = new obj.constructor();

  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