• 手写:深拷贝、promise、bind/call

# 1、var let const 的区别

变量提升(js预解析)、window对象、块级作用域

# 3、模块化

  • AMD/CMD:require.js define定义。AMD是提前执行,CMD是延迟执行
  • CommonJs:Node.js require导入,module.exports导出,
    • (不能直接给exports赋值来导出,因为复杂数据类型赋值指针的问题,module.exports数据不会跟着改变)。
  • es module:原生es6,import导入,export 或 export default导出
    • 和commonjs的区别:commonjs支持动态导入;commonjs是异步导入;commonjs导出的是值的拷贝(浅拷贝),es module导出的是值的真实引用地址。

# 4、vue数据响应式原理

https://cn.vuejs.org/v2/guide/reactivity.html

  • Object.defineProperty()是针对对象的特定属性通过设置get set方法来劫持数据,不兼容ie9以下版本。
  • Proxy是针对object类型数据的所有属性都添加get set方法进行监听,在实现嵌套数据的遍历时更简单,性能更好,而且原生支持数组类型的监听,是es6新增的api,不兼容ie。
  • 在组件挂载的时候解析模板,使用到响应式数据的地方会生成watcher,解析求值时会触发响应式数据里的get方法,通过dep.addSubs()将watcher添加到subs数组里收集依赖;
  • 在更改数据时会触发set方法,通过dep.notify(),遍历subs数组的所有watcher,调用update()派发更新
  • 然后执行render函数,对比生成VDom,最后映射为真实dom展示出来。

# 5、数组的reduce方法

  • reduce((start, current, index, origin) => { return newRes }, initVal)
  • 先看有没有设初始值initVal, 如果没有initVal,那么就从数组第二项开始遍历,累加值start的初始值取数组第一项; 如果有initVal,那么就从数组第一项开始遍历,累加值start的初始值就取initVal; 累加值start后面循环时取的是回调函数的返回值newRes; current是当前遍历的数组元素,index是当前数组元素的索引,origin是原始数组。

# 6、Generator函数

  • 在定义的函数名前加一个星号*,内部通过yield设置分段点,返回一个迭代器,迭代器调用next()方法来使函数分段执行。

  • 可以用来处理ajax请求,解决回到地狱问题,react的状态管理库dva也是推荐这样来处理请求。

    function *fetch() {
        yield ajax(url, () => {})
        yield ajax(url1, () => {})
    }
    let it = fetch()
    let result1 = it.next()
    let result2 = it.next()
    
    1
    2
    3
    4
    5
    6
    7

# 7、promise

  • 三种状态:已完成resolved、已拒绝rejected、等待中pending。
  • then的回调函数的返回值会被Promise.resolve包装成promise对象。
  • Promise.all()所有的都成功或有一个失败;Promise.race()有一个成功或所有都失败。

# 8、async和await

async也是讲函数的返回值用Promise.resolve()包裹一下,和await配套使用, 本质是promise和generator的语法糖。

# 9、requestAnimationFrame

  • window.requestAnimationFrame(callback) 在下一次浏览器重绘之前执行,一般屏幕是1秒60帧,执行间隔就是1000/60,约等于16.67ms。
  • 能用于精确的控制执行间隔,也用于保持动画的流畅性。

# 10、event loop事件循环和事件队列

先在执行栈里执行同步代码,再查找异步队列,推入执行栈里执行异步代码,再执行下一个异步队列,这个过程就形成了事件循环,在一次事件循环中先执行微任务(promise)再执行宏任务(setTimeout)。

# 11、浏览器缓存

  • 强缓存:Cache-Control > Expires
  • 协商缓存:ETag > Last-Modified

# 12、安全

  • XSS:input输入<script>alert(1)</script>,录入数据库中,然后再数据回显的时候可能会执行script脚本。

    • 防范:对输入的尖括号<>进行检查校验。
  • CSRF:通过img标签src指向一个接口地址,来恶意伪造用户的请求。

    • 防范:请求时附带token之类的验证信息;阻止第三方网站的请求(cors或referer白名单)。

# 13、网页性能优化

    • cdn服务加速网络访问
    • 浏览器缓存
    • gzip压缩
    • 图片优化:压缩、base64、svg、字体图标、懒加载
    • 首屏优化:路由懒加载、图片懒加载、dom懒加载、loading效果、骨架屏
    • dns预解析(dns-prefetch)、js和css的预解析preload(当前页资源)和prefetch(其他页资源)
    • script标签放底部,适当地加async和defer异步属性
    • 减少重排重绘
    • 节流和防抖
    • splitChunks分离优化

# 14、MVVM

  • mvc:model、view、controller,controller同时控制model和view,工作职责太大了,不利于频繁更新的场景。
  • mvvm:model、view、viewModel,viewModel只控制操作model数据,然后通知view层更新视图,效率更高。

