模范爸爸|「干货满满」1.5w字初中级前端面试复习总结( 五 )


/** * @param {function} func - 执行函数 * @param {number} delay - 延迟时间 * @return {function} */function throttle(func, delay){let timer = nullreturn function(...arg){if(!timer){timer = setTimeout(()=>{func.apply(this, arg)timer = null}, delay)}}}柯里化Currying(柯里化)是把接受多个参数的函数变换成接受一个单一参数的函数 , 并且返回接受余下的参数而且返回结果的新函数的技术 。
通用柯里化函数:
function currying(fn, arr = []) {let len = fn.lengthreturn (...args) => {let concatArgs = [...arr, ...args]if (concatArgs.length < len) {return currying(fn, concatArgs)} else {return fn.call(this, ...concatArgs)}}}使用:
let sum = (a,b,c,d) => {console.log(a,b,c,d)}let newSum = currying(sum)newSum(1)(2)(3)(4)优点:

  1. 参数复用 , 由于参数可以分开传入 , 我们可以复用传入参数后的函数
  2. 延迟执行 , 就跟 bind 一样可以接收参数并返回函数的引用 , 而没有调用
垃圾回收堆分为新生代和老生代 , 分别由副垃圾回收器和主垃圾回收器来负责垃圾回收 。
新生代一般刚使用的对象都会放在新生代 , 它的空间比较小 , 只有几十MB , 新生代里还会划分出两个空间:form空间和to空间 。
对象会先被分配到form空间中 , 等到垃圾回收阶段 , 将form空间的存活对象复制到to空间中 , 对未存活对象进行回收 , 之后调换两个空间 , 这种算法称之为 “Scanvage” 。
新生代的内存回收频率很高、速度也很快 , 但空间利用率较低 , 因为让一半的内存空间处于“闲置”状态 。
老生代【模范爸爸|「干货满满」1.5w字初中级前端面试复习总结】老生代的空间较大 , 新生代经过多次回收后还存活的对象会被送到老生代 。
老生代使用“标记清除”的方式 , 从根元素开始遍历 , 将存活对象进行标记 。 标记完成后 , 对未标记的对象进行回收 。
经过标记清除之后的内存空间会产生很多不连续的碎片空间 , 导致一些大对象无法存放进来 。 所以在回收完成后 , 会对这些不连续的碎片空间进行整理 。
JavaScript设计模式单例模式定义:保证一个类仅有一个实例 , 并提供一个访问它的全局访问点 。
JavaScript 作为一门无类的语言 , 传统的单例模式概念在 JavaScript 中并不适用 。 稍微转换下思想:单例模式确保只有一个对象 , 并提供全局访问 。
常见的应用场景就是弹窗组件 , 使用单例模式封装全局弹窗组件方法:
import Vue from 'vue'import Index from './index.vue'let alertInstance = nulllet alertConstructor = Vue.extend(Index)let init = (options)=>{alertInstance = new alertConstructor()Object.assign(alertInstance, options)alertInstance.$mount()document.body.appendChild(alertInstance.$el)}let caller = (options)=>{// 单例判断if(!alertInstance){init(options)}return alertInstance.show(()=>alertInstance = null)}export default {install(vue){vue.prototype.$alert = caller}}无论调用几次 , 组件也只实例化一次 , 最终获取的都是同一个实例 。
策略模式定义:定义一系列的算法 , 把它们一个个封装起来 , 并且使它们可以相互替换 。
策略模式是开发中最常用的设计模式 , 在一些场景下如果存在大量的 if/else , 且每个分支点的功能独立 , 这时候就可以考虑使用策略模式来优化 。
就像就上面手写深拷贝就用到策略模式来实现:
function deepClone(obj, map = new WeakMap()) {if (obj === null || typeof obj !== "object") return obj;const type = Object.prototype.toString.call(obj).slice(8, -1)// 策略对象let strategy = {Date: (obj) => new Date(obj),RegExp: (obj) => new RegExp(obj),Array: clone,Object: clone}function clone(obj){// 防止循环引用 , 导致栈溢出 , 相同引用的对象直接返回if (map.get(obj)) return map.get(obj);let target = new obj.constructor();map.set(obj, target);for (let key in obj) {if (obj.hasOwnProperty(key)) {target[key] = deepClone(obj[key], map);}}return target;}return strategy[type] ">


推荐阅读