Skip to content

面经 #21

@Lindysen

Description

@Lindysen

面试回答

1.跨域

jsonp
CORS 需要服务端配合 
简单请求 
HEAD
get
post 
非简单请求
 
会先发送一个预检请求[options],返回204[请求成功但是客户端不需要更新页面] 预检通过后开始发送真正的请求
cookie需要服务端和客户端共同设置才有效,credentials为true
带了cookie之后,且后端设置指定的origin

对于附带身份凭证的请求,服务器不得设置 Access-Control-Allow-Origin 的值为“*”。

Access-Control-Allow -origin 返回允许访问的域
Allow-methoh 返回允许的请求方法
access-control-allow-headers

iframe postMessage
  1. get 与post请求的区别
get 使用URL或Cookie传参,而post 放在body里面,
get (请求url的长度限制 是浏览器和服务器的限制),post 
get 明文传输,数据在地址栏上可见
在使用上的区别

本质上的区别
GET和POST最大的区别主要是GET请求是幂等性的,POST请求不是
幂等性是指一次和多次请求某一个资源应该具有同样的副作用。简单来说意味着对同一URL的多个请求应该返回同样的结果。

所以get请求不应该处理增删改操作
  1. Vue 是如何做双向绑定的
普通对象
data  Object.defineProperty setter getter
需要遍历data的每个属性 给它们加上访问描述符
如果 有属性值还是对象的话 就递归添加

array 重写变异方法,里面还是调用Array.prototype的方法 只是添加了一些自定义的操作 比如 dep.notify


Proxy
不需要一个个属性添加访问描述符
有13种拦截操作
访问Proxy代理对象就可以了
也可以拦截数组操作 
避免了 使用 Vue.set(['xx'],indexOf,'xx')

  1. Vue React的区别
Vue和React 鼓励组件化应用
React: 
1. JSX JS写在一个组件文件中
2. 展示和逻辑耦合在一起了 js和jsx写在一起了

state对象, 不能直接改变,只能通过setState改变

Vue
1. 单文件组件 模版系统 HTML CSS JS写在一个文件里面
 2. 三者是分离的
2. Vue 中的data 是可以直接改变的

监听数据变化不同 

Vue getter/setter 数据劫持 更加细粒度准确知道数据变化
React 是通过比较引用的方式进行的  像shouleComponentUpdate/PureComponent

通信方式不同 
2. provider/inject
1. Vue支持自定义事件 父组件 props 传递给子组件,子组件通过事件给父组件通信

react 
代码逻辑复用不同 mixins,hoc

React组件内部实现渲染列表 条件展示 都是通过js代码控制的
Vue 组件有内置的模版

Vuex是直接修改数据 每个实例都有this.$store拿到store中的数据

Redux  是每次生成一个新的对象,然后组件要通过 connect 拿到组件的属性
  1. ==Virtural DOM==
Js和真实DOM的缓存
操作js对象比操作真实DOM 更节约性能

用js对象描述dom 结构
  1. react 的diff算法
通过深度优先遍历,当访问到一个新树的节点 就和老树的节点进行比较 ,tag 不同 就把差异(有几种差异类型,replace props reorder,text这样)存放在一个对象上,然后patch阶段就通过差异记录,修改DOM树

1. 只在同层级比较
2.class不同直接替换
3. 组件内 比较tag tag不同就直接替换

作用:通过比较两个虚拟树,创建补丁(描述改变的内容),改变真实DOM

diff 更改类型
Attr
Text
Remove
Replace

patch 通过刚才的补丁对象 对真实dom进行操作

5 ==Vuex的内部机制==

Vue.use(Vuex)
调用Vuex.install方法
通过在Vue根实例上添加$store属性然后非根实例都用$parent上¥store都可以访问到Vuex store中的状态