# 15、虚拟dom和diff算法

  • 用js对象描述dom,只更新修改的部分,提升渲染性能,虚拟dom的概念也有利于跨端开发。
  • diff算法:
    • dom有很多子节点,虚拟dom对象也有很多层级,只对同层进行比较,从最外层节点开始,
    • 首先判断两个节点的key值,如果key不一致,就认为是两个不同的节点,算法结束,
    • 如果key相同或没有key值,就判断其他属性是否相同,如果不相同就认为是两个节点,如果相同就判断子节点,这样依次递归查找。

# 18、Vue.extend()

用于拓展组件生成一个构造器,通过new构造器生成一个新的组件实例,类似组件的继承,vue3.0里废弃了。

# 19、mixins

合并规则:data数据和methods之类的对象类型的值会遍历合并,冲突时以组件内优先;钩子函数合并时都会执行,先执行mixins里的。

# 21、vue模板编译过程

将模板编译为抽象语法树AST(多叉树) 将AST转换为渲染函数 执行渲染函数生成VDOM 将VDOM映射为真实DOM

# 22、nextTick()原理

  • vue的dom更新是异步执行的,本身也是使用的nextTick()。修改数据时,会开启一个异步队列,将watcher的update()更新操作缓冲在同一事件循环中,同一个watcher只会被推入队列一次(通过watcherId去重),然后在下一事件循环中刷新队列,执行代码。这样做能减少频繁不必要的更新,提升更新渲染的效率。
  • nextTick()内部通过一系列异步api尝试将回调函数放入异步队列里,包括promise、mutationObserver、setImmediate,最后是setTimeout。
  • 所有的回调方法都会放入callbacks数组里,最后通过flushCallbacks()方法遍历callbacks数组来依次执行回调。

# 23、setState

setState不能保证同步执行,

在钩子函数和合成函数里表现的是异步,在setTimeout和原生事件里表现的是同步。

# 24、UDP和TCP

UDP更轻便,不需要经历建立连接和断开连接的阶段,适合直播。

TCP三次握手:

  • 客户端向服务端发送syn请求包,询问服务端能不能收到请求
  • 服务端接收后向客户端发送ack确认包,告诉客户端能收到
  • 客户端向服务端发送ack确认包,告诉服务端我也能收到,然后客户端进入准备状态,服务器接收后也进入准备状态。

TCP四次挥手:

  • 客户端向服务端发送fin请求包,告诉服务端要断开连接
  • 服务端收到后发送ack确认包告诉客户端收到了断开请求
  • 服务端有未传完的数据会继续传完,然后向客户端发送fin请求包,告诉客户端可以断开连接了
  • 客户端收到后向服务端发送ack确认包,然后客户单断开连接,服务端收到后也断开连接

# 25、http、https、http2

  • 请求报文

    请求行:请求方法、请求地址、请求协议

    请求头:content-type、referer、user-agent

    请求体:body数据

  • 状态码:

    301永久重定向 302临时重定向 304从缓存中读取

    400请求报文错误 403服务器拒绝访问 404找不到资源 414请求数据超限

  • https

    https是通过tls对数据进行了加密,使用了对称加密(AES)和非对称加密(RSA)

  • http2

    http1同时只能请求6个连接,而http2实现了多路复用,可以复用一个tcp连接。

    http1通过文本方式传输数据,http2通过二进制传输。

    https2对header进行了压缩。

    http2可以由服务端push推送。

# 26、输入 URL 到页面渲染的整个流程

dns解析 域名-ip com一级域名、baidu二级域名、www三级域名

tcp连接 三次握手、keep-alive四次挥手

nginx 负载均衡

状态码 200 40x 50x 30x

强缓存、协商缓存

gzip 自动按编码格式解析

html解析 异步script

dom树、css树、render树、重排重绘

gpu绘制,展示完成

# 27、设计模式

  • 工厂模式
    • 通过new出来一个实例对象来实现,可以new一个构造函数,也可以new一个class类。
    • 作用就是隐藏了创建实例的复杂过程,用户不用关心怎么实现的,只需提供一个接口,让用户调用,传入配置生成实例即可。
  • 单例模式
    • 单例模式就是保证全局只有这一个对象,这样可以共用同一个对象的数据
    • 定义一个对象,返回或者导出一个函数,在函数里判断这个定义的对象是否已存在,不存在就创建,已存在就直接返回
  • 适配器模式
    • 用来解决两个接口不兼容的情况,不改变已有的接口,而是包装处理一层来兼容其他接口。
    • 就像电脑不能读取sd卡,可以通过读卡器来识别读取sd卡。
  • 装饰模式
    • 不改变已有的接口,而是给接口添加功能。
    • 改已有的接口有风险,容易产生未知的bug,而利用装饰模式,只需要扩展功能,比较安全,也方便维护。
  • 代理模式
    • 是为了控制对对象的访问,不让外部直接访问对象。
    • 比如js中的事件代理,列表多个元素,都绑定点击事件不方便,可以给父元素绑定事件,通过事件对象获取到子元素来处理。
  • 观察者模式
    • 通过一对一或者一对多的关系,当对象改变时,通知订阅方。
    • vue中的数据响应式也是使用的观察者模式,通过对象代理,在get方法里收集依赖,对象改变时触发set方法,然后派发更新,就实现了数据的响应式。

