js 原理及手动实现

387 阅读2分钟

1. new

// new 做了哪些事
// 1. 创建了一个新的空对象
// 2. 将新对象的 __proto__ 指向构造函数的 prototype 对象
// 3. 将构造函数的作用域赋值给新对象(也就是 this 指向新对象)
// 4. 执行构造函数中的代码(给这个新对象添加属性)
// 5. 返回新的对象

// 代码实现
function myNew(P) {
  let obj = {}
  let args = [...arguments].slice(1)
  obj.__proto__ = P.prototype
  P.prototype.constructor = P
  P.apply(obj, args)
  return obj
}

function _new(fn, ...arg) {
  const obj = Object.create(fn.prototype)
  const ret = fn.apply(obj, arg)
  return ret instanceof Object ? ret : obj
}

2. instanceof

// instanceof 检测 left 的原型链(__proto__)上是否有 right.prototype 有返回 true

function instanceOf(left, right) {
  let leftValue = left.__proto__
  let rightValue = right.prototype
  while (true) {
    if (leftValue === null) {
      return false
    }
    if (leftValue === rightValue) {
      return true
    }
    leftValue = leftValue.__proto__
  }
}

3. call

Function.prototype.myCall = function(content = window) {
  if (typeof this !== 'function') {
    throw new TypeError('Error')
  }
  content.fn = this
  let args = [...arguments].slice(1)
  let result = content.fn(...args)
  delete content.fn
  return result
}

4. apply

Function.prototype.myApply = function(content = window) {
  if (typeof this !== 'function') {
    throw new TypeError('Error')
  }
  content.fn = this
  let result
  // 判断是否有第二个参数
  if (arguments[1]) {
    result = content.fn(...arguments[1])
  } else {
    result = content.fn()
  }
  delete content.fn
  return result
}

5. bind

Function.prototype.myBind= function(content) {
  if (typeof this !== 'function') {
    throw new TypeError('Error')
  }
  let _this = this
  let args = [...arguments].slice(1)
  return function F() {
    // 处理函数使用 new 的情况
    if (this instanceof F) {
      return new _this(...args, ...arguments)
    } else {
      return _this.apply(content, args.concat(...arguments))
    }
  }
}

6. 深拷贝

function deepClone(obj) {
  let result = Array.isArray(obj) ? [] : {}
  for (var key in obj) {
    if (obj.hasOwnProperty(key)) {
      if (typeof obj[key] === 'object' && obj[key] !== null) {
        result[key] = deepClone(obj[key])
      } else {
        result[key] = obj[key]
      }
    }
  }
  return result
}

7. 防抖/节流

// 防抖: 1. 持续触发时不执行 2. 不触发的一段时间后再执行
function debounce(func, delay) {
  let timeout
  return function() {
    clearTimeout(timeout)
    timeout = setTimeout(() => {
      func.apply(this, arguments)
    }, delay)
  }
}

// 节流: 1. 持续触发并不会执行多次 2. 到一定时间再去执行
function throttle(func, delay) {
  let prev = Date.now()
  return function() {
    let now = Date.now()
    if (now - prev >= delay) {
      func.apply(this, arguments)
      prev = Date.now()
    }
  }
}

function throttle2(func, delay) {
  let run = true
  return function() {
    if (!run) return
    run = false
    setTimeout(() => {
      func.apply(this, arguments)
      run = true
    }, delay)
  }
}

8. Promise

class MyPromise {
  constructor(executor) {
    this.status = 'pending'
    this.value = undefined
    this.reason = undefined
    this.resolveCallbacks = []
    this.rejectCallbacks = []

    const resolve = value => {
      if (this.status === 'pending') {
        this.status = 'fulfilled'
        this.value = value
        this.resolveCallbacks.forEach(fn => fn())
      }
    }

    const reject = reason => {
      if (this.status === 'pending') {
        this.status = 'rejected'
        this.reason = reason
        this.rejectCallbacks.forEach(fn => fn())
      }
    }

    try {
      executor(resolve, reject)
    } catch (error) {
      reject(error)
    }

  }

  then(onFulfilled, onRejected) {
    if (this.status === 'fulfilled') {
      onFulfilled(this.value)
    } else if (this.status === 'rejected') {
      onRejected(this.reason)
    } else if (this.status === 'pending') {
      this.resolveCallbacks.push(() => {
        onFulfilled(this.value)
      })

      this.rejectCallbacks.push(() => {
        onRejected(this.reason)
      })
    }
  }
  
  static all(promiseArr) {
    return new Promise((resolve, reject) => {
      let result = []
      promiseArr.forEach((promise, index) => {
        promise.then(val => {
          result[index] = val
          if (result.length === promiseArr.length) {
            resolve(result)
          }
        }, reject)
      })
    })
  }

  static race(promiseArr) {
    return new Promise((resolve, reject) => {
      promiseArr.forEach(promise => {
        promise.then(val => {
          resolve(val)
        }, reject)
      })
    })
  }

}

9. 柯里化

// 柯里化: 把接收多个参数的函数变换成接收一个单一参数(最初函数的第一个参数)的函数 并且返回接收余下的参数且返回结果的函数

// 请实现一个 add 函数,满足以下功能(柯里化)
// add(1) // 1
// add(1)(2) // 3
// add(1)(2)(3) // 6
// add(1)(2, 3) // 6
// add(1, 2)(3) // 6
// add(1, 2, 3) // 6

function Currie(...nums) {
  // 将传入的数据以数组形式保存起来
  let arrs = [...nums]
  // 创建一个方法, 将每一次传入的值保存到数组中
  function Add(...nums) {
    arrs.push(...nums)
    return Add
  }

  Add.toString = () => arrs.reduce((a, b) => a + b)
  return Add
}

10. 数组乱序

function shuffle(arr) {
  for (var i = 0; i < arr.length - 1; i++) {
    let j = parseInt(Math.random() * (arr.length - 1))
    [arr[i], arr[j]] = [arr[j], arr[i]]
  }
  return arr
}

11. 数组快速排序

function quickSort(arr) {
  if (arr.length <= 1) return arr
  let pivotIndex = Math.floor(arr.length / 2)
  let pivot = arr.split(pivoIndex, 1)[0]
  let left = []
  let right = []
  for (var i = 0; i < arr.length; i++) {
    if (arr[i] < pivot) {
      left.push(arr[i])
    } else {
      right.push(arr[i])
    }
  }
  return quickSort(left).concat([pivot], quickSort(right))
}

12. Event Bus

class Bus {
  constructor() {
    this.callbacks = {}
  }
  
  $on(name, fn) {
    this.callbacks[name] = this.callbacks[name] || []
    this.callbacks[name].push(fn)
  }
  
  $emit(name, args) {
    if (this.callbacks[name]) {
      this.callbacks[name].forEach(cb => cb(args))
    }
  }
}

// main.js
Vue.prototype.$bus = new Bus()

// child1
this.$bus.$on('foo', handle)

// child2
this.$bus.$emit('foo')