前端之路 (The Road to a Front-end Developer)

website·Indexed 29 days ago

https://mzhujihui.github.io

A comprehensive guide for front-end developers covering JavaScript fundamentals, including data types, inheritance patterns, and sorting algorithms, as well as development norms, Git and GitHub usage, and various front-end utility tools.

Tokens
2.5K
Snippets
10
Records
17
Agent score
75%

What's inside 前端之路

  1. Understand sorting stability and in-place sorting

    Two key concepts in sorting algorithms:

    • Stability: A sorting algorithm is stable if it preserves the relative order of elements with equal values.
    • In-place Sorting: A sorting algorithm is considered in-place if its space complexity is O(1).
  2. Follow JavaScript and CSS coding standards

    The project adheres to the Airbnb JavaScript Style Guide for JavaScript development and the BEM (Block Element Modifier) methodology for CSS naming and structure.
  3. Identify data types in JavaScript

    There are several ways to determine the type of a value in JavaScript, depending on whether you are checking for a primitive or a specific object instance:

    • typeof: Used for basic type checking (e.g., checking if a value is a string or number).
    • instanceof: Used to check if an object is an instance of a specific class or constructor.
    • Object.prototype.toString: Used for more precise type detection of object classes.
    • isXXX methods: Specialized utility methods such as Array.isArray() for checking if a value is an array.
  4. Configure Git commit messages with Conventional Commits

    Commit messages must follow the @commitlint/config-conventional specification.

    Key workflow details:

    • Use the commitizen tool to assist in writing standardized commit messages.
    • Commits typed as fix or feat are used to automatically generate the changelog.
    • A pre-commit hook is active; you must resolve all ESLint errors before a commit can be successfully pushed.
  5. Manage Git branches using Git Flow

    The main repository follows the Git Flow branching model. When creating new components or contributing features, branches should be checked out from the develop branch. Feature branches should follow the naming convention feature/<component-name> (e.g., feature/button).
  6. Implement Insertion Sort in JavaScript

    Insertion Sort builds the final sorted array one item at a time by taking an element from the unsorted part and inserting it into its correct position within the sorted part.

    • Time Complexity: Worst/Average: O(n²), Best: O(n)
    • Space Complexity: O(1)
    • Stability: Stable
    • Usage Note: Highly efficient for small data sets or nearly sorted arrays. The V8 engine uses insertion sort for arrays with length ≤ 10.
    const insertionSort = (arr) => {
      const a = [...arr]
      if (a.length <= 1) return a
      for (let i = 1; i < a.length; i++) {
          const temp = a[i]
          let j = i - 1
          // Shift elements to the right to create space for temp
          for (j; j >= 0; j--) {
              if (a[j] > temp) {
                  a[j + 1] = a[j]
              } else {
                  break
              }
          }
          a[j + 1] = temp
      }
      return a
    }
  7. Implement Parasitic Combination Inheritance

    This is the most optimized pattern. It uses a borrowed constructor for instance properties and a parasitic approach (Object.create) to inherit the prototype without executing the supertype constructor twice.

    Pros:

    1. Supertype is only called once, avoiding unnecessary properties on the prototype.
    2. Maintains the prototype chain, allowing instanceof and isPrototypeOf() to work correctly.
    function inheritPrototype(subType, superType){
        // Create a copy of the supertype prototype
        var prototype = Object.create(superType.prototype)
        // Restore the constructor property
        prototype.constructor = subType
        // Assign the new prototype to the subtype
        subType.prototype = prototype                     
    }
    
    function Supertype(name) {
        this.name = name
        this.colors = ['white', 'black']
    }
    
    Supertype.prototype.getName = function() {
        console.log('name', this.name)
    }
    
    function Subtype(name) {
        Supertype.call(this, name)
    }
    
    inheritPrototype(Subtype, Supertype);
    
    Subtype.prototype.sayName = function(){
        console.log('sayName', this.name)
    }
    
    const instance1 = new Subtype('奔驰 S')
    instance1.colors.push('blue')
    
    const instance2 = new Subtype('奔驰 G')
  8. Implement Bubble Sort in JavaScript

    Bubble Sort repeatedly steps through the list, compares adjacent elements, and swaps them if they are in the wrong order. This process is repeated until the list is sorted.

    • Time Complexity: Worst/Average: O(n²), Best: O(n)
    • Space Complexity: O(1)
    • Stability: Stable
    const bubbleSort = arr => {
      let swapped = false
      const a = [...arr]
      for (let i = 1; i < a.length; i++) {
        swapped = false
        for (let j = 0; j < a.length - i; j++) {
          if (a[j + 1] < a[j]) {
            [a[j], a[j + 1]] = [a[j + 1], a[j]]
            swapped = true // swap data
          }
        }
        if (!swapped) return a // sorting complete if no swaps occurred in this pass
      }
      return a;
    };
  9. Implement Quick Sort in JavaScript

    Quick Sort is a divide-and-conquer algorithm that picks a 'pivot' element and partitions the array into two sub-arrays: elements less than the pivot and elements greater than or equal to the pivot.

    • Time Complexity: Average/Best: O(n log n), Worst: O(n²)
    • Space Complexity: O(1) (for in-place versions)
    • Stability: Unstable
    const quickSort = (arr) => {
      const a = [...arr];
      if (a.length < 2) return a;
    
      // Use the middle element as the pivot
      const pivotIndex = Math.floor(a.length / 2)
      const pivot = a.splice(pivotIndex, 1)[0]
      let leftArray = []
      let rightArray = []
    
      for (var i = 0; i < a.length; i++){
          if (a[i] < pivot) {
              leftArray.push(a[i]);
          } else {
              rightArray.push(a[i]);
          }
      }
    
      return [...quickSort(leftArray), pivot, ...quickSort(rightArray)]
    }
  10. Implement Selection Sort in JavaScript

    Selection Sort repeatedly finds the minimum element from the unsorted part and puts it at the beginning of the sorted part.

    • Time Complexity: O(n²) for all cases (Best, Worst, Average)
    • Space Complexity: O(1)
    • Stability: Unstable
    const selectionSort = arr => {
      const a = [...arr]
      for (let i = 0; i < a.length; i++) {
        let minIndex = i
        for (let j = i + 1; j < a.length; j++) { // find index of minimum value
          if (a[ j ] < a[ minIndex ]) {
            minIndex = j
          }
        }
        if (minIndex !== i) [a[i], a[minIndex]] = [a[minIndex], a[i]];
      }
      return a;
    }
  11. Implement Combination Inheritance

    Combination inheritance combines the prototype chain (for methods/prototype properties) and the borrowed constructor (for instance properties).

    Caveat: The supertype constructor is called twice (once during new Supertype() for the prototype and once via call() in the subtype constructor), resulting in redundant property assignments on both the prototype and the instance.

    function Supertype(name) {
        this.name = name
        this.colors = ['white', 'black']
    }
    
    Supertype.prototype.getName = function() {
        console.log('name', this.name)
    }
    
    function Subtype(name) {
        Supertype.call(this, name)
    }
    
    Subtype.prototype = new Supertype()
    Subtype.prototype.constructor = Subtype
    
    const instance1 = new Subtype('奔驰 S')
    instance1.colors.push('blue')
    
    const instance2 = new Subtype('奔驰 G')
  12. Implement Borrowed Constructor Inheritance (Classical Inheritance)

    This pattern calls the supertype constructor inside the subtype constructor using call() or apply() to inherit instance properties.

    Pros:

    1. Allows passing arguments to the supertype constructor.
    2. Reference properties are not shared between instances.

    Cons:

    1. Does not inherit prototype properties or methods (cannot access Supertype.prototype).
    2. Poor performance as every subtype instance creates a copy of the supertype constructor's logic.
    function Supertype(name) {
        this.name = name
        this.colors = ['white', 'black']
    }
    
    Supertype.prototype.getName = function() {
        console.log('name', this.name)
    }
    
    function Subtype(name) {
        Supertype.call(this, name)
    }
    
    const instance1 = new Subtype('奔驰 S')
    instance1.colors.push('blue')
    
    const instance2 = new Subtype('奔驰 G')