小总结2022

162 阅读9分钟

**1 **deepClone 手写递归,具体实现方式,特别数据的边界处理(时间,function,正则);如何解决循环引用的问题,处理方式,判断条件终止,deepClone 如何终止的?

export function deepClone(obj, hash = new WeakMap()) {
  // 处理null或者undefined
  if (obj === null) return obj;
  // 处理日期类型
  if (obj instanceof Date) return new Date(obj);
  // 处理正则类型
  if (obj instanceof RegExp) return new RegExp(obj);
  // 普通值或函数不需要深拷贝
  if (typeof obj !== "object") return obj;
  // 对象进行深拷贝
  if (hash.get(obj)) return hash.get(obj);
  let cloneObj = new obj.constructor();
  // 找到的是所属类原型上的constructor,而原型上的 constructor指向的是当前类本身
  hash.set(obj, cloneObj);
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      // 实现一个递归拷贝
      cloneObj[key] = deepClone(obj[key], hash);
    }
  }
  return cloneObj;
}
复制代码

2 (√)js 事件循环机制 1 js是单线程语言,同步和异步任务分别进入不同的执行环境,同步的进入主线程,即主执行栈,异步的进(事件队列) 。主线程内的任务执行完毕为空,上述过程的不断重复为Event Loop (事件循环)。

// 求平均时间
var arr = ["8:01", "9:30", "11:50"];

const average = (arr) => {
  let minutes = 0;
  arr.forEach((o) => {
    let a = o.split(":");
    minutes = minutes + a[0] * 60 + parseInt(a[1]);
  });
  minutes = minutes / arr.length;

  let hour = Math.floor(minutes / 60);
  let minute = minutes - 60 * hour;
  console.log(hour, "...", minute);

  return `${hour}:${minute}`;
};

console.log(average(["8:01", "9:30", "11:50"])); // 9:47
复制代码
var arr = ['8:01', '9:30', '11:50']
let res = 0
arr.forEach(el => {
    res += new Date('2000/01/01 ' + el).getTime()
})
const a = new Date(res / arr.length)
console.log(`${a.getHours()}:${a.getMinutes()}`)
复制代码
-   vue style scoped 属性作用是啥,如何是样式仅在当前模块生效

    -   作用:实现组件的私有化,不对全局造成样式污染,表示当前 style 属性只属于当前模块
    -   原理:打包之后,编译成特定样式,`data-v-[hash]`,即 CSS 带属性选择器

3 遍历数组的方式:forEach;for in;for of;

-   forEach 和 map 的区别;

    -   map 不写 return,默认返回 undefined,返回一个数组长度的 undefined 的数组;

-   forEach 中断循环

    -   用数组的方法,return false;
    -   数组的 api,使用 some 或者 every 实现
    -   使用 for 循环或者 for in 代替
    -   使用 throw 抛出异常

4- 遍历对象的方式

-   for in:主要用来遍历对象(for keys in obj)

    -   遍历自身和继承的可枚举属性(延续原型链遍历出对象的原型属性)
    -   有什么问题:要使用 hasOwnProperty 判断,只处理自身的,不处理继承的

-   for ofES6 新增的,遍历所有数据结构的统一的方法

    -   只要部署了 Symbol.iterator 属性,就被视为具有 iterator 接口,就可以用 forof 循环遍历它的成员
    -   包括数组、SetMap 结构、某些类似数组的对象(比如 arguments 对象、DOM NodeList 对象)、Generator 对象,以及字符串

-   Object.keys:返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含 Symbol 属性)

-   Object.getOwnPropertyNames(obj):返回一个数组,包含对象自身的所有属性(不含 Symbol 属性,但是包括不可枚举属性)

-   Object.getOwnPropertySymbols()

-   Reflect.ownKeys(obj)遍历:返回一个数组,包含对象自身的所有属性,不管属性名是 Symbol 或字符串,也不管是否可枚举

5- vue-router 路由参数,从一个商品跳入到另一个商品,路由参数变化,但是路由不变化,渲染会出现的问题,

-   原因:同一个组件不会挂载两次

-   解决办法:

    -   监听路由参数变化,watch 实现

    -   组件内的路由导航:

        -   路由独享守卫,beforeEnter
        -   组件内的守卫 beforeRouteEnter beforeRouteUpdate (2.2 新增) beforeRouteLeave

6

  • (√)new 操作符具体干了啥?
  • 1 创建一个对象
  • 2 的this指向这个对象
  • 3 执行函数体
  • 4 自动返回这个函数