Vuex 
1. 监测window.Vue判断是否安装Vue ,参数中监测action mutation  是否合法
2. 初始化参数 比如 warpGetter actions mutaitons committing 这些
3. 让dispatch commit 通过bind 使这些方法内部的this指向 store实例
4. 根据调用ModuleCollection方法, options生成根module,options中的moduels生成子module,最终生成一个module树,

5. installModule,使父组件的state有指向子组件state的应用,就让Vuex实例的state 是 一个整个Vuex应用的入口
在Vuex实例上分别注册带有命名空间的actions,mutation,getters
同时子module的dispatch被改写传入的type变成namespacedType这样,变成指向Vuex实例上的namespacedAction, 函数
vuex内部也是通过vm来管理状态,
监测到state变化
严格模式 每次状态变化监测committing 整个标记是不是true 不是 true 就认为非正常操作
  1. PureComponent
1.  props state没有改变 就不会执行render
2.  默认帮我们执行了shouleComponentUpdate 若有这个 则以默认帮我们执行了shouleComponentUpdate为准

适合一些纯函数和简单组件
  1. hooks 和高阶组件
hooks使函数式组件拥有了状态
自定义hooks 实现逻辑复用
减少组件嵌套

一个组件 包括 展示 逻辑 状态

更细粒度的封装逻辑
  1. 为什么会选择 monaco editor
monaco editor
优点
1.就是 vscode 的web版本编辑 使用简单,和vscode的风格交互一致

2. 功能完备集成度高,可以说即插即用,非常适合仅需代码编辑不需要太多扩展和自定义样式的业务场景

3. 原生支持diff,typeScript 

缺点
1. 不支持移动端浏览器
2. 支持的语言种类少
3. 扩展性差

其他的代码编辑器
1. codeMirror 适合扩展性高的定制型编辑器
2.


monaco 是用worker方式 异步处理的我们的编辑器
monaco-editor-webpack-plugin
1. 自动注入 getWorkerUrl 全局变量
2. 自动处理worker 配置问题
2. 自动引入语言包和控件
传入一个组件 返回一个新的组件,新的组件里被加上了模拟器组件

10 react dnd

redux 作者写的 dnd是drag and drop 的意思

HTML5 拖放API的问题
1. 不支持移动端
2. 拖动预览问题
3. 无法开箱即用

React dnd

1. 兼容浏览器差异
2. 拖动源和目标解耦
3. 拖动预览
默认提HTML5 api 封装
4  不直接操作DOM
5. 专注拖拽,不提供现成组件,而是采用包裹使用者的组件注入props实现的

Backend是啥嘞
引入了后端的概念,提供 HTML5 拖拽后端 ,可插拔,可自定义touch mouse行为 模拟的后端实现,后端抹平浏览器差异,处理dom事件
,把dom事件转换为redux action

monitor 检测器,拖放是有状态的,monitor及时获取拖放元素的状态

backend 专注dom事件,组件关注拖动状态,connector把benkend和组件联系起来,可以让bankend获取到dom

type 定义了应用程序里支持的拖拽类型,拖放目标只处理type匹配的拖动源

只有 DragSource 注册的类型 和 DropTarget 注册的类型 完全匹配才可以drop

11 React.cloneElement React.createElement

React.createElement(
type, // 标签名字符串 或者 React组件类型
[props], // 属性
[...children] // 子组件
)

使用JSX编写的代码 会被转换成使用React.createElement创建react元素

cloneElement 以 element 为样本克隆并返回新的元素,返回元素的props是由传入的props和原有props 浅层合并后的结果 key和ref保留 新的子元素将取代现有的子元素

  1. 钉钉应用如何在手机端看到请求
1.vconsole
2. 模拟器

10 输入url 浏览器的执行过程

1. 收到输入的URL,分析协议域名端口 path
2. 解析域名 拿到主机ip 浏览器缓存,本机 hosts 路由器 dns
3. 发起请求,(TCP三次握手)
4. 后端返回响应
5. gizp 解码啥的
6. 分析响应内容 开始渲染
7. 解析html 文档生层dom树,
    异步下载css文件 构建cssom树 然后生成渲染树然后GUI线程去渲染页面