# 28、数据结构

  • 时间复杂度

    • 使用最差的时间来衡量一个算法的好坏,这种衡量方式就是时间复杂度
    • 线性结构,在同一端进行添加和删除的操作,先进后出
  • 队列

    • 线性结构,在一端添加,另一端删除,先进先出
  • 链表

    • 线性的递归结构,通过指针相连,
    • 可以用git仓库的存储理解,不同的分支和节点连接在一起。
  • 二叉树

    • 递归结构,有一个根节点,每个节点最多有两个子节点。
  • 二分搜索树

    • 也是二叉树,特点是右节点比左节点的值大,用于搜索查找比较高效。
    • 非线性的数据结构,可以看成是完全二叉树组成的数组对象。
    • 完全二叉树:除最深层外的其他层的每个节点的子节点都是满的,而且最深层的节点是仅靠着最左侧排列的。

# 29、排序算法

  • 冒泡排序:谁大谁就交换位置,一直找出最大的放最右边,剩余的再重复。时间复杂度:O(n * n)

  • 插入排序:从二个开始依次取出往前插入,插入方式就是比较大小,插入对应的位置,这样前面已插入的都是排序好的了,重复执行。时间复杂度:O(n * n)

  • 快速排序:分治法,选择一个数据作为基准值,小鱼基准值的放左边,大于基准值的放右边,然后拆成两部分,每部分再重复步骤,最后拆到最小粒度。时间复杂度:平均是O(n * logN),最坏是O(n * n)

# 30、flex: 1

全写 flex: 1 1 0%;

flex-grow 定义flex的放大系数,即有剩余空间时放大多少,默认值1。

flex-shrink 定义flex的缩小系数,即空间不足时缩小多少,默认值1。

flex-basis 定义放大或缩小的计算尺寸,根据这个尺寸来判断空间够不够,默认值auto。

# 31、安全区适配

viewport-fit: cover

constant(safe-area-inset-bottom)

env(safe-area-inset-bottom)

# 32、webpack优化

chunk分离 splitChunks

js压缩 terser-webpack-plugin

css压缩 optimize-css-assets-webpack-plugin

gzip压缩

css分离 mini-css-extract-plugin

tree-shaking es6模块化导入导出支持静态分析

DllPlugin 创建manifest.json文件记录缓存信息

IgnorePlugin 忽略打包指定文件

# 33、继承实现

  • class Chilid extends Parent {
      constructor () {
        super()
      }
    }
    
    1
    2
    3
    4
    5
  • function Parent () {
      this.name = 'p'
    }
    function Child () {
      Parent.call(this)
      this.age = 27
    }
    Child.prototype = new Parent()
    
    1
    2
    3
    4
    5
    6
    7
    8

# 34、new 操作符做了什么

  • 创建了一个空对象
  • 通过this变量指代该对象
  • 给对象的属性赋值,并继承了构造函数的原型
  • 构造函数隐式地返回this

# 35、面向对象

运用类、继承、封装等进行程序设计的一种思想。

  • 能够将复杂问题和复杂逻辑简单化
  • 方便扩展
  • 方便维护

# 36、node

  • 特点:js运行环境、依赖v8引擎解释代码、事件驱动、非阻塞I/O、单进程和单线程
  • 优点:高并发、文件读写效率高
  • 缺点:只支持单核cpu、可靠性低(代码出错容易导致整个系统崩溃)

# 37、set map

都是集合类型的数据结构

  • set 数据项不重复
  • weakSet 数据项都是对象,且是弱引用的对象,随时可能会作为垃圾被回收,所以无法遍历
  • map 键值对集合,键可以是任意类型
  • weakMap 键只能是对象,该对象也是弱引用,无法遍历

# 38、ts泛型

不确定数据类型,又想对类型有一定的约束。

比如函数入参和返回值保持一致的类型。

泛型进一步约束:

interface Lengthwise {
    length: number;
}

function say<T extends Lengthwise>(arg: T): T {
	console.log(arg.length)
    return arg;
}
1
2
3
4
5
6
7
8

