You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
思路:使用一个队列来维护任务列表,通过返回 this 来实现链式调用,为了在任务队列中先 push 完所有任务然后再依次执行,添加上 setTimeout 函数
function_LazyMan(name){this.tasks=[]var_this=thisvarfn=(function(){console.log(`Hi! This is ${name}!`)_this._next()})this.tasks.push(fn)setTimeout(function(){_this._next()},0)}_LazyMan.prototype._next=function(){varfn=this.tasks.shift()fn&&fn()}_LazyMan.prototype.eat=function(name){var_this=thisvarfn=(function(){console.log(`Eat ${name}`)_this._next()})this.tasks.push(fn)returnthis}_LazyMan.prototype.sleep=function(time){var_this=thisvarfn=(function(){setTimeout(function(){console.log(`Wake up after ${time} s`)_this._next()},time*1000)})this.tasks.push(fn)returnthis}_LazyMan.prototype.sleepFirst=function(time){var_this=thisvarfn=(function(){setTimeout(function(){console.log(`Wake up after ${time} s`)_this._next()},time*1000)})this.tasks.unshift(fn)returnthis}functionLazyMan(name){returnnew_LazyMan(name)}LazyMan('GGG').sleep(3).eat('milk').eat('fish').sleep(2).eat('water').sleepFirst(2)
在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。
// 修改数据vm.msg='Hello'// DOM 还没有更新Vue.nextTick(function(){// DOM 更新了})// 作为一个 Promise 使用 (2.1.0 起新增,详见接下来的提示)Vue.nextTick().then(function(){// DOM 更新了})
解释:a 是一个对象,b 是对 a 的引用,即 a 和 b 指向同一块内存,所以前两个输出一样。当对 b 作修改时,即 a 和 b 指向同一块内存地址的内容发生了改变,所以 a 也会体现出来,所以第三四个输出一样。当 b 被覆盖时,b 指向了一块新的内存,a 还是指向原来的内存,所以最后两个输出不一样。
三次握手和四次挥手?
建立TCP连接时会发生:三次握手(three-way handshake)
firefox > nginx [SYN] 在么
nginx > firefox [SYN, ACK] 在
firefox > nginx [ACK] 知道了
关闭TCP连接时会发生:四次挥手(four-way handshake)
firefox > nginx [FIN] 我要关闭连接了
nginx > firefox [ACK] 知道了,等我发完包先
nginx > firefox [FIN] 我也关闭连接了
firefox > nginx [ACK] 好的,知道了
几个报文的标识的解释:
SYN: synchronization(同步)
ACK: acknowledgement(确认:告知已收到)
FIN: finish(结束)
TCP 为什么是三次握手,而不是两次或四次?
https://www.zhihu.com/question/24853633
理论上讲不论握手多少次都不能确认一条信道是“可靠”的,但通过3次握手可以至少确认它是“可用”的,再往上加握手次数不过是提高“它是可用的”这个结论的可信程度。
简单说,让双方都证实对方能发收。
知道对方能收是因为收到对方的因为收到而发的回应。
具体:
1:A发,B收, B知道A能发
2:B发,A收, A知道B能发收
3:A发,B收, B知道A能收
http状态码有那些?分别代表是什么意思?
200 OK 请求已成功,请求所希望的响应头或数据体将随此响应返回。
403 Forbidden 服务器已经理解请求,但是拒绝执行它。
404 Not Found 请求失败,请求所希望得到的资源未被在服务器上发现。
500 Internal Server Error 服务器遇到了一个未曾预料的状况,导致了它无法完成对请求的处理。一般来说,这个问题都会在服务器的程序码出错时出现。
401 Unauthorized 即“未认证”,即用户没有必要的凭据。该状态码表示当前请求需要用户验证。
403 Forbidden 服务器已经理解请求,但是拒绝执行它。与401不同的是,身份验证并不能提供任何帮助,而且这个请求也不应该被重复提交。
200 memory from cache 和 304
200 memory from cache 是不向浏览器发送请求,直接使用本地缓存文件。
304,浏览器虽然发现了本地有该资源的缓存,但是不确定是否是最新的,于是想服务器询问,若服务器认为浏览器的缓存版本还可用,那么便会返回304。
Ajax 解决浏览器缓存问题?
url加上随机数或者时间戳
LINK
你对HTTP缓存有什么了解,什么是强缓存和协商缓存?
强缓存
强缓存是利用 Expires 或者 Cache-Control 这两个响应头实现的,它们都用来表示资源在客户端缓存的有效期。
Expires 的值对应一个 GMT 时间来告诉浏览器资源缓存过期时间,如果还没过该时间点则不发请求。
Cache-Control 标头是在 HTTP/1.1 规范中定义的,取代了之前用来定义响应缓存策略的标头(例如 Expires)
协商缓存
协商缓存是利用的是 Last-Modified,If-Modified-Since 和 ETag,If-None-Match 这两对头来管理的。
客户端自动在 If-None-Match HTTP 请求标头内提供 ETag 令牌。服务器根据当前资源核对令牌。如果它未发生变化,服务器将返回 304 Not Modified 响应,告知浏览器缓存中的响应未发生变化,不必再次下载响应,这节约了时间和带宽。
请你说说 get 和 post的区别
GET 用来获取资源,POST 用来新建资源(也可以用于更新资源),PUT 用来更新资源,DELETE 用来删除资源
GET 相对 POST 的优势是:
请求中的 URL 可以被手动输入;
请求中的 URL 可以被存在书签里,或者历史里;
请求中的 URL 可以被缓存;
详见博客理解HTTP协议
https与http区别,为什么https更安全,它有什么劣势
HTTPS其实是有两部分组成:HTTP + SSL / TLS,也就是在HTTP上又加了一层处理加密信息的模块。服务端和客户端的信息传输都会通过TLS进行加密,所以传输的数据都是加密后的数据。
非对称加密算法(RSA)用于在握手过程中加密生成的会话密钥(对称密钥),
对称加密算法(DES AES)用于对真正传输的数据进行加密
而HASH算法(MD5 SHA)用于验证数据的完整性
公钥加密和私钥加密。
非对称加密 也称为公开密钥加密,需要一对密钥,一个是私人密钥,另一个则是公开密钥。这两个密钥是数学相关,用某用户密钥加密后所得的信息,只能用该用户的解密密钥才能解密。如果知道了其中一个,并不能计算出另外一个。因此如果公开了一对密钥中的一个,并不会危害到另外一个的秘密性质。称公开的密钥为公钥;不公开的密钥为私钥。
RSA是常见的公钥加密算法。
对称密钥加密 又称为私钥加密,是密码学中的一类加密算法。这类算法在加密和解密时使用相同的密钥,或是使用两个可以简单地相互推算的密钥。实务上,这组密钥成为在两个或多个成员间的共同秘密,以便维持专属的通讯联系。与公开密钥加密相比,要求双方取得相同的密钥是对称密钥加密的主要缺点之一。
常见的对称加密算法有 DES、3DES、AES 等
creeperyang/blog#1
一个页面从输入 URL 到页面加载显示完成,这个过程中都发生了什么?
1.输入地址
2.浏览器查找域名的 IP 地址,这一步包括 DNS 具体的查找过程,包括:浏览器缓存->系统缓存->路由器缓存...
3.浏览器向 web 服务器发送一个 HTTP 请求
4.服务器的永久重定向响应(从 http://example.com 到 http://www.example.com)
5.浏览器跟踪重定向地址
6.服务器处理请求
7.服务器返回一个 HTTP 响应
8.浏览器显示 HTML
9.浏览器发送请求获取嵌入在 HTML 中的资源(如图片、音频、视频、CSS、JS等等)
10.浏览器发送异步请求
如何解决跨域问题?
默认情况下,XHR对象只能访问与包含它的页面位于同一个域中的资源(协议,端口和主机都相同)
CORS
简单请求
只使用 GET, HEAD 或者 POST 数据类型(Content-Type)是 application/x-www-form-urlencoded, multipart/form-data 或 text/plain 中的一种
非简单请求(预请求)
请求以 GET, HEAD 或者 POST 以外的方法发起请求。或者,使用 POST,发送数据类型为 application/xml 或者 text/xml 的 XML 数据的请求。
不同于简单请求,“预请求”要求必须先发送一个 OPTIONS 请求给目的站点,来查明这个跨站请求对于目的站点是不是安全可接受的。
JSONP
JSONP利用没有跨域限制的 script 标签加载预设的 callback 将内容传递给 JavaScript
详见博客:CORS 跨域资源共享
CSRF 和 XSS
CSRF(跨站域请求伪造)是一种网络的攻击方式,其原理是攻击者构造接口的请求地址,诱导用户去点击或者用特殊方法让该请求地址自动加载。
防御CSRF
1.HTTP Referer 字段;
2.在请求地址中添加 token 并验证。CSRF 是因为攻击者可以完全伪造用户的请求,请求中的信息都是存在于 cookie 中,因此攻击者可以在不知道这些验证信息的情况下直接利用用户自己的 cookie 来通过安全验证。而token可以不存在cookie中。
详见博客:CSRF 与 XSS 攻击
XSS
跨站脚本(XSS)是一种安全漏洞攻击,是代码注入的一种。它允许恶意用户将代码注入到网页上,其他用户在观看网页时就会受到影响。这类攻击通常包含了HTML以及用户端脚本语言。
防御 XSS 攻击最主要的方法是过滤特殊字符,进行 HTML 转义。
Socket 和 Websocket
1.HTTP的生命周期通过Request来界定,也就是一个Request 一个Response,那么在HTTP1.0中,这次HTTP请求就结束了。
2.但是一个request只能有一个response。而且这个response是被动的,不能主动发起。
实现实时信息传递:
1.ajax轮询 的原理非常简单,让浏览器隔个几秒就发送一次请求,询问服务器是否有新信息
2.Websocket是基于HTTP协议的,或者说借用了HTTP的协议来完成一部分握手
LazyMan
思路:使用一个队列来维护任务列表,通过返回 this 来实现链式调用,为了在任务队列中先 push 完所有任务然后再依次执行,添加上 setTimeout 函数
详见博客:如何实现一个LazyMan
前端性能优化的方法(JS/CSS)?
1.减少/最小化 http 请求数
2.延迟加载组件
3.使用CDN
4.加Expires或者Cache-Control头部
5.传输时用gzip等压缩组件
6.把样式放在顶部
7.把脚本放到底部
8.压缩JS和CSS
前端的性能优化大头基本上在网络这个层面,除了已经过时的雅虎军规,基本上离不开缓存、懒加载、组件or路由级别的代码分割,还有一些节流、防抖、静态请求等比较难一点的,现在比较时髦的pwa和http2也是工具本身对前端的优化
Webpack打包优化?
CommonsChunkPlugin提取公共代码块
UglifyJS代码压缩
happypack 多进程去处理文件
alias
Webpack为什么这么难用?
webpack 的插件是面向配置的,而不是面向过程的
什么叫面向过程?如果你知道或者使用过 gulp 这个自动化工具的话,应该会记得 gulp 管道的概念,即从源头那里得到源数据(js/css/html 源码、图片、字体等等),然后数据通过一个又一个组合起来的管道,最后输出成为构建的结果。写成伪代码的话,大概是这样:
配置会随着复杂度的提升,而也逐渐变得复杂,维护越来越难,直到超过某个临界值,就会需要在它的基础上进一步封装,产生新的配置化。
gulp流程控制
模块化编程怎么做,AMD、CMD规范区别?
1.简单的模块:函数 ->
2.闭包,IIFE 模式->
3.CommonJS 规范加载模块是同步的,只有加载完成,才能执行后面的操作。
4.AMD 规范则是非同步加载模块,允许指定回调函数, 推崇依赖前置,提前执行,在定义模块的时候就引入了其他模块,在模块当中已经是可用状态。
5.CMD提倡依赖就近,在需要使用到某个模块的时候,才进行引入。->
6.Webpack 是一个用于现代 JavaScript 应用的模块打包器(module bundler),它能够分析你的项目结构,找到 JavaScript 模块以及一些浏览器无法运行的语言(Scss,TypeScript等),并将其打包成合适的格式供浏览器使用。->
7.ES6 模块
模块化用于解决解决命名冲突与文件依赖
LINK
详见博客JavaScript的模块化编程
commons es6 区别?
CommonJS模块输出的是被输出值的拷贝,也就是说,一旦输出一个值,模块内部的变化就影响不到这个值。ES6模块是动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块。
requirejs,amd原理
加载模块A -> 遍历依赖,加载各依赖(B,C) ->请求各依赖模块(B,C)->
B模块请求完成了 -> B模块和他的依赖都载入好了 -> C模块请求完成了 -> C模块和他的依赖都载入好了
React优化?
shouldComponentUpdate
React.PureComponent:如果组件的
props
和state
都没发生改变,render
方法就不会触发,它只做一个浅比较使用不可突变的数据结构:
不可突变数据使得变化跟踪很方便。每个变化都会导致产生一个新的对象,因此我们只需检查索引对象是否改变
super(props)意义?
为了在
constructor
内使用this.props
。当向super
传递参数props
,才能在当前this
中访问到props
react 取消 AJAX 请求
如果组件在 AJAX 请求完成之前被卸载了,那么你会在浏览器的控制面板上看到一条警告:
cannot read property 'setState' of undefined
。如果这对你来说是个问题的话,你可以追踪未完成的 AJAX 请求并在componentWillUnmount
生命周期方法内将它们取消。react 的 setState()?
setState调用引起的React的更新生命周期函数4个函数(比修改prop引发的生命周期少一个componentWillReceiveProps函数),这4个函数依次被调用。
什么时候应该选择用class实现一个组件,什么时候应该用一个函数实现一个组件?
使用类就允许我们使用其它特性,例如局部状态、生命周期钩子
React / Vue组件的各个生命周期函数吗?
什么是HoC(Higher-Order Component)?适用于什么场景?
高阶组件就是一个函数,且该函数接受一个组件作为参数,并返回一个新的组件
高阶组件属于函数式编程思想,对于被包裹的组件时不会感知到高阶组件的存在,而高阶组件返回的组件会在原来的组件之上具有功能增强的效果。
而Mixin这种混入的模式,会给组件不断增加新的方法和属性,组件本身不仅可以感知,甚至需要做相关的处理(例如命名冲突、状态维护),一旦混入的模块变多时,整个组件就变的难以维护。
Vue 和 Angular 和 React 区别 如何选择?
React 和 Vue 都有:
模板渲染方面:React 使用 JSX(JS 自带的流程控制、直接引用 JS 作用域中的值) ,而 Vue 使用 template(读写自然,简单,设计师和新人易参与)
Vue支持双向绑定,但组件间的数据传递 Vue 默认是单向的,和 React 一样。
Weex 成熟度不能和 React Native 相抗衡
Mobx 在 React 社区很流行,实际上在 Vue 也采用了几乎相同的反应系统
React 的 Virtual DOM 也是需要优化的。
手动添加 shouldComponentUpdate 来避免不需要的 vdom re-render;
Components 尽可能都用 pureRenderMixin,然后采用 Flux 结构 + Immutable.js。
相比之下,Vue 由于采用依赖追踪,默认就是优化状态:你动了多少数据,就触发多少更新,不多也不少。
React/Vue virtual dom原理?diff算法?
Vue 2.0 引入 vdom 的主要原因是 vdom 把渲染过程抽象化了,从而使得组件的抽象能力也得到提升,并且可以适配 DOM 以外的渲染目标(SSR,跨平台)。
数据是否更新跟 虚拟 DOM 关系不大。
虚拟 DOM来确保只对界面上真正变化的部分进行实际的DOM操作
过程:
oldNode 为空时,新节点可以整体作为子树,插入 $parent 中:
newNode 为空时,从 $parent 中根据下标,移除该位置的节点:
既然当前节点类型已经改变,那么直接将当前节点及其下的子节点全量替换掉即可
对当前节点下的所有子节点,递归调用 updateElement 自身,来实现对新旧节点下子树的遍历
谈一谈 shouldComponentUpdate
实现
shouldComponentUpdate
时,不可突变的数据结构帮助我们轻松的追踪对象变化。这通常可以提供一个不错的性能提升React有 shouldComponentUpdate 的原因是因为 React 的 diff 不是 diff 的数据,而是 diff 的html tag。
React Context?
Context 通过组件树提供了一个传递数据的方法,从而避免了在每一个层级手动的传递 props 属性。
单向数据流和双向绑定?
对于非UI控件来说,不存在双向,只有单向。只有UI控件才有双向的问题。
单向绑定使得数据流也是单向的,对于复杂应用来说这是实施统一的状态管理(如redux)的前提。
双向绑定在一些需要实时反应用户输入的场合会非常方便(比如多级联动菜单)。但通常认为复杂应用中这种便利比不上引入状态管理带来的优势。
Vuex 的 state 上使用
v-model
会比较棘手,会抛出一个错误,用『Vuex 的思维』去解决这个问题的方法是:给 中绑定 value,然后侦听 input 或者 change 事件,在事件回调中调用 action。这样做比简单地使用 v-model 要啰嗦得多,但这换来的是 state 的改变更加清晰和可被跟踪。Vuex 并不强制要求所有的状态都必须放在 Vuex store 中 ,你完全可以把它放在 Vuex 外面(比如作为组件的本地状态)。Vue2 双向绑定原理?
Vue 数组更新检测?
Vue 包含一组观察数组的变异方法,所以它们也将会触发视图更新。
Vue.nextTick 实现原理
在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。
难道 vue 是用 MutationObserver 监听 DOM 更新完毕的?
并不是,每次 event loop 的最后,会有一个 UI render 步骤,也就是更新DOM。
每一次事件循环都包含一个microtask队列,在循环结束后会依次执行队列中的microtask并移除,然后再开始下一次事件循环。
Vue和React的key的作用?
当 Vue.js 用
v-for
正在更新已渲染过的元素列表时,它默认用“就地复用”策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序, 而是简单复用此处每个元素。Diff算法只会比较同一层级的节点:
如果节点类型不同,直接干掉前面的节点,再创建并插入新的节点。
如果节点类型相同,则会重新设置该节点的属性,从而实现节点的更新。
我们希望可以在B和C之间加一个F,Diff算法默认执行起来是这样的:即把C更新成F,D更新成C,E更新成D,最后再插入E,是不是很没有效率?
所以我们需要使用key来给每个节点做一个唯一标识,Diff算法就可以正确的识别此节点,找到正确的位置区插入新的节点。
key的作用主要是为了高效的更新虚拟DOM。
谈一谈不可变数据和immutable.js
Redux 源码
https://www.zhihu.com/question/63726609
https://www.zhihu.com/question/41312576
为什么使用MobX?
MobX与Redux比较?
react router 源码
hash
history api
vuex源码?
集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测(来源于同步的 mutation 或纯函数的 reducer )的方式发生变化。
Vuex 使用单一状态树
更改 Vuex 的 store 中的状态的唯一方法是提交 mutation [mju'teʃən],因为 devtools 不知道什么时候回调函数实际上被调用
Action 提交的是 mutation,而不是直接变更状态,Action 可以包含任意异步操作
Vue有哪些不足和缺点
angular的脏值检测和依赖注入如何实现
首先 DOMCompiler 会先发现 ng-controller 指令。然后会调用这个指令的 link 函数生成一个新的 scope 对象传递给 controller 的 invoke 函数。
DOMCompiler 会发现 ng-bind 然后为
$watch
bar。并且还发现了 ng-click 同时添加 click 事件到按钮上。一旦用户点击了按钮,foo函数就会通过
scope.$eval
执行。使用的 scope 对象就是传递给 MainCtrl 的 scope 对象。这之后 ng-click 会执行脏检测$scope.$digest
。脏检测循环会遍历所有的监控表达式,发现 bar 的值变化了。因为我们添加了对应的回调函数,所以就执行它更新span的内容。Scope.$eval
Scope.$digest
ng-model
依赖注入
依赖注入是一种编程模式,可以让类从外部源中获得它的依赖,而不必亲自创建它们。
为什么使用服务端渲染?
与传统 SPA(Single-Page Application - 单页应用程序)相比,服务器端渲染(SSR)的优势主要在于:
更好的 SEO,由于搜索引擎爬虫抓取工具可以直接查看完全渲染的页面。
更快的内容到达时间(time-to-content),特别是对于缓慢的网络情况或运行缓慢的设备。无需等待所有的 JavaScript 都完成下载并执行,才显示服务器渲染的标记,所以你的用户将会更快速地看到完整渲染的页面。
使用服务器端渲染(SSR)时还需要有一些权衡之处:
从一个子路由点返回键或者 history.go(-1) 返回上一级页面时怎么样传递参数?
以路由方式跳转到上一个页面,而非返回 2.可以通过store或者vuex,实现数据共享。
把 xxx-sss 字符串转换为驼峰式
生产者消费者
生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。
TCP 长连接短连接
在HTTP/1.0中默认使用短连接。客户端和服务器每进行一次HTTP操作,就建立一次连接,任务结束就中断连接。
而从HTTP/1.1起,默认使用长连接,用以保持连接特性。使用长连接的HTTP协议,会在响应头加入这行代码:
在使用长连接的情况下,客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭,客户端再次访问这个服务器时,会继续使用这一条已经建立的连接。Keep-Alive不会永久保持连接,它有一个保持时间,可以在不同的服务器软件(如Apache)中设定这个时间。
HTTP协议的长连接和短连接,实质上是TCP协议的长连接和短连接。
相比HTTP长连接,WebSocket有以下特点:
实现超出整数存储范围的两个大正整数相加 function add(a, b)
为什么 0.1 + 0.2 != 0.3,请详述理由
因为 JS 采用 IEEE 754 双精度版本(64位),并且只要采用 IEEE 754 的语言都有该问题。
10 个 Ajax 同时发起请求,全部返回展示结果,并且至多允许三次失败,说出设计思路
Event Loop 事件循环
主线程从"任务队列"中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为Event Loop
一个事件循环 (Event Loop) 会有一个或多个任务队列 (task queue,又称 task source),这里的 task queue 就是 macrotask queue,而 Event Loop 仅有一个 microtask queue。每个线程都有一个独立的 Event Loop,所以每个 web worker 也有独立的 Event Loop
最基本的 Event Loop 如图所示:
宏任务队列(macro tasks)和微任务队列(micro tasks)
macrotask 是严格按照时间顺序压栈和执行的。当一个 task 执行结束后,在下一个 task 执行开始前,浏览器可以对页面进行重新渲染。主要包含:setTimeout,setInterval,setImmediate,I/O,UI交互事件
microtask 通常来说就是需要在当前 task 执行结束后立即执行的任务。主要包含:Promise的回调函数,MutaionObserver
ALetterSong/Note#16
不可变对象
number,string
前端巨量长列表优化?
使用DocumentFragment
DocumentFragments 是一些DOM节点。它们不是DOM树的一部分。
因为文档片段存在与内存中,并不在DOM树中,所以将子元素插入到文档片段时不会引起页面回流(reflow),可以优化性能。
懒加载(分页)
监听父元素的 scroll 事件(一般是 window),通过父元素的 scrollTop 判断是否到了页面是否到了页面底部,如果到了页面底部,就加载更多的数据。
可视区域渲染
通过
reduce
函数来实现简单的数组求和,示例数组[3,4,8,0,9]
requestAnimationFrame 原理?是同步还是异步?
window.requestAnimationFrame() 方法告诉浏览器您希望执行动画并请求浏览器在下一次重绘之前调用指定的函数来更新动画。
它能保证回调函数在屏幕每一次的刷新间隔中只被执行一次,这样就不会引起丢帧现象,也不会导致动画出现卡顿的问题。
js bind 实现机制?手写一个 bind 方法?
用 JS 实现双向链表?
页面性能检测
JS 实现
String.trim()
方法前端开发的难点
https://www.zhihu.com/question/275915023
写一个babel插件
Babel 的三个主要处理步骤分别是: 解析(parse) => 转换(transform) => 生成(generate)
解析
解析是将最初原始的代码转换为一种更加抽象的表示,即AST。 这个步骤分为两个阶段:词法分析 (Lexical Analysis) 和语法分析 (Syntactic Analysis)
词法分析
词法分析接收原始代码,然后把它分割成一些被称为 Token 的东西
语法分析
语法分析接收之前生成的 Token,把它们转换成一种抽象的表示,这种抽象的表示描述了代码语句中的每一个片段以及它们之间的关系。这被称为抽象语法树(Abstract Syntax Tree, 缩写为AST)
转换
转换步骤接收 AST 并对其进行遍历,在此过程中对节点进行添加、更新及移除等操作。 这是 Babel 或是其他编译器中最复杂的过程 同时也是插件将要介入工作的部分。
生成
代码生成步骤通过深度优先遍历整个 AST,把最终(经过一系列转换之后)的 AST 转换成字符串,同时创建源码映射(source maps)。
react组件通信?
sunyongjian/blog#27
一个 connect 怎么做到注入 state 的
响应式编程和声明式编程和命令式编程?
300ms点击延迟?
FastClick 在检测到
touchend
事件的时候,会通过 DOM 自定义事件立即触发一个模拟click
事件,并把浏览器在 300 毫秒之后真正触发的click
事件阻止掉。对于缩放被禁用的网站,Android 平台上的 Chrome 和 Firefox 浏览器会禁用双击缩放功能;如果站点内配置了内容为
width=device-width
的<meta>
标签,Chrome 32 及以上版本的浏览器也会禁用双击缩放功能JS值比较?
[] == [] 这个好理解. 当两个值都是对象 (引用值) 时, 比较的是两个引用值在内存中是否是同一个对象. 因为此 [] 非彼 [], 虽然同为空数组, 确是两个互不相关的空数组, 自然 == 为 false.
[] == ![] 这个要牵涉到 JavaScript 中不同类型 == 比较的规则, 具体是由相关标准定义的. ![] 的值是 false, 此时表达式变为 [] == false, 参照标准, 该比较变成了 [] == ToNumber(false), 即 [] == 0. 这个时候又变成了 ToPrimitive([]) == 0, 即 '' == 0, 接下来就是比较 ToNumber('') == 0, 也就是 0 == 0, 最终结果为 true.
JavaScript 中不同类型以及不同环境下变量的内存都是何时释放?
引用类型是在没有引用之后, 通过 v8 的 GC 自动回收, 值类型如果是处于闭包的情况下, 要等闭包没有引用才会被 GC 回收, 非闭包的情况下等待 v8 的新生代 (new space) 切换的时候回收.
module.exports 与 exports 的区别
运行 test.js 结果为:
{ name: 1 }{ name: 1 }{ name: 2 }{ name: 2 }{ name: 2 }{ name: 3 }
解释:a 是一个对象,b 是对 a 的引用,即 a 和 b 指向同一块内存,所以前两个输出一样。当对 b 作修改时,即 a 和 b 指向同一块内存地址的内容发生了改变,所以 a 也会体现出来,所以第三四个输出一样。当 b 被覆盖时,b 指向了一块新的内存,a 还是指向原来的内存,所以最后两个输出不一样。
明白了上述例子后,我们只需知道三点就知道 exports 和 module.exports 的区别了:
Promise 中 .then 的第二参数与 .catch 有什么区别?
使用
promise.then(onFulfilled, onRejected)
的话在
onFulfilled
中发生异常的话,在onRejected
中是捕获不到这个异常的。在
promise.then(onFulfilled).catch(onRejected)
的情况下then
中产生的异常能在.catch
中捕获是否只要有回调函数就是异步?
单纯使用回调函数并不会异步, IO 操作才可能会异步, 除此之外还有使用 setTimeout 等方式实现异步.
取消一个Promise?
Generator
async 函数是 Generator 函数的语法糖。
实现 co
异步顺序输出
async/await 比 yield 好在哪里?
async/await 相对于 Generator,
1)语义上更容易理解一些
2)async/await 更规范一些,后面只能接 Promise,并且返回的也是 Promise,而 Promise 对开发者也是隐形的。而 Generator 只是迭代器的一个子类型,设计时并不是拿来解决异步问题,只是我们发现可以用来解决问题。
RxJS
RxJS 是用来解决异步和事件组合问题
Observable = 异步数组 = 数组 + 时间轴 = stream
用 setTimeout 实现 setInterval
indexOf和findIndex的区别
Array.prototype.findIndex 是一个回调函数,Array.prototype.indexOf 有两个参数,第一个是需要查找的元素,第二个参数从哪个位置开始查找
代码题:
react 中的某个组件嵌套很深,怎么传递 props?
Context , 发布订阅模式,mobx/redux
并行与并发?
并发的关键是你有处理多个任务的能力,不一定要同时。
并行的关键是你有同时处理多个任务的能力。
并发(Concurrent)的反面是串行。串行好比多个车辆行驶在一股车道上,它们只能“鱼贯而行”。而并发好比多个车辆行驶在多股车道上,它们可以“并驾齐驱”。
并发的极致就是并行(Parallel)。
并发与多线程?
多线程是将串行的计算“改为”并发(并行)的一种方式,并发编程还有其他的实现途径,例如函数式编程。
异步可以用来处理并发
JavaScript 上存在并发(concurrency),各种IO都算,JavaScript 的并发模型基于"事件循环"。不存在的是并行(parallel)
JS 模拟一个并发
Ecmascript 规范里并无与多线程有关的内容,js 的多线程/多进程是由运行环境提供的,通过消息通信传递数据,而且没有语法糖。
在 GUI 编程里,单一线程控制 GUI,应该是一个非常普遍的做法。
function fun() {} 的原型指向哪里 ?
Function.prototype。
代码题,输出顺序
CSS in JS
styled-components 消除dom和css之间做映射,小型化组件,分离容器组件和展示组件
缺点是 场景复杂时的props管理和生成的 className 通常是不稳定的随机串,这就给外部想灵活覆盖样式增加了困难
其他题目 sunyongjian/blog#32
The text was updated successfully, but these errors were encountered: