一、 React 16 生命周期的变化
componentWillMount,componentWillReceiveProps, componentWillUpdate 准备废除。理由:主要是16 版本 render 之前的生命周期可能会被多次执行。
static getDerivedStateFromProps和 getSnapshotBeforeUpdate新增,用于补充上述的生命周期。
二、 redux
Store的角色是整个应用的数据存储中心,集中大部分页面需要的状态数据; ActionCreators ,view 层与data层的介质; Reduce ,接收action并更新Store。 所以流程是 用户通过界面组件 触发ActionCreator,携带Store中的旧State与Action 流向Reducer,Reducer返回新的state,并更新界面。
redux 其实也是一个发布订阅,但是 redux 可以做到数据的可预测和可回溯。
react-redux 的核心组件只有两个,Provider 和 connect,Provider 存放 Redux 里 store 的数据到 context 里,通过 connect 从 context 拿数据,通过 props 传递给 connect 所包裹的组件。
三、网络安全
xss: 往Web页面插件恶意的Script代码,当用户浏览该页之时,嵌入其中 Web 里面的 Script 代码会被执行,从而达到恶意攻击用户的目的。
解决:现在在成熟的框架已经解决了 HttpOnly 防止劫取 Cookie 用户的输入检查 服务端的输出检查
csrf:CSRF 攻击是攻击者借助受害者的 Cookie 骗取服务器的信任,可以在受害者毫不知情的情况下以受害者名义伪造请求发送给受攻击服务器,从而在并未授权的情况下执行在权限保护之下的操作。
解决:CSRF的两个特点:
CSRF(通常)发生在第三方域名。 CSRF攻击者不能获取到Cookie等信息,只是使用。 针对这两点,我们可以专门制定防护策略,如下:
阻止不明外域的访问 同源检测 Samesite Cookie 提交时要求附加本域才能获取的信息 CSRF Token 双重Cookie验证
四、缓存
浏览器缓存分为强缓存和协商缓存,强缓存会直接从浏览器里面拿数据,协商缓存会先访问服务器看缓存是否过期,再决定是否从浏览器里面拿数据。 控制强缓存的字段有:Expires和Cache-Control,Expires 和 Cache-Control。 控制协商缓存的字段是:Last-Modified / If-Modified-Since 和 Etag / If-None-Match,其中 Etag / If-None-Match的优先级比Last-Modified / If-Modified-Since高。
五、跨域
为什么会有跨域
同源策略的限制:同源策略是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSRF等攻击。所谓同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个ip地址,也非同源。
同源策略的限制内容有:
- cookie、LocalStorage、IndexedDB等
- DOM 节点
- http
请求的结果被浏览器拦截
但是有三个属性是允许跨域的:
<img src=XXX><link href=XXX><script src=XXX>
jsonp
利用 <script> 标签没有跨域限制的漏洞,网页可以得到从其他来源动态产生的 JSON 数据。JSONP请求一定需要对方的服务器做支持才可以。
- 缺陷 不安全 只能get方法
cors
CORS 需要浏览器和后端同时支持。IE 8 和 9 需要通过 XDomainRequest 来实现。
浏览器会自动进行 CORS 通信,实现 CORS 通信的关键是后端。只要后端实现了 CORS,就实现了跨域。 服务端设置 Access-Control-Allow-Origin 就可以开启 CORS。 该属性表示哪些域名可以访问资源,如果设置通配符则表示所有网站都可以访问资源。
postMessage
postMessage是HTML5 XMLHttpRequest Level 2中的API,且是为数不多可以跨域操作的window属性之一,它可用于解决以下方面的问题:
- 页面和其打开的新窗口的数据传递
- 多窗口之间消息传递
- 页面与嵌套的iframe消息传递
- 上面三个场景的跨域数据传递
// a.html
<iframe src="http://localhost:4000/b.html" frameborder="0" id="frame" onload="load()"></iframe> //等它加载完触发一个事件
//内嵌在http://localhost:3000/a.html
<script>
function load() {
let frame = document.getElementById('frame')
frame.contentWindow.postMessage('我爱你', 'http://localhost:4000') //发送数据
window.onmessage = function(e) { //接受返回数据
console.log(e.data) //我不爱你
}
}
</script>
// b.html
window.onmessage = function(e) {
console.log(e.data) //我爱你
e.source.postMessage('我不爱你', e.origin)
}
Websocket
Node中间件代理(两次跨域)
nginx反向代理
window.name
localtion.hash
document.domain
六、HTTPS
-
HTTP 是明文传输协议,HTTPS 协议是由 SSL+HTTP 协议构建的可进行加密传输、身份认证的网络协议,比 HTTP 协议安全。
-
关于安全性,用最简单的比喻形容两者的关系就是卡车运货,HTTP下的运货车是敞篷的,货物都是暴露的。而https则是封闭集装箱车,安全性自然提升不少。
-
HTTPS比HTTP更加安全,对搜索引擎更友好,利于SEO,谷歌、百度优先索引HTTPS网页;
-
HTTPS需要用到SSL证书,而HTTP不用;
-
HTTPS标准端口443,HTTP标准端口80;
-
HTTPS基于传输层,HTTP基于应用层;
-
HTTPS在浏览器显示绿色安全锁,HTTP没有显示;
七、webpack的原理
- 初始化参数:从配置文件和Shell语句中读取和合并参数;
- 开始编译:用上一步得到的初始化Compiler对象,加载所有配置的插件,执行对象的run的方法开始执行编译;
- 确定入口:根据配置中的ent ry找到所有的入口文件
- 编译模块:从入口文件出发,调用所有配置的Loader 对模块进行编译,再找出该模块依赖的模块,在递归本步骤直到所有入口依赖的文件都经过了本步骤的处理;
- 完成模块编译:在经过第4步使用 Loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系;
- 输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会;
- 输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统。
八、babel 原理
babel的转译过程分为三个阶段:parsing、transforming、generating,以ES6代码转译为ES5代码为例,babel转译的具体过程如下:
1. ES6代码输入
2. babylon 进行解析得到 AST
3. plugin 用 babel-traverse 对 AST 树进行遍历转译,得到新的AST树
4. 用 babel-generator 通过 AST 树生成 ES5 代码
九、虚拟DOM的理解
本质上是 JavaScript 对象,这个对象就是更加轻量级的对 DOM 的描述。
对于 DOM 这么多属性,其实大部分属性对于做 Diff 是没有任何用处的,所以如果用更轻量级的 JS 对象来代替复杂的 DOM 节点,然后把对 DOM 的 diff 操作转移到 JS 对象,就可以避免大量对 DOM 的查询操作。这个更轻量级的 JS 对象就称为 Virtual DOM 。
那么现在的过程就是这样:
- 维护一个使用 JS 对象表示的 Virtual DOM,与真实 DOM 一一对应
- 对前后两个 Virtual DOM 做 diff ,生成变更(Mutation)
- 把变更应用于真实 DOM,生成最新的真实 DOM
可以看出,因为要把变更应用到真实 DOM 上,所以还是避免不了要直接操作 DOM ,但是 React 的 diff 算法会把 DOM 改动次数降到最低。
十、es module 和 commonjs 的区别
- 前者是值的引用,后者是值的拷贝。
- 前者编译时输出接口,后者运行时加载。
十一、react 里如何做动态加载
- react.lazy
const LazyComponent = React.lazy(() =>
import(/* webpackChunkName: 'lazyComponent'*/ "../components/LazyComponent")
);
配合suspense,
return (
<div>
<MainComponet />
<React.Suspense fallback={<div>正在加载中</div>}>
<LazyComponent />
</React.Suspense>
</div>
)
fallback中可以修改为任意的spinner,本次不做过多优化。假如你不使用React.suspense,则React会给出你错误提示,因此记得React.lazy和React.Suspense搭配使用。 此时我们可以从网络请求中看到,动态加载的lazyComponet组件被单独打包到一个bundle里面.
return (
<div>
<MainComponet />
{this.state.showLazyComponent && (
<React.Suspense fallback={<div>正在加载中</div>}>
<LazyComponent />
</React.Suspense>
)}
</div>
)
另外通过 webpack 的动态加载:import() 和 ensure.require。
十一、new的执行过程
- 创建一个空对象
- 将对象的_proto_指向构造函数的 prototype
- 将这个构造函数作为这个对象的this
- 返回该对象
function myNew(Con,...args) {
let obj = Object.create(Con.prototype);
let result = obj.apply(Con,args);
return typeof result === 'object' ? result : obj;
}