7- (√)数组常用方法

-   pushpopshiftunshift;slice;splice
-   indexOf;includes;find
-   reversesort;
-   joinsplit;concat;
-   some;every;forEach;filter;map
-   reduce;reduceRight
// accumulator-累加器;currentValue-当前值;currentIndex-当前值索引;initialValue-初始值;
array.reduce(function(accumulator, currentValue, currentIndex, array), initialValue)

  // 1. 数组求和
let total = [1, 2, 3, 4].reduce((acc, cur) => (acc += cur), 90);

// 2. 数组去重 [1,2,4,null]
// 2.1 filter
let arr = [1, 2, 2, 4, null, null].filter((item, index, arr) => arr.indexOf(item) === index);
// 2.2 new Set
let arr = [...new Set([1, 2, 2, 4, null, null])];
// 2.3 reduce
let arr = [1, 2, 2, 4, null, null].reduce((acc, cur) => {
    return acc.includes(cur) ? acc : acc.concat(cur);
}, []);

// 3. 扁平化多维数组 [0, 1, 2, 3, 4, 5, 6, 7]
let arr = [0,[1],[2, 3],[4, [5, 6, 7]]]
// 3.1 flat
arr.flat(Infinity);
// 3.2 reduce
let dimensionReduction = function (arr) {
    return arr.reduce((acc, cur) => {
        return acc.concat(
            Array.isArray(cur) ?
            dimensionReduction(cur) :
            cur
            );
    }, []);
}
dimensionReduction(arr);

// 4. 求字符串中字母出现的次数
const str = 'sfhjasfjgfasjuwqrqadqeiqsajsdaiwqdaklldflas-cmxzmnha';
const res = str.split('').reduce((acc, cur) => {acc[cur] ? acc[cur]++ : acc[cur] = 1; return acc;}, {});

// 5. 数组转对象  按照id 取出stream
var streams = [{name: '技术', id: 1}, {name: '设计', id: 2}];
var obj = streams.reduce((acc, cur) => {acc[cur.id] = cur; return acc;}, {});
复制代码
  • 手写 reduce
Array.prototype.myReduce = function (cb, initValue) {
  const array = this; // 获取数组
  let pre = initValue || array[0];
  const startIndex = initValue ? 1 : 0;
  for (let i = startIndex; i < array.length; i++) {
    const cur = array[i];
    pre = cb(pre, cur, i, array);
  }
  return pre;
};
复制代码
  • (√)web 攻击方式:攻击目标,预防方式

    • XSS (Cross Site Scripting) 跨站脚本攻击

    • CSRF(Cross-site request forgery)跨站请求伪造

      • token 实现安全的原理
    • SQL 注入攻击

  • (√)http1.0,htt1.1,http2.0,http3.0 的区别

    • http 是有状态还是无状态的,请求有无区别(无状态,携带辅助信息)
  • (√)vue diff 算法

    • 比较只会在同层级进行, 不会跨层级比较:节点类型不同,直接用新的替换旧的;相同,就比较子节点
    • 在 diff 比较的过程中,循环从两边向中间比较
  • (√)vue 虚拟 DOM 的作用

    • 不会进行回流和重绘;
    • 对于频繁操作,只进行一次对比差异并修改真实 DOM,减少了真实 DOM 中多次回流重绘引起的性能损耗;
    • 有效降低大面积的重绘与排版,只更新差异部分,进行渲染局部;
  • (√)vue key 的作用:高效的更新虚拟 dom

  • (√)v-if 和 v-for

  • (√)JS 事件循环机制

    • 同步、异步(宏任务、微任务);
    • 一段代码,输出执行顺序
  • (√)项目错误处理

    • 后端接口报错:axios 的响应拦截器处理
    • 代码逻辑错误
    • 对象属性未定义错误处理:可选链 obj?.name
    • 错误拦截:try、catch
    • vue 内置错误处理机制:errorHandler;errorCaptured

444

  1. URL 解析
  2. DNS 查询
  3. TCP 连接(三次握手) 第一次握手:建立连接时,客户端发送 syn(建立联机)包到服务器,并进入 syn_send 状态,等待服务器确认; 第二次握手:服务器收到 syn 包,确认包信息,同时自己也发送一个 syn + ack(确认)包并进入 syn_recv 状态; 第三次握手:客户端收到 syn+ack 包,向服务器发送 ack 包,发送完后,客户端和服务器都进入 established 状态,完成三次握手;
  4. HTTP 请求
  5. 服务器响应请求
  6. 页面渲染 解析 HTML,构建 DOM 树(script 会下载 并解析 js,异步下载完执行是仍会阻塞 DOM 解析) 解析 CSS(link 或 style 标签),生成 CSS 规则树(HTML 和 CSS 解析相互独立) 合并 DOM 树和 CSS 规则,生成 render 树 布局 render 树( Layout / reflow 回流),负责各元素尺寸、位置的计算 绘制 render 树( paint 重绘),绘制页面像素信息 浏览器会将各层的信息发送给 GPU,GPU 会将各层合成( composite ),显示在屏幕上

实现两个字符串型数字的加法运算,返回字符串型的数字的和

注意:无法直接对传入参数进行转换成数字

思路:一位数一位数相加,采用隐式转化的方式相加

sum("1233", "233"); // '1466'

function sum(num_str1, num_str2) {
  // 字符串转字符数组
  const num_arr1 = num_str1.split("");
  // 字符串转字符数组
  const num_arr2 = num_str2.split("");
  // 竖式加法计算次数
  let sum_length = Math.max(num_arr1.length, num_arr2.length);
  // 求和结果
  const sum = [];
  // 进位标志位
  let CF = 0;
  // 循环语句为什么加CF进位存在判断呢,因为当最高位产生进位,(如 999 + 9999)
  // 计算到千分位9的时候,并且没有更多数要参与运算时,仍然需要进位参与一次运算,否则丢失进位。
  while (sum_length-- > 0 || CF) {
    // 求和,注意数组长度不够,按0算
    let temp =
      Number.parseInt(num_arr1.pop() || 0) +
      Number.parseInt(num_arr2.pop() || 0) +
      CF;
    if (temp >= 10) {
      temp %= 10; // 取个位数
      CF = 1; // 产生进位(对于加法,最多产生1个进位)
    } else {
      CF = 0; // 未产生进位
    }
    sum.unshift(temp); // 记录求和数据(从头插入)
  }
  return sum.join("");
}
复制代码
  • vue2.0 和 vue3.0 区别

    • 2.0

      • 双向数据绑定:Object.defineProperty
    • 3.0

      • 双向数据绑定:Proxy,Reflect
      • Composition API:更好的逻辑复用和代码组织
      • Fragment:可以用多个根元素
      • Teleport(任意门)
      • 使用 Typescript 开发
      • 重构 Virtual DOM,修改了 diff 算法
  • v-model 在 2.0 和 3.0 里面的区别,实现原理

    • 破坏性的: 当用在 自定义组件 上的时候,v-model 的 prop 与 event 的默认名已变更:

      • prop: value -> modelValue;
      • event: input -> update:modelValue;
    • 破坏性的: v-bind 的 .sync 修饰符以及 model 选项已删除,取而代之的是 v-model 的一个参数;

    • 新的: 现在可以在一个组件上使用多个 v-model 来绑定数据了;

    • 新的: 新增了自定义 v-model 修饰符的功能。

  • flex 弹性布局

    • flex:1,等价于 0 1 auto,各个参数含义
    • 实现纵向三栏布局,中间 flex:1,如果中间宽度大于外层宽度,怎样表现?
  • z-index 无效问题:生效范围;什么情况下会失效,边界条件

    1. 父级元素溢出隐藏或者不显示:父元素设置了 overflow:hidden /display:none/ 等,那么子元素如果在父元素外部绝对定位,那么调节子元素 z-index 可能不会显示
    2. 父级元素层级低,z-index 被覆盖
    3. 没有设置定位(position)属性
    4. 父级元素 position 属性为 relative
    5. 含有浮动(float)属性
    6. IE 不兼容
  • 移动端 1px 边框

    1. 针对 IOS:border:0.5px solid #E5E5E5
    2. 使用边框图片
    3. 使用 box-shadow 实现:试了下,看不出效果
    4. 使用伪元素:设置绝对定位,和父元素左上角对齐。将伪元素的长和宽先放大 2 倍,然后再设置一个边框,以左上角为中心,缩放到原来的 0.5 倍
    5. 设置 viewport 的 scale 值
  • 协商缓存和强缓存使用场景

    1. 强缓存:访问服务器获取到数据后缓存下来,过期时间之内不会再重复请求,而是直接从本地缓存数据库读取

    • http1.0:Expire 相应头。expires 表示未来资源会过期的时间

    • http1.1:Cache-Control。max-age=xxx(缓存的资源将在 xxx 秒后过期);no-cache(需要使用协商缓存来验证是否过期);no-store(不可缓存)

    1. 协商缓存:每次读取数据都要和服务端通信,增加缓存标志。如果不匹配,表示资源更新,返回新数据;匹配则表示没有更新,返回 304

    • http1.0:Last-Modified;If-Modified-Since;弊端是时间的精确度只能在秒,资源没变但时间变了,也会更新

    • http1.1:Etag; If-None-Match

    1. 常见情况

    • 输入 url 回车进入:根据实际缓存策略处理,没有设置 no-cache 或 no-store,默认先走强制缓存路线
    • 按钮刷新,F5 刷新,右键重新加载:将 cache-control 的 max-age 直接设置成了 0,让缓存立即过期,直接走协商缓存路线
    • ctrl+F5 强刷:浏览器会强行设置 no-cache,强制获取最新的资源
  • vue-router 实现原理

    • 怎么知道页面变化了,更新页面;3.0 通过响应式,监听变量,响应机制;局部刷新
    • hash 模式:hashchange
    • history 模式:pushState 和 replaceState
  1. ES6 常用方法和属性
  • 类 class,extends
  • 模块化 import/export
  • 箭头函数
  • 模板字符串
  • 函数参数默认值
  • 解构赋值
  • 扩展运算符(...)
  • let, var, const
  • Promise, .then, .catch, .finally, .all(), .race,
  • async/await
  • includes;Object.values();Object.entries()
  1. props 传值无法更新问题

