【JavaScript】阶段性复习

  • View / MVVM 框架
    • 对比 React 、Angular 和 Vue
      • 相同点
      • 不同点
    • 如何实现一个组件,前端组件的设计原则是什么?
  • Vue
    • computed 与 watch 的区别
    • Vue.nextTick 原理和作用
    • Vue3.x 的新特性
  • React
    • React 生命周期
    • React 中使用 useEffect 如何清除副作用?
    • 对比 React 和 Vue 的 diff 算法
    • React 中有哪几种类型的组件,如何选择?
  • Css
    • 如何实现单行居中,多行居左?
    • 如何实现 1px 边框?
    • 多方法实现高度 100% 容器
    • 多方法实现圆角边框
    • 多方法实现文字描边
  • JavaScript
    • es3相关题
    • 事件
      • 事件传播的过程
      • Event Loop 的执行顺序?
      • 为什么 Vue.$nextTick 通常比 setTimeout 优先级高,渲染更快生效?
    • 一些ES6新特性
    • 列举类数组对象
    • 闭包
      • 什么是闭包?
      • 什么是词法?
      • 什么是函数柯里化?
    • bind / apply / call / new
      • 手写bind
      • 手写 call
      • 手写apply
      • 手写new
      • 手写防抖
      • 手写节流
    • 原型链
      • 对比各种继承
    • 模块化
      • webpack 中 loader 和 plugin 的区别?
      • 如何自定义一个 webpack 插件?
      • 对比 import、import() 和 requrie
  • 算法
    • 位运算
      • 什么是原码、反码、补码?
      • 位运算求绝对值?
    • 数组
      • 去除数组中的指定元素
      • 数组去重方法
      • 判断一个对象是不是数组 Array
      • 移动零
      • 空间复杂度为 O(1) 的中序遍历(莫里斯)遍历
    • 递归
      • 求最大公约数
    • 排序
      • 插入排序
      • 快速排序
      • 归并排序
      • 冒泡排序
  • 全栈
    • node.js
      • express 中 next 的作用?
      • 对比 express 和 koa?
    • 计算机网络
      • 对比持续通信的方法
      • 网络结构按五层和七层分别是
      • 什么是 TCP 三次握手,为什么要三次握手?
      • 浏览器有哪些请求方法?
      • 提交表单的内容类型有哪些?
      • docker 与虚拟机区别
      • 对比 Intel 的 VT-x,VT-d,VT-c
      • 对比 Cookie、LocalStorage、SessionStorage、Session、Toke
      • 什么是 Service Worker?
    • 性能
      • 如何测量并优化前端性能?
    • SEO
      • 前端中有哪些 SEO 优化手段?
    • 安全
      • 什么是帆布指纹?
      • 对比各种分布式 ID 的生成方式
      • 各种跨域方法
    • 数据库
      • 什么是乐观锁,什么是悲观锁
      • 什么是事务
      • 文档管理工具
      • 对比 Git 和 SVN

View / MVVM 框架

对比 React 、Angular 和 Vue

相同点

  • React 和 Vue都提供了 Virtual Dom
  • 提供了 响应式(Reactive)和组件化(Composable)的视图组件
  • 注意力保持在核心库,而将其他功能如路由和全局状态管理交给相关的库

不同点

渲染优化
React:当组件状态发生变化时,以该组件为根,重新渲染整个组件子树

  • shouldComponentUpdate,采用合适方式,如不可变对象,比较 props 和 state,决定是否重新渲染当前组件
  • 使用 PureComponent:继承自 Component 类,自动加载 shoudComponentUpdate 函数,自动对
    props 和 state 浅比较决定是否触发更新

Vue:自动追踪组件依赖,精确渲染状态改变的组件
HTML 和 CSS
React:支持 JSX

  • 在构建视图时,使用完整的 JavaScript 功能
  • 开发工具多支持 JSX 语法高亮,类型检查和自动完成

Vue:提供渲染函数,支持 JSX,但默认推荐 Vue 模版

  • 与书写 HTML 更一致的开发体验
  • 基于 HTML 的模版更容易迁移到 Vue
  • 设计师和新人开发者更容易理解和参与
  • 支持模板预处理器,如 Pug

CSS 作用域
React:通过 CSS-in-JS 方案,如 styled-components 和 emotion
Vue:

  • 支持 CSS-in-JS 方案,如 styled-components-vue 和 vue-emotion

  • 单文件组件中 style 标签可选 scoped 属性。支持 Sass \ Less \ Stylus 等 CSS 预处理器,深度集成
    CSS Modules

规模
向上扩展:
React:

  • 路由库和状态管理库,由社区维护支持,生态松散且繁荣
  • 提供脚手架工具,故意作了限制
  • 不允许在项目生成时进行配置
  • 只提供一个单页面应用模板
  • 不支持预设配置

Vue:

  • 路由库和状态管理库,由官方维护支持,与核心库同步更新
  • 提供 CLI脚手架,可构建项目,快速开发组件的原型
  • 允许在项目生成时配置
  • 提供了各种用途的模板
  • 支持预设配置

向下拓展
React:学习曲线陡峭,需要前置知识:JSX ES2015,需要学习构建系统
Vue:既支持向上拓展与 React 一样,也支持向下拓展与 jQuery 一样,上手快

原生渲染
React Native:使用相同组件模型编写具有本地渲染能力的APP,跨平台开发
Weex:阿里巴巴发起,Apache 基金会孵化,同样支持本地渲染,跨平台开发
NativeScript-Vue,基于 Vue.js 构建原生应用的 NativeScript 插件

MobX
React:流行的状态管理框架
Vue:选择 Vue 比 React + MobX 更合理

Preact 和其它类 React 库
难以保证与 React 库 100% 兼容

Vue 和 Angular 相同点
TypeScript 都支持 TypeScript,支持 类型声明 和 组件装饰器
运行时性能,Angular 和 Vue 都很快

Vue 和 Angular 不同点

  • 体积

Angular 用 AOT 和 tree-shaking 缩小体积
Vuex + Vue Router (gzip 后 30kB)比使用优化angular-cli (~65kB)小

  • 灵活性

Vue 提供构建工具,不限制组织应用代码的方式
Angular 提供构建工具,有相对严格的代码组织规范

  • 学习曲线

Vue 只需 HTML 和 JavaScript 基础
Angular 提供 API 和 概念 更多,设计目标针对 大型复杂应用,对新手有难度

如何实现一个组件,前端组件的设计原则是什么?

  • 单一原则:一个组件只做一件事
  • 通过脑图、结构图,标识组件的 State Props Methods 生命周期,表示层次和数据流动关系
  • State 和 Props
    • 扁平化:最多使用一层嵌套,便于对比数据变化,代码更简洁
    • 无副作用:State 仅响应事件,不受其他 State 变化影响
  • 松耦合
    • 组件应该独立运行,不依赖其它模块
    • 配置、模拟数据、非技术说明文档、helpers、utils 与 组件代码分离 视图组件只关心视图,数据获取,过滤,事件处理应在外部 JS 或 父组件 中处理
  • Kiss原则(Keep it Simple Stupid)
    • 不需要 State 时,使用 函数组件
    • 不要传递不需要的 Props
    • 及时抽取复杂组件为独立组件
    • 不要过早优化
  • 参考 CSS 的 OOSS 方法论,分离 位置 和 样式,利于实现皮肤
  • 考虑 多语言、无障碍 等后期需求

Vue

computed 与 watch 的区别

computed

  • 支持数据缓存
  • 内部数据改变也会触发
  • 不支持异步,异步无效
  • 适用于 一个属性由其他属性计算而来,依赖其他属性的场景

watch

  • 不支持数据缓存
  • 可以设置一个函数,带有两个参数,新旧数据
  • 支持异步
  • 监听数据必须是 data 中声明过或者父组件传递过来的 props 中数据
  1. immediate:组件加载立即触发回调函数执行
  • deep:深度监听

Vue.nextTick 原理和作用

  • Vue 异步执行 DOM 更新,观察数据变化,开启队列缓冲同一事件循环中所有数据改变
  • 同一个 watcher 被多次触发,只会被推入到队列中一次,避免不必要的计算和 DOM 操作
  • 在下一个事件循环 tick 中,Vue 刷新队列并执行实际(已去重)工作
  • 异步队列使用 Promise.then 和 MessageChannel,不支持环境使用 setTimeout(fn, 0)
  • 在需要立即更新 DOM 的场景中使用

Vue3.x 的新特性

API 风格

  • Vue2.x:Options API
  • Vue3.x:Composition API

生命周期

  • 组件生命周期
//Vue2.x:
beforeCreate
created
beforeMount
mounted
beforeUpdate
updated
beforeDestroy
destroyed
activated
deactivated
errorCaptured
//Vue3.x:
setup
onBeforeMount
onMounted
onBeforeUpdate
onUpdate
onBeforeUnmout
onUnmounted
onActivated
onDeactivated
onErrorCaptured
onRenderTriggered
onRenderTracked
  • 指令生命周期
//Vue2.x:
bind
inserted
update
componentUpdated
unbind
//Vue3.x:
beforeMount
mounted
beforeUpdate
updated
beforeUnmount
unmounted

数据

  • Vue2.x:data
  • Vue3.x
  1. ref 基础类型和对象的双向绑定
  2. reactive 对象的双向绑定 ---- 通过 toRefs 转为 ref

监听

  • Vue2.x:watch
  • Vue3.x:watchEffect
  1. 传入回调函数,不需要指定监听的数据源,自动收集响应式数据

  2. 可以从回调函数中,获取数据的最新值,无法获取原始值

slot

  • Vue2.x:通过 slot 使用插槽,通过 slot-scope 给插槽绑定数据
  • Vue3.x:v-slot: 插槽名 = 绑定数据名

v-model

  • Vue2.x:.async 绑定属性和 update:+ 属性名 事件
  • Vue3.x:无需 .async 修饰

新功能

  • Teleport:适合 Model 实现

  • Suspense:

    1. 一个组件两个 template

    2. 先渲染 #fallback 内容,满足条件再渲染 #default

    3. 适合异步渲染显示加载动画,骨架屏等

  • defineAsyncComponent:定义异步组件

  • 允许多个根节点

性能

  • 使用 Proxy 代替 definePoperty 和 数组劫持
  • 标记节点类型,diff 时,跳过静态节点
  • 支持 ES6 引入方法,按需编译
  • 配套全新的 Web 开发构建工具 Vite

React

React 生命周期

React 16.4 + 生命周期
Mounting
constructor
getDerivedStateFromProps
render
React 更新 DOM 和 refs
componentDidMount
Updation
props 变化 → getDerivedStateFromProps
setState() → getDerivedStateFromProps → shouldComponentUpdate
forceUpdate() → getDerivedStateFromProps
render
getSnapshotBeforeUpdate
React 更新 DOM 和 refs
componentDidUpate
Unmouting
componentWillUnmount

React 中使用 useEffect 如何清除副作用?

在 useEffect 中返回一个清除函数,名称随意,可以是匿名函数或箭头函数,在清除函数中添加 处理副作用的逻辑,如移除订阅等JavaScriptfunction component(props) {function handleStatusChange(status) { console.log(status.isOnine) }useEffect(() => {API.subscribe(props.id, handleStatusChange))}return function cleanup() {API.unsubscribe(props.id, handleStatusChange)}
}

对比 React 和 Vue 的 diff 算法

(1)相同点

  • 虚拟 Dom 只同级比较,不跨级比较
  • 使用 key 标记和复用节点,不建议使用数组索引 index 作为 key

(2)不同点

  • 顺序

     Vue:两端到中间React:从左到右
    
  • 节点元素类型相同,ClassName 不同

     Vue:不同类型元素,删除重新创建React:相同类型元素,修改
    
  • 节点类型

     Vue 3.x:VNode 创建时,即确定类型
    

React 中有哪几种类型的组件,如何选择?

  • 无状态组件

     更适合函数组件负责展示无状态,复用度高
    
  • 有状态组件

     函数组件 + hooks 或 类组件useState 或 声明 stateuseEffect 或 使用生命周期
    
  • 容器组件

     子组件状态提升到此,统一管理异步操作,如数据请求等提高子组件的复用度
    
  • 高阶组件

     接收组件,返回组件为原有组件增加新功能和行为代替 mixins,避免状态污染
    
  • 回调组件

     高阶组件的另一种形式将组件本身,通过 props.children 或 prop 属性 传递给子组件适合不能确定或不关心传给子组件数据的场景,如路由,加载组件的实现
    

Css

如何实现单行居中,多行居左?

父级元素:
CSStext-align: center;自身元素:
CSStext-align: left;
display: inline-block;

如何实现 1px 边框?

方法一:border-width
CSS.border {border: 1px solid;
}
@media screen and {min-resolution: 2dppx} {.border {border: 0.5px solid;}
}
@media screen and (min-resolution: 3dppx) {.border {border: 0.333333px solid;}
}方法二:伪类 + transform
CSSdiv::after {content: '';display: block;border-bottom: 1px solid;
}
@media only screen and (min-resolution: 2dppx) {div::after {-webkit-transform: scaleY(.5);transform: scaleY(.5);}
}
@media only screen and (min-resolution: 3dppx) {div::after {-webkit-transform: scaleY(.33);transform: sacleY(.33);}
}

多方法实现高度 100% 容器

1)百分比<style>
html, body {height: 100%;
}
div {height: 100%;background-color: azure;
}
</style>
<div></div>2)相对单位<style>
div {height: 100vh;background-color: azure;
}
</style>
<div></div>3)calc<style>
html, body{height: 100%;
}
div {height: calc(100%)
}
</style>
<div></div>

多方法实现圆角边框

背景图片:绘制圆角边框的图片,4个圆角 + 4个边框的小图片,拼成圆角边框
border-radius: 5px
clip-path: inset(0 round 5px)

多方法实现文字描边

text-shadow: 0 0 1px black;
-webkit-text-stroke: 1px black;
position: relative / position: absolute 子绝父相

JavaScript

es3相关题

   a = [],a.push(...[1, 2, 3]) ,a = ?a = [1, 2, 3],考核点如下:[].push:调用数组 push 方法apply:第一参数:指定 push 执行时的 this,即正在调用 push 的对象为数组 a第二参数:传入数组或类数组对象作为参数数组,展开作为 push 的参数列表push的语法:支持将一个或多个元素添加到数组末尾arr.push(element1, ..., elementN)
   a = ?, a==1 && a==2 && a==3 成立== 会触发隐式转换,=== 不会对象转字符串先尝试调用对象的 toString()对象无 toString()或 toString 返回非原始值,调用 valueOf() 方法将该值转为字符串,并返回字符串结果否则,抛出类型错误对象转数字先尝试调用对象的 valueOf(),将返回原始值转为数字对象无 valueOf() 或 valueOf 返回不是原始值,调用 toString() 方法,将返回原始值转为数字否则,抛出类型错误对象转布尔值True代码JavaScriptconst a = {count: 0,valueOf() {return ++this.count}}数组隐式转换会调用数组的 join 方法,改写此方法JavaScriptconst a = [1, 2, 3]a.join = a.shift
   null == undefined 结果比较 nullundefined 的时候,不能将 nullundefined 隐式转换,规范规定结果为相等
  • 常见的类型转换
类型 to Boolean to Number to String
Boolean true true 1 “true”
Boolean false false 0 “false”
Number 123 true 123 “123”
Number Infinity true Infinity “Infinity”
Number 0 false 0 “0”
Number NaN false NaN "NaN "
String ’ ’ false 0 “”
String '123 ’ true 123 “123”
String '123abc ’ true NAN “123abc”
String 'abc ’ true NAN “abc”
Null null false 0 “null”
Undefined Undefined false NAN “Undefined”
Function function() {} true NAN “function(){}”
Object { } true NAN “[object Object]”
Array [ ] true 0 " "
Array [’ abc’ ] true NAN " abc"
Array [’ 123’ ] true 123 " 123"
Array [’ 123’,‘abc’ ] true NAN " 123,abc"
对比 get 和 Object.defineProperty相同点都可以定义属性被查询时的函数不同点在 classes 内部使用get 属性将被定义到 实例原型Object.defineProperty 属性将被定义在 实例自身
对比 escape encodeURI 和 encodeURIComponentescape对字符串编码ASCII 字母、数字 @ * / + - _ . 之外的字符都被编码encodeURI对 URL 编码ASCII 字母、数字 @ * / +~ ! # $ & () =, ; ?- _ . '之外的字符都被编码encodeURIComponent对 URL 编码ASCII 字母、数字 ~ ! * ( ) - _ . ' 之外的字符都被编码

事件

事件传播的过程

  • 事件冒泡

     DOM0 和 IE支持(DOM1 开始是 W3C 规范)从事件源向父级,一直到根元素(HTML)某个元素的某类型事件被触发,父元素同类型事件也会被触发
    
  • 事件捕获

     DOM2 支持从根元素(HTML)到事件源某个元素的某类型事件被触发,先触发根元素,再向子一级,直到事件源
    
  • 事件流

     事件的流向:事件捕获 → 事件源 → 事件冒泡
    
  • 阻止事件冒泡

     标准:event.stopPropagation()IE:event.cancelBubble = true
    

Event Loop 的执行顺序?

  • 宏任务

     Task Queue常见宏任务:setTimeout、setInterval、setImmediate、I/O、script、UI rendering
    
  • 微任务

     Job Queue常见微任务:浏览器:Promise、MutationObserverNode.js:process.nextTick
    
  • 执行顺序

     首先执行同步代码,宏任务同步栈为空,查询是否有异步代码需要执行执行所有微任务执行完,是否需要渲染页面重新开始 Event Loop,执行宏任务中的异步代码
    

为什么 Vue.$nextTick 通常比 setTimeout 优先级高,渲染更快生效?

  • Vue.$nextTick 需要异步执行队列,异步函数的实现优先使用

     Promise、MutationObserver、setImmediate都不兼容时,使用 setTimeout
    
  • Promise、MutationObserver、setImmediate 是微任务

  • setTimeout、UI rendering 是宏任务

  • 根据执行顺序

     Promise、MutationObserver、setImmediate 创建微任务,添加到当前宏任务微任务队列。队列任务执行完,如需渲染,即可渲染页面setTimeout 创建宏任务,如果此时正在执行微任务队列,需要等队列执行完,渲染一次后,重新开始 Event Loop,执行宏任务中的异步代码后再渲染
    

一些ES6新特性

   letconstPromiseClass箭头函数函数参数默认值模版字符串解构赋值展开语法构造数组,调用函数时,将 数组表达式 或 string 在语法层面展开对象属性缩写键名和键值相同函数省略 function模块化

列举类数组对象

  1. 定义

    拥有 length 属性
    若干索引属性的任意对象
    
  2. 举例

    NodeList
    HTML Collections
    字符串
    arguments
    $ 返回的 jQuery 原型对象
    
  3. 类数组对象转数组

    新建数组,遍历类数组对象,将每个元素放入新数组
    Array.prototype.slice.call(ArrayLike) 或 [].slice.call(ArrayLike)
    Array.from(ArrayLike)
    apply 第二参数传入,调用数组方法
    

闭包

什么是闭包?