async 异步下载 异步执行 不一定保证顺序 不会阻塞dom树构建
defer 是立即下载延迟执行 等dom树构建完成再执行 保证顺序,相当于放在body底部的效果

11 如何理解原型链

每个对象有个原型链最终指向Object.prototype
但是Object.prototype.proto指向null

12 作用域链

先在当前上下文中寻找变量属性,找不到的话 就去父作用域找,最后就到全局作用域找,找不到就返回undefined
闭包 是函数+自由变量
函数的执行上下文(this, 变量对象,)中有个scope属性 里面存着作用域的Ao

13 证书???

ca 发给服务器的签名
ca = 本身信息+服务器信息+加上服务器信息的摘要用私钥加密的秘闻

14.== router底层实现==

  1. forceUpdate 和setState的区别
setState 总是会触发一次渲染,除非shouleComponentUpdate检查为false,

当props,state 深层次数据改变,或者render()依赖外部数据时,

forceUpdate将会跳过 本身组件的 shouleComponentUpdate的调用
但是子级的生命周期 和shouledComponetntUpdate还是会调用
  1. ==webpack 核心流程原理==,怎么实现模块化的,treeshaking 怎么做的?

17 ==Vue compouted 怎么实现==

18 函数柯里化

处理多参数 函数的,
接受函数的部分参数,返回一个接受余下参数的函数

解决的问题 场景
1. 参数复用
2. 延迟调用

生于函数式编程,陷于函数式编程
相对于 bind -> 箭头函数等,性能不算高的

function trueCurrying(fn,...args){
    if(args.length > fn.length) {
      return fn(...args);
    }
    return function(args2) {
      return trueCurrying(fn,...args,...args2);
    }
}

19 函数式和响应式的理解

函数式编程
1.函数是一等公民,认为和其他的变量是一样的,可以被传递,做为返回值等
函数式编程的特性:
1. 纯函数 相同输入必然得到相同输出,没有任何副作用(做了与函数本身无关的事情),不会改变外界变量,http请求,console.long等
2. 只用表达式不用语句,表达式是有返回值的,语句没有返回值

优势:
2. 更便于测试
3. 更接近于自然语言
4. 开发更快

响应式编程
面向数据流和变化传播的编程范式
用异步数据流进行编程,点击事件就是一个异步事件流,可以对他进行侦测然后进行操作

21 客户端渲染和服务端渲染

22 Vue router 和window.location.href

Vue router 不会打开一个新的页面, 不会引起页面刷新
window.location.href 是打开一个新的页面,

23== css 动画 和js动画==

1. transtion  animation 的区别

js 

25 React 16版本中生命周期的变化

unsafe_componentWillMount 
可能会首页白屏,,componentWillMount执行后,第一次渲染已经开始了, 请求还没得到响应 ,没有异步数据,首页还是白屏

服务端渲染的话 在componentWillMount 开启定时器事件监听的话,不会执行 componentWillUnmount 这样会引起内存泄露

可能还会引起发两次相同请求 ,服务端一次 客户端一次

getDerivedStateFromPorps 获取派生state 从props中,函数内禁止调用this.props 通过nextProps 和 prevProps进行比较 来返回组件的state

之前使 根据props 生成新的state, 执行回调放在componentWillReceiveProps一个生命钩子中
unsafe_componentWillReceiveProps

现在分成两个
getDerivedStateFromProps  产生派生状态
componentDidUpdated 执行回调

在组件更新前读取 DOM 元素状态

unsafe_componentWillUpdate,根据props执行一个回调,可能会被执行多次
componentDidUpdate 保证执行一次

有部分现象时在componentWillUpdate获取更新前的dom元素信息,再在 componentDidUpdate利用,
 getSnapShotBeforeUpdate 在render之前调用 保证获取到的信息更准确
 

26 createElement 和 cloneElement 的 区别