通过 props 传值不随着变化而变化,原因及解决方法(实际问题)

  • watch 监听:immediate;deep
  • this.$set()
  • 使用 v-if
  • Object.assign()
  1. Promise 常用方法
  • Promise

    • 异步编程的一种解决方案,解决地狱回调
    • 三种状态:pending(进行中);fulfilled(已成功);rejected(已失败)
    • then,catch,finally
    • all,race,allSettled,resolve,reject,try
  • async/await:Generator(yield,next) 的语法糖

  1. 手写 Promise.all;Promise.all 和 Promise.race 的区别?
// Promise.all
export const all = (promiseArr) => {
  let result = [];
  let count = 0;
  return new myPromise((resolve, reject) => {
    for (let i = 0; i < promiseArr.length; i++) {
      Promise.resolve(promiseArr[i]).then(
        (res) => {
          result[i] = res;
          count++;
          // 全部promise执行成功之后才resolve
          if (count === promiseArr.length) {
            resolve(result);
          }
        },
        (err) => {
          reject(err);
        }
      );
    }
  });
};

// Promise.race
export const race = (promiseArr) => {
  return new myPromise((resolve, reject) => {
    for (let i = 0; i < promiseArr.length; i++) {
      Promise.resolve(promiseArr[i]).then(
        (res) => {
          // 只要有任何一个promise状态变更就resolve
          resolve(res);
        },
        (err) => {
          reject(err);
        }
      );
    }
  });
};
复制代码
  1. 元素在页面隐藏的方式
  • display:none
  • visibility:hidden
  • opacity:0
  • 设置 height、width 模型属性为 0
  • position:absolute,将元素移出可视区域
  • transform 偏移:同上
  • clip-path:裁剪
  1. CSS 高度塌陷的原因;如何解决(BFC)
-   原因:
    -   子元素浮动,父元素就会塌陷
    -   当子元素添加了 positive:absolute 属性,父元素高度塌陷,高度为 0

-   解决:

    -   触发 BFC:overflow hidden
    -   清除浮动:clear both;after 伪元素

21. 模块化方式,import 和 require 区别

-   CommonJs (典型代表:node.js 早期):用于服务端

    -   都运行在模块作用域,不会污染全局作用域
    -   同步加载的,即只有加载完成,才能执行后面的操作
    -   首次执行后就会缓存,再次加载只返回缓存结果,如果想要再次执行,可清除缓存
    -   require 返回的值是被输出的值的拷贝,模块内部的变化也不会影响这个值

-   AMD (典型代表:require.js):异步模块定义

    -   所有依赖模块的语句,都定义在一个回调函数中,等到模块加载完成之后,这个回调函数才会运行
    -   require

-   CMD (典型代表:sea.js)

-   ES6 的 Module:import/export

    -   CommonJS 和 AMD 模块,都只能在`运行时`确定这些东西
    -   ES6 设计思想是尽量的静态化,使得`编译时`就能确定模块的依赖关系,以及输入和输出的变量
    -   import()允许您仅在需要时动态加载模块,而不必预先加载所有模块