# 39、for...in 和 for...of

  • for...in

    用于迭代对象的除Symbol以外的可枚举属性

    迭代数组时,迭代的是数组的下标

  • for...of

    用于迭代对象的数据

    迭代数组时,迭代的是数组的项

  • Array.prototype.arrCustom = function() {};
    
    let iterable = [3, 5, 7];
    iterable.foo = 'hello';
    
    for (let i in iterable) {
      console.log(i); // 0, 1, 2, "foo", "arrCustom"
    }
    
    for (let i of iterable) {
      console.log(i); // 3, 5, 7
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12

# 40、水平垂直居中

  • flex
  • absolute
  • table-cell 父盒子设置display: table-cell; 子盒子设置display: inline-block;
  • grid 父盒子设置display: grid; place-items: center center;

# 41、push、pop、unshift、shift

  • push()和unshift()
    • 向数组的 尾部/头部 *添加若干元素*,并返回 数组的 新长度
  • pop()和shift()
    • 从数组的 尾部/头部 *删除1个元素(删且只删除1个)*,并返回 被删除的元素;空数组是继续删除,不报错,但返回undefined;

# 42、vue重写数组的7个方法

push pop unshift shift splice sort reverse

  • 通过Object.create()对Array的原型创建一个实例对象(arrayMethods)
  • 遍历这7个方法,对创建的这个实例对象以及相应的方法属性添加响应式,进行监听
  • 重写这些方法,在调用原方法后,再手动通知订阅者(ob.dep.notify())来派发更新
  • https://www.cnblogs.com/ming1025/p/13082822.html

# 43、keep-alive原理

通过缓存vnode实现,在渲染的时候对比组件的name(通过include和 exclude控制),命中缓存时就从缓存中读取。

activated deactivated

内存超限时通过LRU算法来管理

# 44、css modules

在css-loader里配置

{
  loader: 'css-loader',
    options: {
      modules: {
        localIdentName: "[name]_[local]__[hash:5]"
      }
    },
}
1
2
3
4
5
6
7
8

# 45、addEventListener

options参数

  • 布尔值,默认false,冒泡阶段触发
  • 对象值,
    • capture,默认false,冒泡阶段触发
    • once,默认false,是否只调用一次
    • passive,chrome等浏览器下默认是true,是否不调用preventDefault(),提升scroll事件和touch事件(touchstart touchmove)的性能

# 46、小程序运行机制

  • 小程序是运行在宿主环境,也就是app客户端内,

  • 传统的网页是js执行和dom渲染在一个线程里,js会阻塞dom的渲染,

  • 而小程序是分成了渲染层和逻辑层,在不同的线程里,渲染层运行在webview里,逻辑层运行在JsCore里,js的运行不会阻塞渲染,提升了页面运行效率。

  • 渲染层和逻辑层之间是通过native客户端来进行数据交互,也就是使用的小程序基础库。

  • 在逻辑层里通过setData改变数据,native转发到渲染层,然后对比数据生成虚拟dom,最后更新在视图上。

性能优化:减少setData的频率、减小setData传递的数据量。

# 47、手机调试

  • vconsole
  • charles
  • spy-debugger
  • chrome devtools (只能安卓,需要开启开发者调试和usb调试、连接数据线、安装usb驱动)

# 48、render函数

render函数可以用来动态创建组件节点:

  • 参数第一个是createElement函数,通常用h指代,参数第二个是context对象,一般在函数式组件(无状态,渲染快)里使用。

  • createElement函数参数:标签名,标签属性对象,子节点数组。返回值是VNode,所有VNode组成VDom。

render函数可以用jsx语法代替:

  • 先安装插件babel-preset-jsx,在babel.config.js里配置引入,然后就可以在jsx后缀的文件里使用了。
  • 比render函数更简单直观。

# 49、native交互

  • 通过url scheme拦截

    • 客户端注册一个url scheme协议,h5使用并传递参数,客户端拦截获取到数据
    • 不适合数据量大的;只能由h5向客户端传递数据
  • 通过在window对象上添加bridge桥接属性

    • 客户端引入相应的库可以执行js代码(evaluateJavascript)
    • 通过在window对象上约定一个属性,作为桥接,所有的交互方法都注册在这个桥接上
    • 比如,h5向客户端传递数据,就是客户端提前注册一个方法,h5这边调用并传递数据,必要时多设置一个参数作为回调函数,h5提前注册好回调函数,客户端接收参数后先执行完正常的逻辑,最后调用回调参数即可。
  • 推荐插件:DSBridge,支持同步调用,兼容性好。

# 50、webview优化

  • 提前初始化webview
    • app启动时在后台初始化一个全局的webview,后续打开页面时就使用这个webview
  • 客户端代理数据请求
    • 必要的时候可以由客户端在初始化webview时就获取接口数据,页面初始化后从客户端里拿数据。(例如动态图片域名)
  • 利用dns缓存
    • webview页面域名使用和客户端api相同的域名,域名解析时会缓存dns。
最后更新时间: 2022/10/23 10:24:55