This is the 14th day of my participation in the August More Text Challenge. For details, see:August is more challenging

Can’t hold it. Can’t hold it

Ah ~ ~ ~ ~ ~ ~

Last night wrote more than 3 o ‘clock in the morning, this morning and continue to work, and continue to write after work, 555555

Tanabata so over T_T, really can’t, do not want to write hydrology, time is in a hurry, can only squeeze themselves, while young can squeeze

It’s only 14 days. There are 17 more days left in August, which means there are 17 more to write before you reach your August goal

Depend!

Insist, come on ~~!!

Have a goal can not give up!!

This article has a lot of code, and most of the instructions are in the comments

Parsing URL parameters

It takes the parameters in the URL and turns them into objects

function getUrlParams(url){
  let reg = /([^?&=]+)=([^?&=]+)/g
  let obj = { }
  url.replace(reg, function(){
      obj[arguments[1]] = arguments[2]})return obj
}
let url = 'https://www.junjin.cn?a=1&b=2'
console.log(getUrlParams(url)) // { a: 1, b: 2 }
Copy the code

call

Change this to something that can take more than one parameter

Function.prototype.myCall = function(ctx) {
  ctx = ctx || window // ctx 就是 obj
  let fn = Symbol()
  ctx[fn] = this // this 就是 foo
  letresult = ctx[fn](... arguments)delete ctx[fn]
  return result
}
let obj = { name: MuHua}function foo(){ return this.name }
// foo foo foo foo foo foo foo foo
console.log( foo.myCall(obj) ) / / MuHua
Copy the code

Use Symbol because it is unique and avoid having the same name as the property in OBj

The idea is to add foo to obj, execute foo to get the return value, and delete foo from obj

apply

The same principle applies, except that apply accepts an array as the second argument and does not support the third argument

Function.prototype.myApply = function(ctx) {
  ctx = ctx || window
  let fn = Symbol()
  ctx[fn] = this
  let result
  if (arguments[1]) { result = ctx[fn](... arguments[1])}else {
  result = ctx[fn]()
  }
  delete ctx[fn]
  return result
}
Copy the code

bind

Function.prototype.myBind = function (ctx) {
  const self = this
  const fn = function(){}
  const bind = function(){
    const _this = this instanceof fn ? this : ctx
    return self.apply(_this, [...args, ...arguments])
  }
  fn.prototype = this.prototype
  bind.prototype = new fn()
  return bind
}
Copy the code

Bind does not execute immediately; it returns a function

  • Functions can be executed directly and pass parameters, such asfoo.myBind(obj, 1)(2, 3), so you need to[ ...args, ...arguments ]Consolidation parameters
  • The function can also worknew“, so judge the prototypethis instanceof fn

Then implement prototype inheritance, if you don’t know much about prototypes, please go to my last article to help the big factory, JavaScript front end summary

The difference between call, apply, and bind

  • Can be changedthisPoint to the
  • The call and will applyExecuted immediatelyInstead, bind returns a function
  • Call and bind can be acceptedMultiple parameters.applyI can only accept two. The second one isAn array of
  • The bind parameter can be passed multiple times

instanceof

Note in the comment, take two arguments and determine if the second argument is on the prototype chain of the first argument

function myInstanceof(left, right) {
  // Get the prototype of the instance object, which is left.__proto__
  let left = Object.getPrototypeOf(left)
  // Get the prototype of the constructor
  let prototype = right.prototype
  // Determine if the constructor stereotype is in the instance stereotype chain
  while (true) {
    // The prototype chain is null
    if (left === null) return false
    if (prototype === left) return true
    // If you don't find it, take the upper layer and continue the cycle
    left = Object.getPrototypeOf(left)
  }
}
Copy the code

Array to heavy

Personally, I like it very much

// A sample array
let arr = [1.1."1"."1".true.true."true", {}, {}, "{}".null.null.undefined.undefined]

/ / method
let unique1 = Array.from(new Set(arr))
console.log(unique1) // [1, "1", true, "true", {}, {}, "{}", null, undefined]

/ / method 2
let unique2 = arr= > {
  let map = new Map(a)// Or use an empty object let obj = {} to make use of the property of the object that cannot be repeated
  let brr = []
  arr.forEach( item= > {
    if(! map.has(item)){// If it is an object, judge! obj[item]
      map.set(item, true) Obj [item] = true if it is an object
      brr.push(item)
    }
  })
  return brr
}
console.log(unique2(arr)) // [1, "1", true, "true", {}, {}, "{}", null, undefined]