闭包是由函数以及声明该函数的词法环境组合而成

  • 一个函数和对其周围状态(词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包
  • 可以在内层函数中访问到其外层函数的作用域
  • 每当创建一个函数,闭包就会在函数创建的同时被创建出来

什么是词法?

  • 词法,英文 lexical ,词法作用域根据源代码声明变量的位置来确定变量在何处可用

    嵌套函数可访问声明于它们外部作用域的变量

什么是函数柯里化?

 函数调用:一个参数集合应用到函数部分应用:只传递部分参数,而非全部参数柯里化(curry):使函数理解并处理部分应用的过程保存调用 curry 函数时传入的参数,返回一个新函数结果函数在被调用后,要让新的参数和旧的参数一起应用到入参函数

bind / apply / call / new

手写bind

  • 第一个参数接收 this 对象

  • 返回函数,根据使用方式

      直接调用改变 this 指向拼接参数调用函数构造函数不改变 this 指向,忽略第一参数拼接参数new 函数
    
Function.prototype.myBind = function(_this, ...args) {const fn = thisreturn function F(...args2) {return this instanceof F ? new fn(...args, ...args2): fn.apply(_this, args.concat(args2))}
}
//使用
function Sum (a, b) {this.v= (this.v || 0)+ a + breturnthis
}
const NewSum = Sum.myBind({v: 1}, 2)
NewSum(3) // 调用:{v: 6}
new NewSum(3) // 构造函数:{v: 5} 忽略 myBind 绑定this

手写 call

  • 第一参数接收 this 对象
  • 改变 this 指向:将函数作为传入 this 对象的方法
  • 展开语法,支持传入和调用参数列表
  • 调用并删除方法,返回结果
Function.prototype.myCall = function(_this, ...args) {if (!_this) _this = Object.create(null)_this.fn = thisconst res = _this.fn(...args)delete _this.fnreturn res
}
// 使用
function sum (a, b) {return this.v + a + b
}
sum.myCall({v: 1}, 2, 3) // 6

手写apply

  • 第一参数接收 this 对象
  • 改变 this 指向:将函数作为传入 this 对象的方法
  • 第二个参数默认数组
  • 展开语法,支持调用参数列表
  • 调用并删除方法,返回结果
Function.prototype.myApply = function(_this, args = []) {if (!_this) _this = Object.create(null)_this.fn =thisconst res = _this.fn(...args)delete _this.fnreturn res
}
// 使用
function sum (a, b) {return this.v + a + b
}
sum.myApply({v: 1}, [2, 3]) // 6

手写new

  • 第一参数作为构造函数,其余参数作为构造函数参数
  • 继承构造函数原型创建新对象
  • 执行构造函数
  • 结果为对象,返回结果,反之,返回新对象
function myNew(...args) {const Constructor = args[0]const o = Object.create(Constructor.prototype)const res = Constructor.apply(o, args.slice(1))return res instanceof Object ? res : o
}
// 使用
function P(v) {this.v = v
}
const p = myNew(P, 1) // P {v: 1}

手写防抖

  • 声明定时器

  • 返回函数

  • 一定时间间隔,执行回调函数

  • 回调函数

      已执行:清空定时器未执行:重置定时器
    
function debounce(fn, delay) {let timer = nullreturn function (...args) {if (timer) clearTimeout(timer)timer = setTimeout(() => {timer = nullfn.apply(this, args)}, (delay + '') | 0 || 1000 / 60)}
}

手写节流

  • 声明定时器

  • 返回函数

  • 一定时间间隔,执行回调函数

  • 回调函数

      已执行:清空定时器未执行:返回
    
function throttle(fn, interval) {let timer = nullreturn function (...args) {if (timer) returntimer = setTimeout(() => {timer = nullfn.apply(this, args)}, (interval +'')| 0 || 1000 / 60)}
}

原型链

对比各种继承

(1)原型链继承

子类原型指向父类实例

function Parent() {}
function Child() {}
Child.prototype = new Parent()
const child = new Child()
  • 好处:

      子类可以访问到父类新增原型方法和属性
    
  • 坏处:

      无法实现多继承创建实例不能传递参数
    

(2)构造函数

function Parent() {}
function Child(...args) {Parent.call(this, ...args) // Parent.apply(this, args)
}
const child = new Child(1)
  • 好处:

      可以实现多继承创建实例可以传递参数
    
  • 坏处:

      实例并不是父类的实例,只是子类的实例不能继承父类原型上的方法
    

(3)组合继承

function Parent() {}
function Child(...args) {Parent.call(this, ...args)
}
Child.prototype = Object.create(Parent.prototype)
Child.prototype.constructor = Child
const child = new Child(1)
  • 好处:

      属性和原型链上的方法都可以继承创建实例可以传递参数
    

(4)对象继承
斜体样式
Object.create

JavaScriptconst Parent = { property: 'value', method() {} }
const Child = Object.create(Parent)
create
JavaScriptconst Parent = { property: 'value', method() {} }
function create(obj) {function F() {}F.prototype = objreturn new F()
}
const child  = create(Parent)
  • 好处:

    可以继承属性和方法

  • 坏处:

    创建实例无法传递参数
    传入对象的属性有引用类型,所有类型都会共享相应的值
    (5)寄生组合继承

JavaScriptfunction Parent() {}
function Child(...args) {Parent.call(this, args)
}
function create(obj) {function F() {}F.prototype =  objreturn F()
}
function extend(Child, Parent) {const clone = create(Parent.prototype)clone.constructor = ChildChild.prototype = clone
}
extend(Child, Parent)
const child = new Child(1)

(6)ES6继承

JavaScriptclass Parent {constructor(property) {this.property = property}method() {}
}
class Child extends Parent {constructor(property) {super(property)}
}

模块化

webpack 中 loader 和 plugin 的区别?

loader

  • 在打包前或期间调用
  • 根据不同匹配条件处理资源
  • 调用顺序与书写顺序相反
  • 写在前面的接收写在后面的返回值作为输入值
    plugin
  • 基于 Tapable 实现
  • 事件触发调用,监听 webpack 广播的事件
  • 不同生命周期改变输出结果

如何自定义一个 webpack 插件?

  • 声明一个自定义命名的类或函数
  • 在原型中新增 apply 方法
  • 声明由 Compiler 模块暴露的生命周期函数
  • 使用 webpack 提供的 API 或 自行处理内部实例的数据
  • 处理完成后,调用 webpack 提供的回调函数
    示例:

实现一个 MyPlugin,获取指定图片,新增静态资源到本地


class MyPlugin { // 声明类apply(compiler) { // 新增 apply 方法// 声明生命周期函数compiler.hooks.additionalAssets.tapAsync('MyPlugin', (compilation, callback) => {download('https://img.shields.io/npm/v/webpack.svg', res => {if (res.status === 200) {// 调用 APIcompilation.assets['webpack-version.svg'] = toAsset(res)// 异步处理后,调用回调函数callback()} else {callback(new Error('[webpack-example-plugin] Unable to download the image'))}})})}
}

对比 import、import() 和 requrie

import import() require
规范 ES6Module ES6Module CommonJS
执行阶段 静态 编译阶段 动态 执行阶段 动态 执行阶段
顺序 置顶最先 异步 同步
规范 ES6Module ES6Module CommonJS
规范 ES6Module ES6Module CommonJS
规范 ES6Module ES6Module CommonJS

算法

位运算

什么是原码、反码、补码?

原码、反码和补码,均有 符号位数值位 两部分

符号位:用 0 表示正,用 1 表示负

在计算机系统中

  • 数值一律用补码来表示和存储,好处

      符号位和数值位统一处理加法和减法统一处理
    

正数

原码:符号位 0
反码:与原码相同
补码:与原码相同

负数

原码:符号位 1
反码:符号位不变,数值位取反
补码:符号位不变,数值位取反 +1

0

原码:+0 0000 0000 -0 1000 0000
反码:+0 0000 0000 -0 1111 1111
补码:+0 0000 0000 -0 0000 0000 相同

位运算求绝对值?

数在计算机中,用补码表示

负数的补码 = 负数的原码 → 符号位不变,其余位取反,+1

-2
原码:1000 0010
反码:1111 1101
补码:1111 1110(反码加一,计算机实际存储的值)
取反:0000 0001
加一:0000 0010 = 2

解法一:根据符号位,正数返回本身,负数返回 取反 + 1

const abs = x => {
const y = x >>> 31 // 看符号位
return y === 0 ? x : ~x + 1
}

解法二:任何数与 -1 异或 ^ 运算,相当于取反。任何数与 0 异或 ^ 运算,还是本身

-1
原码:1000 0001
反码:1111 1110
补码:1111 1111

无符号右移

const abs = x => {
const y = x >>> 31
return (x ^ -y) + y
}

有符号右移

const abs = x => {
const y = x >> 31
return (x ^ y) - y
}

数组

去除数组中的指定元素

输入:a = [‘1’, ‘2’, ‘3’, ‘4’, ‘5’, ‘6’] target = ‘4’

输出:a = [‘1’, ‘2’, ‘3’, ‘5’, ‘6’]

方法一:

const removeByValue = (a, target) => {for (let i = 0; i < a.length; i++) {if (target === a[i]) {a.splice(i, 1)}}return a
}

方法二:

const removeByValue = (a, target) => a.splice(a.findIndex(v => v === target), 1)

方法三:

const removeByValue = (a, target) => {let j = 0, i = -1while (++i < a.length) {if (a[i] === target) i++a[j++] = a[i]}a.length--return a
}

数组去重方法

function unique (arr) {
return Array.from(new Set(arr))
}

  • Set 去重 + 扩展运算符 …
function unique (arr) {return [...new Set(arr)]
}
  • Object
function unique (arr) {const h = Object.create(null)arr.forEach(v => h[v] = 1)return Object.keys(h).map(v => v | 0)
}
  • Map
function unique (arr) {const h = new Maparr.forEach(v => h.set(v, 1))return Array.from(h.keys())
}
  • for 循环 + splice
function unique (arr) {for (let i = 0; i < arr.length; i++) {for (let j = i + 1; j < arr.length; j++) {if (arr[i] === arr[j]) {arr.splice(j, 1)j--}}}return arr
}
  • Sort 排序 + 相邻相同 splice
function unique (arr) {arr.sort()for (let i = 0; i < arr.length - 1; i++) {if (arr[i] === arr[i + 1]) {arr.splice(i, 1)i--}}return arr
}
  • filter + indexOf
function unique (arr) {return arr.filter((v, index, ar) => ar.indexOf(v) === index)
}
  • filter + hasOwnproperty
function unique (arr) {const h = {} // 注意只有 {} 才有 hasOwnPropertyreturn arr.filter(v => !h.hasOwnProperty(v) && (h[v] = 1))
}
  • indexOf + 辅助数组
function unique (arr) {const r = []arr.forEach(v => r.indexOf(v) === -1 && r.push(v)) return r
}
  • includes + 辅助数组
function unique (arr) {const r = []arr.forEach(v => !r.includes(v) && r.push(v))return r
}function unique (arr) {const r = []arr.forEach(v => !r.includes(v) && r.push(v))return r
}

判断一个对象是不是数组 Array

  • isPrototypeOf

      测试一个对象是否在另一个对象的原型链上prototype 不可省略
    
 function isArray(o) {return Array.prototype.isPrototypeOf(o)
}
  • instanceof
    用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上
function isArray(o) {return o instanceof Array
}
  • Array.isArray
    用于确定传递的值是否是一个 Array
function isArray(o) {return Array.isArray(o)
}
  • Object.prototype.toString
    方法返回一个表示对象的字符串
function isArray(o) {return Object.prototype.toString.call(o) === '[object Array]'
}

移动零

问题
给定一个数组 nums,编写一个函数所有 0 移动到数组的末尾,同时保持非零元素的相对顺序

示例:

输入:[0, 1, 0, 3, 12]
输出:[1, 3, 12, 0, 0]
说明:
(1)必须在原数组上操作,不能拷贝额外的数组

(2)尽量减少操作次数

解析
(1) 辅助数组

const moveZeros = a => {const tmp = new Uint32Array(a.length)for (let i = 0, j = 0; i < a.length; i++) if (a[i]) tmp[j++] = a[i]return tmp
}

(2) 双指针交换

const moveZeros = a => {let i = j = -1while (++i < a.length) if (a[i]) a[++j] = a[i]while (++j < a.length) a[j] = 0return a
}

(3) Sort 排序

const moveZeros = a => a.sort((a, b) => -(b === 0 ^ 0))

空间复杂度为 O(1) 的中序遍历(莫里斯)遍历

const isValidBST = (root, l = -Infinity) {while(root) {if (root.left) {const p = root.leftwhile (p.right && p.right !== root) p = p.rightif (p.right === null) p.right = root, root = root.leftelse {root = root.rightp.right= null
}} else {root= root.right}}
}

递归

求最大公约数

辗转相除法 (又称 欧几里得算法)

  • 递归
function gcd(a, b) {const t = a % bif (t === 0) return breturn gcd(b, t)
}
  • 迭代
function gcd(a, b) {let twhile (t = a % b) {a = bb = t}return b
}

更相减损法(又称 九章算术)

  • 递归
function gcd(a, b) {if (a === b) return ba > b ? a -= b : b -= areturn gcd(a, b)
}

排序

插入排序

const sort = a => {for (let i = 1; i < a.length; i++)for (let j = i; j-- && a[j + 1] < a[j];)[a[j + 1], a[j]] = [a[j], a[j + 1]]return a
}

快速排序

const sort = (a, s = 0, e = a.length - 1) => {if (s >= e) returnlet l = s, r = ewhile (l < r) {while (l < r && a[r] >= a[s]) r--while (l < r && a[l] <= a[s]) l++[a[l], a[r]] = [a[r], a[l]]}[a[l], a[s]] = [a[s], a[l]]sort(a, s, l - 1)sort(a, l + 1, e)return a
}

归并排序


const sort = (a, l = 0, r = a.length - 1) => {if (l === r) return const m = l + r >>> 1, t = []sort(a, l, m)sort(a, m + 1, r)let p1 = l, p2 = m + 1, i = 0while (p1 <= m || p2 <= r) t[i++] = p2 > r || p1 <= m && a[p1] < a[p2] ? a[p1++] : a[p2++]for (i = 0; i < t.length; i++) a[l + i] = t[i]return a
}

冒泡排序

const sort = (a) => {for(let i = 0; i < a.length - 1; i++)for (let j = 0; j < a.length - 1 - i; j++)if (a[j] > a[j + 1])[a[j], a[j + 1]] = [a[j + 1], a[j]]return a
}

全栈

node.js

express 中 next 的作用?

next 是 中间件函数的第三参数

  • 执行 next(),控制权交给下个中间件
  • 不执行
    终止请求
    挂起请求

对比 express 和 koa?

  • Handler 处理方式

      Express:回调函数Koa:Async / Await
    
  • 中间件

      Express:同一线程,线性传递Koa:洋葱模型,级联传递
    
  • 响应机制

      Express:res.send 立即响应Koa:设置ctx.body,可累加,经过中间件后响应
    

计算机网络

对比持续通信的方法

  • 轮询

      通过 setInterval 或 setTimeout 定时获取并刷新页面上的数据定时查询,不一定有新数据并发较多时,增加服务器负担
    
  • 长连接

      页面其纳入 iframe,将 src 设为长连接减少无用请求并发较多时,增加服务器负担
    
  • 长轮询

      服务端收到请求后,hold 住链接,直到新消息返回时才响应减少无用请求返回数据顺序无保证
    
  • Flash Socket

      客户端通过嵌入 Socket 类 Flash与服务器端的 Socket 接口通信真正即时通信非 HTTP 协议,无法自动穿越防火墙
    
  • WebSocket

      在客户端和服务器间打开交互式通信绘话兼容 HTTP 协议。与 HTTP 同属应用层。默认端口是 80 和 443建立在 TCP 协议基础之上,与 HTTP 协议同属于应用层数据格式轻量,性能开销小,通信高效可以发送文本,也可以发送二进制数据没有同源限制协议表示符:ws,加密 wss
    
  • socket.io

      跨平台的 WebSocket 库,API 前后端一致,可以触发和响应自定义事件
    
// 服务端
const io = require("socket.io")(3000)
io.on('connection', socket => {socket.on('update item', (arg1, arg2, callback) => {console.log(arg1, arg2)callback({ status: 'fulfilled' })})
})
// 客户端
const socket = io()
socket.emit('update item', "1", { name: 'updated' }, res => {console.log(res.status) // ok
})

网络结构按五层和七层分别是

  • TCP / IP 体系结构

      网络接口层网际层 IP运输层 TCP 或 UDP应用层(TELNET FTP SMTP等)
    
  • 五层

      物理层数据链路层网络层运输层应用层
    
  • 七层:Open System Inerconnect Reference Model 开放式系统互联通信参考模型

      物理层数据链路层网络层传输层会话层表达层应用层
    

什么是 TCP 三次握手,为什么要三次握手?

(1)什么是 TCP 三次握手?

  • 起初
    客户端 CLOSED
    服务端 CLOSED

  • 第一次握手
    客户端发送请求报文

      传输自身通讯初始序号客户端 SYN-SENT
    
  • 第二次握手
    服务器接收请求报文

    1.同意连接

          传输自身通讯初始序号服务端 SYN-RECEIVED
    

    2.拒绝连接

         服务端 REFUSED
    
    • 第三次握手
      1.客户端接收应答报文

      客户端发送确认报文
      客户端 ESTABLISHED
      2.服务端接收确认报文

      服务端 ESTABLISHED

(2)为什么要三次握手?

客户端首次发送请求无应答,TCP 启动超时重传
服务器收到重传的请求,建立连接,接收数据,关闭连接
服务器收到客户端首次发送请求,再次建立连接,但客户端已经关闭连接
需要三次握手,客户端发送确认报文后再建立连接,避免重复建立连接

浏览器有哪些请求方法?

方法 描述 请求体 响应体 支持表单 安全 幂等 可缓存
GET 请求资源
HEAD 请求资源头部
POST 发送数据 数据类型由Content-Type 指定 响应头包含 expires 和 max-age
PUT 发送负载 创建或替换目标资源
DELETE 删除资源 不限 不限
CONNECT 创建点到点沟通隧道
OPTIONS 检测服务器支持方法
TRACE 消息环路测试 多用于路由检测
PATCH 部分修改资源

提交表单的内容类型有哪些?

  • application/x-www-form-urlencoded:初始的默认值

Content-Type:application/x-www-form-urlencoded

key1=value1&key2=value2

  • multipart/form-data:适用于使用 标签上传的文件

Content-Type:multipart/form-data; boundary=------数据边界值

------数据边界值
Content-Disposition: form-data; name=“key1”
value1
------数据边界值
Content-Disposition: form-data; name=“key2”
value2

  • text/plain:HTML5 引入类型

Content-Type:text/plain

key1=value1
key2=value2

docker 与虚拟机区别

启动速度

  • Docker:秒级启动
  • 虚拟机:几分钟启动

需要资源

  • Docker:操作系统级别虚拟化,与内核直接交互,几乎没有性能损耗

  • 虚拟机:

      通过虚拟机监视器(Virtual machine monitor,VMM,Hypervisor)厂商:Citrix XenServer,Hyper-V,开源 KVM 、Xen、VirtualBSD
    

轻量

  • Docker:内核与应用程序库可共享,占用内存极小,资源利用率高
  • 虚拟机:同样硬件环境,Docker 运行的镜像数量远多于 虚拟机数量

安全性

  • Docker:安全性更弱。租户 root 与宿主机 root 等同,有提权安全风险

  • 虚拟机:

      租户 root 权限与宿主机的 root 虚拟机权限分离用如 Intel 的 VT-d 和 VT-x 的 ring-1 硬件隔离技术,虚拟机难以突破 VMM 直接与宿主或彼此交互
    

可管理型

  • Docker:集中化管理工具还不算成熟
  • 虚拟机:拥有相对完备的集中化管理工具

高可用和可恢复性

  • Docker:依靠 快速重新部署 实现
  • 虚拟机:负载均衡、高可用、容错、迁移、数据保护,VMware可承诺 SLA(服务级别协议)99.999% 高可用

快速创建、删除

  • Docker:秒级别,开发、测试、部署更快
  • 虚拟机:分钟级别

交付、部署

  • Docker:在 Dockerfile 中记录了容器构建过程,可在集群中实现快速分发和快速部署
  • 虚拟机:支持镜像

对比 Intel 的 VT-x,VT-d,VT-c

VT-x

运行 ESXI 上的 64位 Guest OS 基本指令
Intel 运用Virtualization 虚拟化技术中的指令集
减少 VMM 干预,硬件支持 VMM 与 Guest OS
需要 VMM 干预,更快速、可靠、安全切换
更灵活、更稳定

VT-d

使一个 Guest OS 独占并直接存取硬件设备,加快读写速度
开启条件:北桥芯片支持,BIOS 开启

VT-c

  • Virtual Machine Direct Connect

      虚拟机的虚拟网络卡传送透过 VMM 来进行传输Guest OS 可以直接对 实体网络 I/O 进行存取加强 VT-d,让多个虚拟机与实体 I/O 装置同时建立通道
    
  • Virtual Machine Direct Queues

      由 VMM 管理的虚拟化 Switch 转送封包给虚拟机封包流向哪个虚拟机,需要额外 CPU 资源透过网卡内建 Layer2 classifier / sorter 加速网络资料传送在芯片里安排并通过队列排序好封包给虚拟机,不需要 VMM 支持大大降低网络负载和 CPU 使用率
    

对比 Cookie、LocalStorage、SessionStorage、Session、Toke

  • Cookie

      保存位置:客户端生命周期:expires 前有效,不设置 会话期间有效存储大小:一般 4KB数据类型:字符串特点:请求头 cookie ,同域名每次请求都附加响应头 set-cookie 设置 cookie
    
  • LocalStorage

      保存位置:客户端生命周期:不清空缓存,一直有效存储大小:一般 5MB数据类型:字符串SessionStorage保存位置:客户端生命周期:会话期间有效存储大小:一般 5MB数据类型:字符串
    
  • Seesion

      保存位置:服务端,sessionid 存在 cookie 或 跟在 URL 后生命周期:默认 20分钟,可更改。清空 cookie 或 更改 URL 传参,影响 Session存储大小:不限制数据类型:字符串、对象、数组,序列化后以字符串存储
    
  • Token

      保存位置:客户端 Cookie / WebStorage / 表单 等生命周期:根据存储位置决定存储大小:根据存储位置决定数据类型:字符串组成uid 用户身份标识time 时间戳sign 签名其他参数
    
  • JWT - JSON Web Token

      特点将部分用户信息存储本地,避免重复查询数据库组成Header(头部)alg 表示签名的算法,默认是 HMAC SHA256 (HS256)typ 表示令牌的类型,JWTPayload(负载)7 个官方字段jti 编号iss 签发人sub 主题aud 受众exp 过期时间nbf 生效时间iat 签发时间私有字段name 姓名admin 是否管理员Signature(签名)secret 密钥使用指定 alg 签名算法,生成签名HMAC SHA256(btoa(Header) + '.' + btoa(Payload), secret)算出签名
    

什么是 Service Worker?

  • Web 应用程序、浏览器与网络之间的代理服务器
  • 拦截网络请求,并根据网络采取适当动作,更新服务器资源
  • 完全异步,不阻塞 JavaScript 线程,不能访问 DOM
  • 提供入口以推送通知和访问后台同步 API
  • 用于离线缓存,后台数据同步,响应来自其它源的资源请求,集中接收成本高的数据更新

性能

如何测量并优化前端性能?

(1)前端页面加载阶段

  • 网络
    重定向
    redirectStart
    redirectEnd
    DNS 查询
    domainLookupStart
    domainLookupEnd
    TCP 连接
    connectStart
    conentEnd
  • 请求响应
    发送请求
    requestStart
    收到响应
    responseStart
    responseEnd
  • 解析渲染
    DOM 解析
    domLoading
    domInteractive
    DOM 渲染
    domContentLoadedEventStart
    domContentLoadedEventEnd
    domComplete
    (2)衡量性能的时间点
    首字节时间:收到服务器返回第一个字节的时间。反映网络后端的整体响应耗时
    白屏时间:第一个元素显示时间
    首屏时间:第一屏所有资源完整显示时间。SEO 指标,百度建议2秒内为宜,不超过3秒
    (3)测量性能的工具
    Chrome 浏览器 ,开发者工具
    Performance:通过录制页面加载过程,可以获得加载,脚本执行,渲染,布局等时间分布情况
    Lighthouse:可以分别模拟移动端和电脑端打开URL,从性能、可访问性、最佳实践(安全、用户体验、函数是否符合标准等)、SEO、单页应用等角度,获得修改建议
    NodeJS
    SiteSpeed:

npm i -g sitespeed.io && sitespeed.io https://leetcode-cn.com
线上测试工具
Speedcurve:https://speedcurve.com
webpagetest:https://www.webpagetest.org
(4)性能优化方法
DNS 预读取:

<link rel="dns-prefetch" href="//leetcode-cn.com" />
  • 预加载
    Image / Audio
    prefetch:
<link rel="prefetch" href="//leetcode-cn.com" />
  • 懒加载
    图片懒加载
    DOM懒加载
  • 渲染
    减少重排
    减少重绘
    节流
    防抖
  • 缓存
    离线缓存
    HTTP 缓存
  • 图片
    合并图片请求
    Base64 将图片嵌入 CSS
    SVG sprites
    响应式图片:不同分辨率和 DPR 下显示不同图片
    媒体查询
    IMG 的 srcset 属性
    图片压缩
    image-webpack-loader、imagemin-webpack-plugin 工程化压缩图片工具
    WEBP 和 AVIF 图片格式
  • HTTP
    使用 HTTP2 / HTTP3
    使用 CDN
    使用 gzip / br 压缩静态资源

SEO

前端中有哪些 SEO 优化手段?

  • 文字
    字号 14px 以上,16px 为宜,避免小于 12px,有行距、换行和段落
    避免使用 visibility:hidden,display: none, 绝对定位,与背景相同颜色,堆砌关键词,隐藏主要内容

  • 图片
    Logo 的 DIV 中写关键词,设置 text-ident 为负数隐藏
    图片添加 width 和 height,避免读取元数据,再重排
    图片添加 alt,描述图片内容,便于搜索引擎蜘蛛理解,提升可访问性
    主要图片与内容相关,不要过长或过窄,正方形为宜
    主要图片设置 src 属性,避免全部图片都使用懒加载
    图片可以点击放大,多张图片间可以切换

  • 适配
    1.独立 H5 网站
    H5移动版与PC版域名不同,移动版子域名,推荐使用 m.x.com 等移动网站常用域名
    向搜索引擎提交适配规则:PC版和H5移动版组成一一对应的URL对或正则匹配关系
    不同域名,使用不同蜘蛛抓取
    2.代码适配
    H5 移动版和PC版域名相同,返回代码不同
    后端根据 User-Agent,返回不同的代码
    添加响应头:Vary: User-agent
    同一URL,蜘蛛应使用不同UA或不同蜘蛛多次抓取
    3.自适应
    H5 移动版和PC版 域名相同,返回代码相同
    前端通过相对单位、媒体查询、srcset 实现响应式或自适应布局
    同一URL,蜘蛛可以只抓取一次

  • SSR:Server Side Render 服务端渲染

安全

什么是帆布指纹?

const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
const txt = 'canvasfingerprinting'
ctx.fillText(txt, 0, 0)
const b64 = canvas.toDataURL().replace('data:image/png;base64,', '') // 返回一个包含图片的 data URI,并替换 Mine-type,返回 base64 编码
const bin = atob(b64) // 函数能够解码 base64 编码的字符串数据
const canvasFingerprinting = bin2hex(bin.slice(-16, -12)) // 将 Unicode 编码转为十六进制

对比各种分布式 ID 的生成方式

  • UUID
    生成简单,本地生成
    无序,无意义

  • 数据库自增ID
    auto_increment 实现简单,单调自增,查询快
    数据库服务器宕机风险
    使用 SELECTLAST_INSERT_ID() 代替 max(id) 提高高并发时的查询效率
    不同数据库服务器,设置不同自增起始值和步长

  • 数据库自增ID段

CREATE TABLE ids_increment (
type int(8) NOT NULL COMMENT ‘业务类型’,
max_id int(8) NOT NULL COMMENT ‘当前业务的最大ID’,
step int(8) NOT NULL COMMENT ‘当前业务的ID段步长’,
version ini(8) NOT NULL COMMENT ‘当前业务的版本号,每次分配 +1,乐观锁’
)

  • Redis
    set 字段的初始值 incr 该字段,每次 +1
    使用 RDB 定时持久化
    使用 AOF 命令持久化

  • 雪花算法
    64 位 ID:符号位(1 位) + 时间戳(41 位) + 机器 ID(5 位) + 数据中心 ID(5 位)+ 自增值(12 位)

各种跨域方法

(1)跨域
协议、域名、端口不同,需要跨域

(2)跨域解决方案

  • jsonp:JSON with Padding
<script> 标签没有同域限制
服务端返回页面上 callback 包裹的 json 数据
兼容性好
仅支持 GET
  • CORS:Cross-origin resource sharing 跨域资源共享
    请求类型:
    简单请求 :
    满足以下 2 条件
GET HEAD POST
Content-Type
application/x-www-form-urlencoded
multipart/form-data
text/plain
** 复杂请求** :
不满足以上2条件
需发送 OPTION 预检请求,查询服务器支持的方法
按请求类别处理const express = require('express')
const app = express()
const whiteList = ['http://localhost']
app.use((req, res, next) => {const origin = req.headers.originif (whiteList.includes(origin)) {// 允许访问源,附带凭证请求时,必须指定 URI。相反,可设置为 *res.setHeader('Access-Control-Allow-Origin', origin)// 允许请求头,逗号隔开res.setHeader('Access-Control-Allow-Headers', 'authorization, username')// 允许请求方法,逗号隔开res.setHeader('Access-Control-Allow-Methods''GET, HEAD, POST, OPTIONS')/* 允许凭证客户端需配置 const xhr = new XMLHttpRequest()xhr.withCredentials = true */res.setHeader('Access-Control-Allow-Credentials', true)// 预检请求的返回结果,允许请求头和请求方法可以被缓存多久,缓存期间不再发送预检请求,单位秒res.setHeader('Access-Control-Allow-Max-Age', 10)// 允许响应头res.setHeader('Access-Control-Expose-Headers', 'authorization, username')if (req.method === 'OPTIONS') {res.end() // 预检请求直接返回空响应体}}
})
  • postMessage
    window属性
    跨窗口,跨框架frame、iframe,跨域
    允许不同源脚本采用异步方式进行有限通信
otherWindow.postMessage(message, targetOrigin, [transfer])
// otherWindow:
iframe.contentWindow 属性
window.open 返回
window.frames 访问
window.onmessage = e => console.log(e.data) // 接收返回数据
  • Websocket
    基于 TCP
    全双工通信
    应用层协议
// 客户端
const socket = new WebSocket('ws://localhost:3000')
socket.onopen = () => socket.send('message') // 向服务器发送数据
soket.onmessage = e => console.log(e.data) // 接收服务器返回数据
// server.js
const express = require('express')
const app = express()
const ws = require('ws')
const wss = new ws.Server({port: 3000})
wss.on('connection', ws => {ws.on('message', data => console.log(data))
})
  • 代理服务器转发
代理服务器设置 CORS 请求头字段nginxadd_headerkangle回应控制,增加表,标记模块,add_headernodejsresponse.writeHead
代理服务器向源服务器继续请求nginx七层 HTTP 代理:配置 httphttp {server {listen 80;location / {proxy_pass http://127.0.0.1:3000}}
}
四层 TCP 代理:配置 streamsteam {upstream proxyServer {server 127.0.0.1:3000;}server {listen 80;proxy_pass proxyServer;}
}
kangle七层 HTTP 代理请求控制,增加表目标设置为代理匹配模块设置原域名和端口,标记模块设置目标域名和端口
nodejs七层 HTTP 代理const http = require('http')
http.request({host: '127.0.0.1',port: 3000,url: '/'
})
  • document.domain
主域名相同,子域名不同
设置值为 主域名iframewindow.name不超过 2MB同一个iframe加载跨域页,跨域页设置 window.name加载同域页,读取 iframe.contentWindow.namelocation.hash不会被 URL 编码加载跨域页,参数跟在 # 后。window.onhashchange 监听 hash 变化跨域页获取 location.hash,加载同域页,参数跟在 # 后同域页设置 window.parent.parent.location.hash = location.hash,将参数回传

数据库

什么是乐观锁,什么是悲观锁

并发控制

  • 需要保证并发情况下的数据准确性

  • 保证一个用户的工作不会对另一个用户的工作产生不合理的影响

  • 避免

      脏读:一个事务看见另一个事务未提交的数据不可重复读:一个事务两次读取到的数据内容不同,另一事务修改了数据幻读:一个事务两次读取到的数据条数不同,另一事物增删了数据
    

乐观锁:多读 适用

  • 仅在数据提交更新时,检测数据冲突。冲突时,采用竞争机制
  • 依靠数据本身来保证数据正确性,如添加字段 version

悲观锁:多写 适用

  • 共享锁(读锁):多个事务同一数据共享锁,只读不可写
  • 排他锁(写锁):一次仅一个事务可读写数据
  • 依赖数据库的锁机制,如 MySQL:select … for update

什么是事务

(1)定义

访问并可能更新数据库中数据项的一个程序执行单元(Uint)
一条 SQL、一组 SQL 和 整个程序都可以是事务

(2)特点

  • 原子性(atomicity):不可分割,要么都做,要么都不做
  • 一致性(consistency):一个一致性状态变到另一个一致性状态
  • 隔离性(isolation):一个事务的执行不能被其他事务干扰,操作和数据使用不依赖和干扰其它并发事务
  • 持久性(durability):提交后的改变永久生效。不受故障或其它操作影响

(3)在 Mysql 中使用事务

# 关闭自动提交
SET autocommit = 0
# 或者开始一个事务
BEGIN
若干SQL语句
# 提交事务
COMMIT 对数据库所有修改都永久生效
若干SQL语句
# 回滚事务
ROLLBACK 结束当前事务,撤销所有未提交的更改
# 设置保存点
SAVEPOINT id 创建名为 id 的保存点
# 回滚事务到保存点
ROLLBACK TO id 把事务回滚到保存标记点
# 设置事务的隔离级别
SET TRANSACTION InnoDB 存储引擎提供事务的隔离级别有
(1) READ UNCOMMITTED
(2) READ COMMITED
(3) REPEATABLE READ
(4) SERIALIZABLE

##项目管理

文档管理工具

API 接口协作管理工具SwaggerSpringApizza文档协作工具石墨文档有道笔记 + 有道云协作印象笔记自动文档生成apiDoc:根据 API 描述,自动生成文档jsDoc:根据 JS 注释,自动生成文档

对比 Git 和 SVN

架构
Git:分布式,本地克隆版本库无网络依然可以操作分支,提交文件,查看历史记录SVN:集中式,代码一致性高依赖网络存储Git:按元数据,即描述文件的数据SVN:按文件分支Git:移动指针,创建切换快SVN:拷贝目录权限Git:经常按项目配置更适合开源SVN:经常按目录配置更适合内部开发

【JavaScript】阶段性复习相关推荐

  1. javascript正则表达式复习

    javascript的正则表达式复习 参考资源: w3cschool javascript regexp 菜鸟吧 javascript正则表达式 这里主要记录几个自己之前不是很熟悉的知识点,其他的知识 ...

  2. JavaScript基础复习之数据类型,解读数据类型不为人知的一面

    <=> 朋友你好,这里是小毅的前端日记, 分享代码日常 ! <=> 本文目标:查缺补漏Javascript数据类型,解读数据类型不为人知的一面 <=> 卑微的大三前 ...

  3. JavaScript知识点复习总结

    TypeScript 中文手册 - TypeScript 中文手册 (bootcss.com)https://typescript.bootcss.com/ 教程:JavaScript 语法_w3cs ...

  4. javascript基础复习之函数,定时器,erval函数

    Function对象 JS中函数就是Function对象 函数名就是指向Function对象的引用 使用函数名就可以访问函数的对象 函数名()是调用函数 function 函数名 ([参数]) {函数 ...

  5. JavaScript对象复习

    JavaScript对象 Array对象 function $(tg) {return document.writeln("<br/>"+tg); } var arr= ...

  6. JavaScript期末复习

    一.选择题 1.下列关于鼠标事件描述有误的是( ) A.click表示鼠标单击 B.onDblClick表示鼠标双击事件 C.onMouseDown表示鼠标的按钮被按下 D.onmousemove表示 ...

  7. JavaScript知识点复习--思维导图(全)

    把尚硅谷JS高级的视频二刷整理出来的思维导图,算是又把知识过了一遍:快开学了,事情有点多,而且还想着以后+web安全,思路还没理清:另外,最近要准备数模,事情多,效率低,web前端的复习以及学习先搁置 ...

  8. javascript之复习(框架里的方法们)

    继上次整理,一些东西没有整理完.就写在这.可能比较乱比较杂,因为都是整理的一些东西,也没有到做成专题的程度. 1.String.repeat() 大家要实现重复一个字符串的重复怎么写呢,反正我的第一想 ...

  9. day31-python阶段性复习五

    打印目录下所有文件 os 模块 os.listdir('/home') 列出目录下所有文件 os.path.isdir('/home') 判断一个文件是不是一个目录 os.path.isfile('/ ...

最新文章

  1. java aws访问授权 实例_java – 使用IAM身份验证和Spring JDBC访问AWS ...
  2. SwiftUI之深入解析如何实现3D Scroll效果
  3. 推荐:个人时间跟踪工具 ManicTime
  4. 分布式配置中心阿波罗的搭建与客户端的应用
  5. 2019 ACM/ICPC 全国邀请赛(西安)J And And And (树DP+贡献计算)
  6. “Replit 威胁我,要求我关闭我的开源项目!”
  7. andoid-sdk 安装时出现 Stopping ADB server failed(code -1) 错
  8. 信息系统项目管理师论文写作技巧
  9. 维修电工技师、高级技师技能实训考核装置
  10. 安卓UI相关开源项目库汇总
  11. 联合国发布AI报告:自动化和AI对亚洲有巨大影响
  12. C语言面试篇(一)总结
  13. python模拟投掷色子并做出数据可视化统计图
  14. PLC维修-禾川HCA8-32X32YT
  15. 寻找可落地的因果科学范式:从因果推理到因果学习
  16. JUnit 实战第二版 中文目录
  17. 给电脑设置不能访问公网但是能够访问局域网
  18. nrm 安装后报错 Error [ERR_REQUIRE_ESM]: require() of ES Module
  19. 院士报告: 未来智能城市的痛点、突破
  20. 研究生科研论文必用软件——我的一套组合

热门文章

  1. 为什么要进行实名认证?如何实名认证?
  2. Rsync 备份服务:基本概述、应用场景、传输模式、注意事项、密码解决方案、服务实践、备份案例、结合inotify
  3. 利用MediaRecorder录制视频切片上传到ftp服务器
  4. HTTP 所有状态码
  5. 进入html+css世界的正确姿势
  6. 华测教育入选【腾讯课堂 · 薪选课程】--这可能是你进腾讯的最好机会!
  7. Cadence 16.6 Allegro铺铜后去掉贴片元件焊盘之间铜皮的方法
  8. JS生成浏览器唯一标识解决方案
  9. 梦幻西游手游最多人的服务器,梦幻西游手游哪个区人多及区服选择分析
  10. 【转载】Android App应用启动分析与优化