createElement是 把 根据jsx 生成 描述dom的js对象
cloneElement 是 改造自组件,添加上一些 额外的prorps

type attrs children
attrs: style value
style: style.cssText = value
value input或者textArea  直接 node.value
其他setAttribute()

28 webpack 怎么实现模块化的 treeshaking 怎么做到的

treeShaking 依赖的es6 的静态分析,
但是还有短版的
1. 不能对entry 进行treeShaking
2. 不会对异步分割出去的代码做 Tree Shaking。
Webpack 只是指出了哪些函数用上了哪些没用上
要剔除用不上的代码还得经过 UglifyJS 去处理一遍

resolve 中的 mainFields 用于配置采用哪个字段作为模块的入口描述。
//  针对 Npm 中的第三方模块优先采用 jsnext:main 中指向的 ES6 模块化语法的文件
jsnext:main
// 依次降级
mainFields: ['jsnext:main', 'browser', 'main']

29 react 16 新特性,react 17 前瞻,fiber,hooks,suspense,异步渲染


30 协调算法

通过VDom 前后对比,找出变化,然后在真实dom上应用变化,这一过程叫 reconcilation

16版本以前,diff 是中序深度优点遍历整个树,收集change, 若整个树很大diff的过程就会很长占据主线程,,交互 动画等就会阻塞无响应,导致页面卡顿

stack
存在的问题
1. 并不是所有setState更新 都要马上更新真实dom显示出来 ,比如在屏幕之外的部分
2. 并不是所有的更新的优先级一样
3. 理想情况下,高优先级的操作是可以打断低优先级操作的执行的


fiber 就是把这个过程拆分,防止主线程占据时间过长
reconcilation(可中断的)
commit(不可中断的)

fieber节点
1. return 指向父节点
2. children 指向第一个子节点
3. sider指向兄弟节点

fiber 
{
    return{} // 改变的结果合并到改对象
    children{}
    sider{}
}

 
在render 就是渲染完成的生成一个 fiber tree,
同时维护 一个 workInprocess Tree来标记更新

自顶向下处理 fiber tree ,每处理一个fiber 节点都看 是否还能拥有主线程的时间,有的话 就继续处理下一个fiber节点(通过child 和 sider 指针,指向下一个待处理的fiber节点),没改动直接返回标记这个节点处理完成再返回 ,有改动就打个标记

改动添加到 effect list中 并合并到上一层父节点中
// 合并后,回到父节点Item,父节点标记完成。

执行完成后一层层向上 merge effect,所有节点已经标记完成 workInProcess tree 进入 precommiting阶段
commit 阶段 更新真实dom

更新完成后 workInprocess Tree 和真实dom的结构一致,
为了保持 fiber tree 和真实dom 保持一致就 fiber tree 与 workInprocess Tree 互换,释放内存

如果当前处理 react 渲染时间过长,到时后面的渲染卡住,所有fiber reconcilation就有了优先级策略
1. 高优先级任务可以打断低优先级
2. 当低优先级任务重写获得时间片的时候 会从新执行

componentwillrecivePorps 这些生命钩子 可能会执行多次

31 装饰器

不用于函数,是因为函数存在变量提升
装饰器一个函数,只能用于类和类的方法,不能用于函数

function (target,name,descriptor){
     // 为类/ 类的方法
}
//core-decorators.js

Mixin 模式

改造类,使类继承另一个类的方法 是对象继承的另一种方式
// 相当于一个混合类生成器,继承superclass的同时,混入foo 方法
minin = (superclass) => class extends superclass{
    foo() { // 
    console.log('foo from MyMixin');
  }
}
这种写法的一个好处是 可以调用super
避免覆盖父类中的同名写法

32 ==算法== 深度优先 广度优先

33 https 怎么做到数据包被劫持的


34 证书的是什么

CA = 服务器信息+ 证书中心的信息+ 服务器信息的摘要的私钥密文

客户端 根据相同的散列算法算出服务器信息的摘要,在用证书中心的公钥加密 比较密文是否相同