/ / method 3
let unique3 = arr= > {
  let brr = []
  arr.forEach(item= > {
    // Use indexOf to return whether the array contains any value
    if(brr.indexOf(item) === -1) brr.push(item)
    Return false if the array contains a value. Return true if it does
    if(! brr.includes(item)) brr.push(item) })return brr
}
console.log(unique3(arr)) // [1, "1", true, "true", {}, {}, "{}", null, undefined]

4 / / method
let unique4 = arr= > {
  // Use filter to return the set that meets the criteria
  let brr = arr.filter((item, index) = > {
    return arr.indexOf(item) === index
  })
  return brr
}
console.log(unique4(arr)) // [1, "1", true, "true", {}, {}, "{}", null, undefined]
Copy the code

The above method cannot de-iterate a reference type unless it is the same as a pointer, which can be de-iterated, such as in the following case

let crr = []
let arr = [crr,crr]
Copy the code

Array flattening

That’s turning a multidimensional array into a one-dimensional array

// A sample array
let arr = [1[2[3[4[5]]]]]

/ / method
// Flat () by default flattens one layer of nested arrays
// Infinity is infinite. It will level you no matter how many layers are nested
let brr1 = arr.flat(Infinity)
console.log(brr1) // [1, 2, 3, 4, 5]

/ / method 2
// Convert to a string, remove the "[" and"] "from the string, and convert the string back to an array
let brr2 = JSON.parse( "[" + JSON.stringify(arr).replace(/\[|\]/g."") + "]")
console.log(brr2) // [1, 2, 3, 4, 5]

/ / method 3
let brr3 = arr= > {
  // Use recursion. You can also use the for loop to add recursion
  // Reduce accumulators, which are loops in nature,
  // cur is the current value of the loop, equivalent to arr[I], pre is the previous value, equivalent to arr[i-1] in the loop
  let crr = arr.reduce((pre, cur) = > {
    return pre.concat(Array.isArray(cur) ? brr3(cur) : cur);
  }, [])
  return crr
}
console.log(brr3(arr)) // [1, 2, 3, 4, 5]
Copy the code

Image stabilization

It is not executed in the case of consecutive clicks, but only after the specified number of seconds have elapsed since the last click

Application scenarios: Click the button, input box fuzzy query, word association, etc

function debounce(fn, wait) {
  let timeout = null
  return function(){
    // Stop the delayed task at each click
    if(timeout ! = =null) clearTimeout(timeout)
    // Otherwise, the deferred task is enabled
    timeout = setTimeout(fn, wait)
  }
}
function sayDebounce() {
  console.log("Shake off success!")
}
btn.addEventListener("click", debounce(sayDebounce,1000))
Copy the code

The throttle

Frequent triggers, such as scrolling or continuous clicking, are performed only once in a specified interval

Application scenarios: Click buttons, listen to scroll bars, lazy loading, etc

// In scenario 1, if you click continuously, wait every second
function throttle(fn, wait) {
  let bool = true
  return function() {
    if(! bool)return
    bool = false
    setTimeout(() = > {
      // fn() // this points to window
      fn.call(this.arguments) // in fn, this refers to BTN
      btn = true
    }, wait)
  }
}
// In scenario 2, the first click is executed immediately and then every second after wait
function throttle(fn, wait) {
  let date = Date.now()
  return function() {
    let now = Date.now()
    // Compare the current time minus the time of the last click to the time of the pass
    if (now - date > wait) {
      fn.call(this.arguments)
      date = now
    }
  }
}
function sayThrottle() {
  console.log("Throttling success!")
}
btn.addEventListener("click", throttle(sayThrottle,1000))
Copy the code

new

function myNew(fn,... args){
  // Not a function can't be new
  if(typeoffn ! = ="function") {throw new Error('TypeError')}// Create an object that inherits the fn prototype
  const newObj = Object.create(fn.prototype);
  // Bind fn's this to the new object, inherit its properties, and get the return result
  const result = fn.apply(newObj, args);
  // Return the result based on the type of the result object
  return result && (typeof result === "object" || typeof result == "function")? result : newObj; }Copy the code

Object.create

function createObj(obj){
  function Fn(){}
  Fn.prototype = obj
  return new Fn()
}
Copy the code

Create an empty object and modify the stereotype, which is nothing to say, but usually you pass a null in, so that you don’t create an object that doesn’t have a stereotype that’s contaminated by the stereotype, or you pass the stereotype of the object that you want to inherit

Es5 inheritance

// Create a superclass
function Parent(){}
Parent.prototype.getName = function(){ return 'MuHua' }
/ / subclass
function Child(){}

/ / way
Child.prototype = Object.create(Parent.prototype)
Child.prototype.constructor = Child // re-specify constructor
2 / / way
Child.prototype = ObjectThe create (Parent. Prototype, {constructor: {value: Child,
    writable: true.// Attribute can be modified
    enumerable: true./ / attributes can be enumerated (ergodicity), for example, in the for/in the Object. The keys/JSON stringify
    configurable: true.// Attribute can modify the attribute description object and can delete}})console.log(new Child().getName) / / MuHua
Copy the code

There are many ways of ES5 inheritance, such as prototype chain inheritance, combination inheritance, parasitic inheritance… Wait, it’s enough to know one type of interview

Es6 inheritance

// Create a superclass
class Parent(a){
  constructor(props){
    this.name = 'MuHua'}}// Create a subclass that inherits from the parent class
class Child extends Parent{
  // Props is an inherited attribute, myAttr is its own attribute
  constructor(props, myAttr){
    // Call the constructor of the superclass, which is equivalent to getting the reference to this of the superclass
    super(props)
  }
}
console.log(new Child().name) / / MuHua
Copy the code

Deep copy

// Write a generic traversal with while
function myEach(array, iteratee) {
    let index = -1;
    const length = array.length;
    while (++index < length) {
        iteratee(array[index], index);
    }
    return array;
}
function myClone(target, map = new WeakMap(a)){
    // Reference type to continue deep copy
    if (target instanceof Object) {
        const isArray = Array.isArray(target)
        // Clone the object and array types
        let cloneTarget = isArray ? [] : {} 
        
        // Prevent circular references
        if (map.get(target)) {
            // If there is a copy, return it directly
            return map.get(target) 
        }
        // Store the copy record without it
        map.set(target,cloneTarget) 
        
        // If it is an object, take out the corresponding key set and return it as an array
        const keys = isArray ? undefined : Object.keys(target)
        // value is the key of an object or the value of an array
        myEach(keys || target, (value, key) = > { 
            if (keys) {
                // If it is an object, replace the subscript with value
                key = value 
            }
            / / recursion
            cloneTarget[key] = myClone(target[key], map) 
        })
        return cloneTarget
    } else {
        return target
    }
}
Copy the code

Getting the data type

function getType(value) {
  if (value === null) {
    return value + ""
  }
  if (typeof value === "object") {
    // Array, object, null are all objects in typeof, so we need to handle {} as an example
    let valueClass = Object.prototype.toString.call(value) // [object, object]
    let type = valueClass.split("") [1].split("") ["O", "b", "j", "e", "c", "t", "]]
    type.pop() ["O", "b", "j", "e", "c", "t"]
    return type.join("").toLowerCase() // object
  } else {
    return typeofvalue; }}console.log( getType(1))// number
console.log( getType("1"))// string
console.log( getType(null))// null
console.log( getType(undefined))// undefined 
console.log( getType({}) ) // object
console.log( getType(function(){}))// function 
Copy the code

The function is curialized

Curilization functions are one of the higher-order functions. The benefits are mainly reuse and delayed execution of parameters, but the performance is not as good. You have to create arrays to store parameters, you have to create closures, and accessing argements is a little slower than accessing named parameters

Add (1)(2)(3) (1)(2, 3, 4)(5)(); add(1)(2, 3, 4)(5)(); add(2, 3, 4)(5)()

// The parameters passed in each call are accumulated
function reduce (. args) {
    return args.reduce((a, b) = > a + b)
}
function currying (fn) {
  // Store the parameters of each call
  let args = []
  return function temp (. newArgs) {
    if (newArgs.length) {
      // If there are arguments, merge them and return itself
      args = [ ...args, ...newArgs ]
      return temp
    } else {
      // Perform the cumulative result operation and return the result
      let val = fn.apply(this, args)
      args = [] // Make sure it is cleared when called again
      return val
    }
  }
}
let add = currying(reduce)
console.log(add(1) (2.3.4) (5) ())/ / 15
console.log(add(1) (2.3) (4.5) ())/ / 15
Copy the code

AJAX

// This is the structure for calling the following function
myAjax({
  type: "get".url: "https://xxx".data: { name: "MuHua".age:18 },
  dataType: "json".async: true.success:function(data){
    console.log(data);
  },
  error:function(){
    alert('error'); }})// Define a method that converts {name: "mu ", age:18} to name= mu &age=18
function fn(data){
  let arr = []
  for(let i in data){
    arr.push( i+'='+data[i])
  }
  return arr.join('&')}// The following is the function that implements the above calls and passes
function myAjax(options){
  let xhr = null
  let str = fn(options.data)
  / / create the XHR
  if(window.XMLHttpRequest){
    xhr = new XMLHttpRequest()
  }else{
    xhr = new ActiveXObject('Microsoft,XMLHTTP')}// Only get and POST are configured
  if(options.type === 'get'&& options.data ! = =undefined) {// Create the HTTP request
    xhr.open(options.type, options.url+'? '+str, options.async || true)
    // Send the request
    xhr.send(null)}else if(options.type === 'post'&& options.data ! = =undefined){
    xhr.open(options.type, options.url, options.async || true)
    // Set the request header
    xhr.setRequestHeaders('Content-type'.'application/x-www-form-urlencoede')
    xhr.send(str)
  }else{
    xhr.open(options.type, options.url, options.async || true)
    xhr.send(null)}// Listening status
  xhr.onreadystatechange = function(){
    if(xhr.readyState === 4 && xhr.status === 200) {let res = xhr.responseText
      try{
        if(options.success === undefined) {return xhr.responseText
        }else if(typeof res === 'object'){
          options.success(res)
        }else if(options.dataType === 'json'){
          options.success(JSON.parse(res))
        }else{
          throw new Error()}}catch(e){
        if(options.error ! = =undefined){
          options.error()
          throw new Error()}else{
          throw new Error()}}}}}Copy the code

Promise

class MyPromise {
  constructor(fn){
    // Store the reslove callback list
    this.callbacks = []
    const resolve = (value) = > {
      this.data = value // Return the value to the.then
      while(this.callbacks.length) {
        let cb = this.callbacks.shift()
        cb(value)
      }
    }
    fn(resolve)
  }
  then(onResolvedCallback) {
    return new MyPromise((resolve) = > {
      this.callbacks.push(() = > {
        const res = onResolvedCallback(this.data)
        if (res instanceof MyPromise) {
          res.then(resolve)
        } else {
          resolve(res)
        }
      })
    })
  }
}
// This is the test case
new MyPromise((resolve) = > {
  setTimeout(() = > {
    resolve(1)},1000)
}).then((res) = > {
    console.log(res)
    return new MyPromise((resolve) = > {
      setTimeout(() = > {
        resolve(2)},1000)
    })
}).then(res= >{console.log(res)})
Copy the code

The full Promise is simply too long, much, much longer than AJAX, so I implemented a minimalist version with only resolve and then methods and unlimited.then

Promise.all

Promise.all can package multiple Promise instances into a new Promise instance. An array of Promise objects is passed in. On success, an array of results is returned in the same order as the object was passed in. On failure, the initial value in the reject state is returned

Promise.all is the perfect solution for situations where you need to send multiple requests simultaneously and return results in sequence

MyPromise.all = function (promisesList) {
  let arr = []
  return new MyPromise((resolve, reject) = > {
    if(! promisesList.length) resolve([])// Loop directly and execute the passed promise simultaneously
    for (const promise of promisesList) {
      promise.then((res) = > {
        // Save the returned result
        arr.push(res)
        if (arr.length === promisesList.length) {
          // Return the result set at the end of the execution
          resolve(arr)
        }
      }, reject)
    }
  })
}
Copy the code

Promise.race

The pass argument is exactly the same as all above, passing in an array of Promise instances and then executing them all at the same time. The first one that finishes is returned with only one result

MyPromise.race = function(promisesList) {
  return new MyPromise((resolve, reject) = > {
    // Loop directly and execute the passed promise simultaneously
    for (const promise of promisesList) {
      // Return to the outside directly, so there is only one, depending on which is fast
      promise.then(resolve, reject)
    }
  })
}
Copy the code

Bidirectional data binding

let obj = {}
let input = document.getElementById('input')
let box = document.getElementById('box')
// Data hijacking
Object.defineProperty(obj, 'text', {
  configurable: true.enumerable: true.get() {
    // Get the data directly
    console.log('Got the data')},set(newVal) {
    // Modify the data to re-assign the value
    console.log('Data updated')
    input.value = newVal
    box.innerHTML = newVal
  }
})
// Input listen
input.addEventListener('keyup'.function(e) {
  obj.text = e.target.value
})
Copy the code

routing

// Simple hash routing
class myRoute{
  constructor(){
    // Route stores objects
    this.routes = {}
    / / the current hash
    this.currentHash = ' '
    // Bind this to prevent this pointing from changing when listening
    this.freshRoute = this.freshRoute.bind(this)
    / / to monitor
    window.addEventListener('load'.this.freshRoute, false)
    window.addEventListener('hashchange'.this.freshRoute, false)}/ / store
  storeRoute (path, cb) {
    this.routes[path] = cb || function () {}}/ / update
  freshRoute () {
    this.currentHash = location.hash.slice(1) | |'/'
    this.routes[this.currentHash]()
  }
}
Copy the code

conclusion

Praise support, hand stay fragrance, and have glory yan

Thank you for seeing this!