JavaScript notes how to write JavaScript

Posted by mashamit on Mon, 17 Jan 2022 18:41:19 +0100

Three principles for writing JavaScript: each responsible component encapsulation process abstraction

Each party shall take its own responsibility

  • HTML/CSS/JavaScript each has its own responsibilities

    • HTML -> Structural ; CSS -> Presentational ; JavaScript -> Behavioral
  • Unnecessary direct manipulation of styles by JS should be avoided
  • You can use class to represent status
  • Zero JS scheme should be sought for pure presentation class interaction

Component encapsulation

A component is a unit that contains modules (HTML), styles (CSS) and functions (JS) extracted from a Web page. Good components have encapsulation, correctness, expansibility and reusability. The steps of implementing components: structure design, presentation effect, behavior design, and three refactorings: plug-in refactoring, template refactoring, and abstract refactoring.

  • Structural design: HTML
  • Presentation effect: CSS
  • Behavior design: JS

    • API (function), API design shall ensure atomic operation, single responsibility and flexibility.
    • Event (control flow), which uses custom events to decouple.
  • Plug in refactoring, i.e. decoupling

    • Extract control elements into plug-ins
    • The relationship between plug-ins and components is established through dependency injection
  • Templating reconstruction

    • Template HTML for easier extension
  • Abstract refactoring (component framework)

    • Abstract the general component model

Process abstraction

Process abstraction refers to some methods used to deal with local detail control. It is the basic application of functional programming.

  • Higher order function

    • Take function as parameter
    • Take function as return value
    • Often used in function decorators
//Zero order higher-order function, equivalent to direct call function
function HOF_0 (fn){
    return function(...args){
        return fn.apply(this.args);
    }
}
  • Construct the once high-order function. In order to enable the "execute only once" requirement (such as some asynchronous operations and one-time HTTP requests) to cover different event processing, we can separate this requirement by using closures. This process is called process abstraction.
function once ( fn ) {
    return function (...args){
        const res = fn.allpy (this.args);
        fn = null;
        return res;
    }
}
  • The anti shake function does not execute the function immediately when the event is triggered for the first time, but gives a period value. If the rolling event is not triggered again within the period value, the function will be executed. If the rolling event is triggered again within the period value, the current timing will be cancelled and the timing will be restarted

    const debounce = (fn, delay) => {
      let timer = null;  
      //With closures
      return function () {
          clearTimeout(timer);
          timer = setTimeout(fn, delay);
      }
    }
  • Throttling function is a function that is opened regularly like a control valve, that is, after the function is executed once, it will temporarily fail in a certain period of time, and then reactivate after this period of time. Effect: if a large number of the same events are triggered in a short time, after the function is executed once, the function will not work within the specified time period until it takes effect again.

    const myThrottle = (fn, delay) => {
      let flag = true;
      return function () {
          if (!flag) {
              return false;
          } else {
              flag = false;
              setTimeout(() => {
                  fn();
                  flag = true;
              }, delay);
          }
      }
    }
  • Why use higher order functions?

    • Reduce the number of non pure functions in the system and improve the testability and stability of the system.

Write JavaScript

Writing code should pay attention to

  • efficiency
  • style
  • Usage scenario
  • appointment
  • Design
    The specific code implementation depends on the scenario. Different scenarios focus on different points. For example, in some low-level scenarios, they may pay more attention to efficiency, and in multi person collaboration, they may pay more attention to conventions.

Determine whether it is a power of 4

  • General operation

    const isPowerOfFour = (num) => { 
      num = parseInt(num); 
      while(num > 1){ 
          if(num % 4) return false; 
          num /= 4; 
      } 
      return true;
    }
  • Optimized version 1, the binary number using the power of 4, the highest bit is 1, and the lower bit is an even number of 0

    const isPowerOfFour = (num) => {
      num = parseInt(num);
      return num > 0 &&
             (num & (num-1)) === 0 &&
             (num & 0XAAAAAAAA) === 0;
    }
  • Optimized version 2, using regular expressions
const isPowerOfFour = (num) => {
    num = parseInt(num).toString(2);
    return /^1(?:00)*$/.test(num);
}

Achieve traffic light switching effect

  • In version 1, a callback may occur using setTimeout

    const traffic = document.getElementById('traffic'); 
    (function reset(){ 
      traffic.className = 's1'; 
      setTimeout(function(){ 
          traffic.className = 's2'; 
          setTimeout(function(){ 
              traffic.className = 's3'; 
              setTimeout(function(){ 
                  traffic.className = 's4'; 
                  setTimeout(function (){ 
                      traffic.className = 's5'; 
                      setTimeout(reset,1000) 
                  },1000) 
              },1000) 
          },1000) 
      },1000) 
    })();
  • Optimized version, using async/await

    const traffic = document.getElementById('traffic'); 
    function wait(time){ 
      return new Promise(resolve => setTimeout(resolve,time)) 
    } 
    
    function setState(state){ 
      traffic.className = state;
    } 
    
    async function start(){ 
      while(1){ 
          setState('wait'); 
          await wait(1000); 
          setState('stop'); 
          await wait(3000); 
          setState('pass'); 
          await wait(3000);
      } 
    } 
    
    start();

shuffle algorithm

  • Error example
    It seems that you can shuffle cards correctly, but in fact, the probability of smaller cards in front is greater, and the probability of larger cards in the back is greater

    const cards = [0,1,2,3,4,5,6,7,8,9];
    const shuffle = (cards) => {
      return [...cards].sort(() => { Math.random() > 0.5 ? -1 : 1 });
    }
  • Correct example
const cards = [0,1,2,3,4,5,6,7,8,9]; 
function *draw(cards){ 
    const c = [...cards]; 
    for(let i = c.length ; i > 0 ; i--){ 
        const pIdx = Math.floor(Math.random() * i);
        [c[pIdx],c[i - 1]] = [c[i - 1],c[pIdx]]; 
        yield c[i - 1];
    } 
    return c; 
}

Bonus package problem

  • Version 1 is similar to cutting a cake. Continue to cut the largest one, and the results will be more average

    function generate(amount,count){ 
      let ret = [amount]; 
      while(count > 1){ 
          // Pick out the largest for segmentation 
          let cake = Math.max(...ret), 
          idx = ret.indexOf(cake), 
                part = 1 + Math.floor((cake / 2) * Math.random()), 
                rest = cake - part; 
          ret.splice(idx,1,part,rest); 
          count --; 
      } 
      return ret; 
    }
  • In version 2, the randomness is large, and there may be large red envelopes
function *draw(cards){ 
    const c = [...cards]; 
    for(let i = c.length ; i > 0 ; i --){ 
        const pIdx = Math.floor(Math.random()*i); 
        [c[pIdx],c[i-1]] = [c[i - 1],c[pIdx]]; 
        yield c[i-1] 
    } 
    return c;
} 

function generate(amount,count){ 
    if(count <= 1) return [amount]; 
    const cards = Array(amount - 1).fill(null).map((_,i) => i+1); 
    const pick = draw(cards); 
    const result = []; 
    for(let i = 0 ; i < count; i++){ 
        result.push(pick.next().value);
    } 
    result.sort((a,b)=>a-b); 
    for(let i = count - 1 ; i > 0 ; i--){ 
        result[i] = result[i] - result[i - 1];
    } 
    return result; 
}

Topics: Javascript Front-end