36 闭包 ,闭包的应用

闭包 是函数+ 自由变量

自由变量是指那些不是函数的形参或者函数内定义的局部变量

函数在创建的时候就会把他的上层上下文数据保存起来,哪怕是全局变量也是如此,因为函数中访问全局变量就是在访问自由变量

[[scope]]中保存着父函数的AO

即使创建它的上下文已经销毁,它仍然存在(比如,内部函数从父函数中返回)

37 redux 好难啊啊啊啊

38 变量提升 函数提升

块级作用域
 块级作用域存在于
 1. 函数内部
 2. {}大括号里
 
块级作用域用于在块之外无法访问块中声明的变量

在进入执行上下文时,AO 活动对象,会先处理函数声明,其次进行变量声明,如果变量声明时,已经有行参和函数定义了,就不影响这些已经定义的变量

39 异步渲染

40 hook

1. 使函数组件拥有状态
2. 使代码逻辑更加精简 不重复,本来写在componentDidMount/ componentDidUpdate 的逻辑写在一起,comoenentwillUnmount
3. 逻辑复用,减少组件嵌套
组件包括 状态 生命周期 展示 ,但是 hooks 专注与展示 逻辑复用

41 属性访问描述符

数据描述符

enumeable// 是否是可枚举的 for in object.keys JSON.stringify都获取不到
value
configuable //  是否是可删除的 delete 操作,是否是可配置的不能使用 defineProperty
writable // 是否可重写

访问描述符
get
set

45 层叠上下文

层叠等级在同一个层叠上下文中比较才有意义

拥有层叠上下文的元素比普通元素更接近于屏幕

怎么产生层叠上下文呢
1. html元素 根层叠上下文
2. position 不为static 且z-index为具体的值,auto不算具体值

两个层叠上下文,层叠等级相同,后面的覆盖前面
层叠顺序
background/border < ( index<0) < block块级盒子< float盒子< inline-block盒子< z-index 0/auto < z-index>0

46 react 中的key

保证某个元素的key在同级列表中是否唯一,
virtual DOm diff阶段,根据key 来判断这个元素是新近创建还是移动而来

47 CSRF cross-site-request-forgery 跨站请求伪造

同源策略
浏览器,从两个方面去作同源策略: 1 是dom 2请求的接口
攻击者盗用了你的身份 ,以你的名义发送恶意请求,骗取服务器执行某些操作

1. Referer 检查,检查请求来源
// referer是在发起请求前,或者window.location.href的值设为referer
2. 服务端生成 token,请求时带着cookie和token 以便服务器检查/校验

48 xhr 封装库

axios 是基于Promise实现的是,
1. 使用promise api
2. 是对XMLHttpRequest的封装,可以监测到请求的进度
3. 可设置请求超时,validateStatus, 
4. 可取消请求
5. 可拦截请求,
6. 转换请求和响应的数据 transformRequest,只能在post put patchde 这几个请求方法中,参数值要求是个函数数组,要求函数返回字符串,arraybuffer,stream
7. transformRequest 在被then和catch 处理前 转换响应数据
8. 配置灵活,创建请求实例,或者设置默认配置
9 自动转换成json格式
10 提供并发请求的接口
axios.all([getUserInfo(),getUserData()]).then(axios.spread(function(info,data){
    
})
11 体积小
12 客户端支持csrf,每次请求都带一个从cookie里拿到一个key,同源策略,假冒的网站是拿不到这个key


fetch
1. 需要自己对请求到的数据进行转换 转成text json
2. 更加底层 可以看成是一个原生的XHR 提供丰富的api
3. 关注点分离,让输入,输出,用事件跟踪状态放在一个对象里

缺点:
1. 当服务器返回400 500的错误码时,并不会reject,只有当网络错误导致请求不能完成 才会reject
2 fetch 不支持abort,不支持超时控制,setTimeout 这些控制不会阻止请求,请求还是会在后台进行,浪费流量
3. 默认跨域不带cookie 需要带上 fetch(url,{cred: 'include'})

49 尾调用优化,只在严格模式下有效

尾调用是函数式编程的一个重要的概念,当函数执行的最后一个是返回另外一个函数的调用。

调用栈:函数执行就会往调用栈中push一条记录,执行结束就弹出

栈桢: 函数调用时产生的空间

调用帧
当前帧

当函数A执行的时候就会往调用栈中push一个记录,此时叫调用帧,内部调用另外一个函数B,就进入那个函数B的上下文,那个函数叫当前帧,因为函数A执行的最后一句是return,所有不需要保留函数A的调用栈,就用B替换掉A,减少调用栈的大小

只要直接用内层函数的调用记录取代外层函数的调用记录


50 typed Array 类型化数组 Int8Array

ArrayBuffer DataView TypedArray 为javaScript操作二进制数据提供了便利

ArrayBuffer 二进制数据缓冲区 一块内存 存储二进制数据的内容 不可以直接读写 

需通过 TypedArray ,DataView读写 将缓冲区数据表现为特定的格式

TypedArray  Int8Array[表示每个元素存储一个字节]  Int32Array 

TypedArray对象 是描述一个底层二进制数据缓冲区的内容的 类似数组视图

TypedArray 数组内成员是同一个类型,且完全连续无空位,本身不存储真实数据 是展示视图 数据存在ArrayBuffer中,适合处理简单二进制数据,复杂的数据还是适合由DataView处理

TypeArray构造器 是所有类型化数组构造器的原型 没有全局的TypeArray和TypeArray属性

只能通过使用类似Object.getPrototypeOf(Int8Array.prototype)的方式进行访问.

所有类型化数组构造器都会继承TypedArray构造器上的通用的属性和方法
所有类型化数组构造器的原型都以TypedArray.prototype为原型

当创建一个TypedArray实例(例如:Int8Array)时,一个数组缓冲区将被创建在内存中,如果ArrayBuffer对象被当作参数传给构造函数将使用传入的ArrayBuffer代替。缓冲区的地址被存储在实例的内部属性中,所有的%TypedArray%.prototype上的方法例如set value和get value等都会操作在数组缓冲区上。

51 MVVM 和 MVC 的区别

MVC

Model 存着数据和数据处理逻辑
View 是视图展示层
controller  处理view的用户交互,调用model层的方法改变数据,数据改变,Model通知view更改
model 通知view 是观察者模式

其实视图层完全有处理用户交互的能力,所有的事件处理逻辑含在controller里面 ,就很臃肿,而且无法复用

MVVM

view 视图层
model 数据层
viewModel是最核心的地方

view和model 相互无感知


52 children.map

React.Children.map(children,function[(thisArg)]) 
children里的每个子节点都调用一遍函数,并将 this 设置为 thisArg

53 TypeScript

是 JavaScript 的超集 给 js 的生态加了类型机制并最终把代码编译为js代码

javaScript是弱类型语言,变量的类型具有动态性,只有执行的时候才能确定变量的类型,
TypeScript的类型机制杜绝了由变量类型的误用问题
静态分析,自动编译工具的帮助,在编写代码时减少错误

增大了开发人员的学习曲线,增加了设定类型的开发时间

增强了代码的维护性和健壮性

interfase test{
     destroy(): void;
}

类型声明文件怎么写的

声明文件 xxx.d.ts 存放当前项目中,建议和其他 *.ts 都存放在 src 目录下(没有生效,可检查 tsconfig.json 中的 file、include、exclude 等配置);

为了便于自己和他人,请将声明文件和 npm 包绑定在一起
npm包 检查 package.json types字段 

npm 包声明文件和其有一定区别。

不使用 declare 声明全局变量,就只是声明一个普通变量(局部变量);
声明文件中使用 export 导出;
使用文件用 import 导入然后使用,这个和 ES6 一样(无学习成本);

decaler module 'dom-util'{
    <!--type text = (test:string) =>  void-->
    <!--export default waterMark;-->
    export function(text:string):void//  类型声明
    export function parseUrl(url?: string): Location
}

54 技术选型

1. 社区 react的社区更大 有更多的工具 包啥的
2. Vue 有官方维护的全家桶 react 没有
3.主要是看 团队成员喜欢擅长哪个把 毕竟 项目的开发速度与质量还是要保证的

react
1.学习曲线
更庞大的社区,大量的工具和包。
3 成熟度 
facebook团队维护 13年发布拥有强大背景的公司支持,更加安全的未来和稳定。
4. React不具有实际的路线图,基于RFC规则

vue
1.状态管理路由管理这些是官方维护的,react 需要去自己折腾
2.更快的上手,FED(前端开发)和BED(后端开发)都会在Vue代码中感觉很自然,速度很快
4.Vue的高级路线图 github上 可以找到 在博客上
可用的插件和工具更少,社区更小。

55 ==react的事件机制==

56 babel-polyfill vs babel-runtime

babel-polyfill
babel只负责语法转换,例如把es6的语法转成es5 ,但是有对象,方法 本身浏览器不支持
比如:
1. 全局对象: weakMap Promise等
2. 全局静态函数等: Array.form等
3. 实例的方法: Array.prototype.includes等
需要引入 abel-polyfill 来模拟实现

引入babel-polyfill会有两个副作用
1. 引入新的全局对象,比如Promise、WeakMap等。
2. 修改现有的全局对象,比如修改Array.prototype


开发库,工具 优先考虑babel-runtime
babel-runtime 将开发者依赖的内置的全局对象,抽取成单独的模块,并通过模块导入的方式引入,避免了对全局作用域的修改(污染)。

babel-plugin-transform-runtime 主要做了三件事
1. core.js : 内置的全局对象 通过从babel-runtime/core.js映射到相应模块中
2. helper: 内联的工具的消除,从babel-runtime/helpers中导入
3. regenerator 遇到async/generator函数 则自动导入bable-runtime/regenerator模块

虽然避免了修改全局对象,但是也引入了不少冗余的导入代码。

babel-register

它的原理是通过改写 node 本身的 require,添加钩子,然后在 require 其他模块的时候,就会触发 babel 编译。
你引入require('babel-register')的文件代码,是不会被编译的

是一个编译器,实时编译,不需要输出文件,执行的时候再去编译。所以它很适用于开发。

57 怎么实现登陆

cookie session
1.当客户端把身份信息传给服务端通过身份认证后,服务端就会生成身份认证相关的session数据保存在内存或者内存数据库。并将对应的 sesssion_id返回给client,client会把保存session_id(可以加密签名下防止篡改)在cookie。此后client的所有请求都会附带该session_id(毕竟默认会把cookie传给server)以确定服务端是否存在对应的session以检验登陆状态
优点
相比JWT,最大的优势就在于可以主动清除session了
缺点
如果是分布式部署,需要做多机共享session机制,实现方法可将session存储到数据库中或者redis中

基于cookie 的机制很容易被 CSRF

jwt json web token

它定义了一种紧凑且独立的方式,可以将各方之间的信息作为JSON对象进行安全传输。该信息可以验证和信任,因为是经过数字签名的。

JWT基本上由.分隔的三部分组成,分别是头部,有效载荷和签名。 
Header.Payload.Signature
Header是固定的 {
    type: 'JWT',
    alg: 采用的hash算法
}
payload 部分是可以被加密的,真实存储我们需要传递的信息的部分

Signature就是会header和payload部分进行签名保证token在传输的过程中不被串改,但是为了加密,除了header和payload字段外 还有一个密钥字段

客户端拿到token后存到localStorage 或者 sessionStorage中
下次请求时放到header的auth字段

无状态JWT,只有等到过期才可销毁

58 cookie localStorage sessionStorage

cookie 大小只有几k 存在过期时间  请求时可以带上

localStorage 大小是5M 存在本地 持久存储 除非手动清楚  仅在客户端中保存,不参与和服务器的通信
在同一个浏览器内,同源文档之间共享 localStorage 数据,可以互相读取、覆盖。

sessionStorage 大小也是5M 会话期间有效 会话结束清除仅在客户端中保存,不参与和服务器的通信
,只有同一浏览器、同一窗口的同源文档才能共享数据。

59 Session

Session是在无状态的HTTP协议下,服务端记录用户状态时用于标识具体用户的机制。它是在服务端保存的用来跟踪用户的状态的数据结构,可以保存在文件、数据库或者集群中。

60 物理像素 逻辑像素

物理像素
设备屏幕实际拥有的像素点,屏幕的基本单元,是有实体的。

逻辑像素
设备独立像素,可以理解为反映在CSS/JS程序里面的像素点,也就是说css像素是逻辑像素的一种。

设备像素比 Device Pixel Ratio
一个设备的物理像素与逻辑像素之比。

使用4个乃至更多物理像素来渲染1个逻辑像素

window.devicePixelRatio

61 发布第三方包有那些考量

jsnext:mian

有es5 版本 和es6 版本 方便使用tree shaking
内建 ts 类型 声明文件 不需要使用者再去写类型声明文件了

想要 发布到 Npm 上去的代码保持和源码的目录结构一致,那么用 Webpack 将不在适合
像 Lodash 这样的工具函数库在项目中可能只用到了其中几个工具函数,如果所有工具函数打包在一个文件中,
Webpack 适合于构建完整不可分割的 Npm 模块。



output.libraryTarget 配置以何种方式导出库。
output.library 配置导出库的名称。
output.libraryExport
配置要导出的模块中哪些子模块需要被导出。。 它只有在 output.libraryTarget 被设置成 commonjs 或者 commonjs2 时使用才有意义。

62 ==Vue keep-alive怎么实现的==

63 单元测试 mocha

1. 测试脚本要与源码脚本同名 xx.test.js
2. describe 测试套件 it 测试用例

var add = require('./add.js');
var expect = require('chai').expect;
describe('加法函数的测试',function() {
it('1+1',function() {
    expect(add(1+1)).to.be.equal(2);
})
})

所谓"断言",就是判断源码的实际执行结果与预期结果是否一致,

mocha add.test.js

Mocha默认运行test子目录里面的测试脚本。Mocha默认只执行test子目录下面第一层的测试用例,不会执行更下层的用例。

mocha --recursive test子目录下面所有的测试用例----不管在哪一层----都会执行。

Mocha允许在test目录下面,放置配置文件mocha.opts

--compilers js:babel-core/register参数指定测试脚本的转码器。

Mocha默认每个测试用例最多执行2000毫秒,如果到时没有得到结果,就报错。
-t或--timeout参数指定超时门槛。

it块执行的时候,传入一个done参数,当测试结束的时候,必须显式调用这个函数,告诉Mocha测试结束了。

Mocha在describe块之中,提供测试用例的四个钩子:before()、after()、beforeEach()和afterEach()。它们会在指定时间执行。

it('异步请求应该返回一个对象', function() {
  return fetch('https://api.github.com')
    .then(function(res) {
      return res.json();
    }).then(function(json) {
      expect(json).to.be.an('object');
    });
});

Mocha内置对Promise的支持,允许直接返回Promise,等到它的状态改变,再执行断言,不必显示done()

64 scope hoisting 作用域提升 webpack

1. 代码体积更小,因为函数声明存在大量的代码
2. 代码运行时因为创建的函数作用域变少 内存开销变小

现象是  函数声明由2个变成1个,b中的代码直接被注入到a中

实现原理: 分析模块之间的依赖关系,尽可能把分散的代码合并,前提是不能造成冗余代码,所有只有那些被引用到一次的模块才会被合并

需要配合一个插件
new ModuleConcatenationPlugin()

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions