中级前端面试题必备知识点(2.5w+月薪)进阶
中级前端面试题必备知识点(2.5w+月薪)进阶
&時光
于 2021-05-09 19:27:38 发布
510
收藏 11
分类专栏: vue react javascript 文章标签: html vue.js reactjs javascript css
版权
vue
同时被 3 个专栏收录
30 篇文章0 订阅
订阅专栏
react
20 篇文章0 订阅
订阅专栏
javascript
38 篇文章0 订阅
订阅专栏
中级前端面试题必备知识点(2.5w+月薪)进阶
前端已经不再是5年前刚开始火爆时候的那种html+css+js+jquery的趋势了,现在需要你完全了解前端开发的同时,还要具备将上线、持续化、闭环、自动化、语义化、封装......等概念熟练运用到工作中的一个职业,甚至用人部门还希望你了解并掌握深度学习及机器学习的相关概念。在面试过程中,各部门交叉面试的时候会提问一些关于后端的知识。
假如你想要拿到2.5w+月薪,你的能力应该达到掌握以下全部知识点并有过开发后端接口与数据处理(node、java、c......必须掌握一种)的经验。本文就是结合自己的工作、面试经验,同时为那些想要冲击2w+薪资的1-3年新手们准备的。
需要注意的是,所有大厂的社招会按照你当前工作经验进行+1,+2的难度提升(假设你工作一年,会按照三年工作经验进行招聘,同时二三面会按照你的项目经验进行择优筛选)所以起步是互联网公司的同学占了很大的优势,有些小伙伴在国企工作一年~三年,项目经验的欠缺导致竞争力不足,没别的办法,建议早日跳出自己的舒适圈,之后你会体会到不一样的前端开发。以下是面试时高频出现且必须要掌握的知识点
坚持不懈,必能成功。已于21年初加入网易大前端。特来还愿。希望看到这篇文章的小伙伴早日实现大厂梦~~~
1、mock
在前后端分离的开发中,Mock 数据是前端开发中很重要的一个环节,前端可以不必强依赖后端接口,只需要约定好对应的数据接口,前端可以通过 Mock 模拟数据先行开发,在后端接口开发完成后,只需要切换对应的接口地址即可,可以保证项目的同步开发。
本地内容:在mock文件夹下中的index文件中定义好自有的接口路径,再到根目录的service文件夹下生成对应业务模块的js文件。文件内将相应微服务的接口匹配好。暴露出去供业务功能调用。
2、网络请求编码表示
会从你是否关注Request head的哪些内容入手,一般关注点放在statusCode和method上就够用,重点200,304。同时掌握了基础后希望注意的点为文件上传的内容(百度问过断点续传的实现)
200: '服务器成功返回请求的数据。',
201: '新建或修改数据成功。',
202: '一个请求已经进入后台排队(异步任务)。',
204: '删除数据成功。',
304:协商缓存
400: '发出的请求有错误,服务器没有进行新建或修改数据的操作。',
401: '用户没有权限(令牌、用户名、密码错误)。',
403: '用户得到授权,但是访问是被禁止的。',
404: '发出的请求针对的是不存在的记录,服务器没有进行操作。',
406: '请求的格式不可得。',
410: '请求的资源被永久删除,且不会再得到的。',
422: '当创建一个对象时,发生一个验证错误。',
500: '服务器发生错误,请检查服务器。',
502: '网关错误。',
503: '服务不可用,服务器暂时过载或维护。',
504: '网关超时。'
写给新手前端的各种文件上传攻略,从小图片到大文件断点续传 - 掘金juejin.im
3、axios工作流程
axios 是一个基于Promise 用于浏览器和 nodejs 的 HTTP 客户端,本质上也是对原生XHR的封装,只不过它是Promise的实现版本,符合最新的ES规范,它本身具有以下特征:
1.从浏览器中创建 XMLHttpRequest
2.支持 Promise API
3.客户端支持防止CSRF
4.提供了一些并发请求的接口(重要,方便了很多的操作)
5.从 node.js /java创建 http 请求
6.拦截请求和响应
7.转换请求和响应数据
8.取消请求
9.自动转换JSON数据
防止CSRF:就是让你的每个请求都带一个从cookie中拿到的key, 根据浏览器同源策略,假冒的网站是拿不到你cookie中得key的,这样,后台就可以轻松辨别出这个请求是否是用户在假冒网站上的误导输入,从而采取正确的策略。
/**
*
*
* @param {*} params mmsi
* @param {*} callback
*
*
*/
getship_cargo_detail:function(params,callback){
axios.get(server.portAddress+"newshipcargo/newship_pos_detail",{params})
.then(function(res){
callback(res.data);
})
.catch(function(error){
console.log("get_ship_cargo_data_error");
})
},
//调用方法
shipcargoserver.getship_cargo_detail({mmsi:mmsi},data=>{
if(data){
this.setState({
pageNumber:data.,,,,,,,
})
}
})
4、ElementUI(ElementReact)与antdesign和ice-work的比较
使用Element的原因是通过学习饿厂的 Element
其设计原则可以兼容三大框架 (三大框架各有实现):
Vue Element
React Element
Angular Element
整体上 UI 都是一套,但在不同框架中实现方式各异,API 变更较小,如果需要多个框架保持一套风格, Element 是非常好的选择。为了减少学习变更后项目api
antdesign功能极强,主要用来学习与观摩,模仿其语法及代码风格,主要基于React组件库的支持。感觉唯一的不足时在于当时使用时缺少一些在线预览的功能,最近又出了antdvue
飞冰最有意思的是钉钉群实时答疑让p7给你答疑(前提是混入群中)。500+ ICE 使用者在群里问任何层级的前端问题
React 组件。基础组件使用 Fusion,此外根据业务特性等开发了 40+ 业务组件
Playground:可复用模板,用于快速展示效果的业务。
5、WebRequest
API 可以让插件监控 Chrome 的网络请求,甚至重定向请求。例如:临时替换hotfix分支的图片
// background.js
chrome.webRequest.onBeforeRequest.addListener(
function (details) {
const url = details.url;
if (url === 'http://n.sinaimg.cn/news/1_img/upload/7b577cec/576/w778h598/20180820/lSSg-hhxaafy9194151.jpg') {
console.log(22)
return {
redirectUrl: 'https://github.com/welearnmore/chrome-extension-book/raw/master/doc/images/logo_google_developers.png'
}
}
return {cancel: false}
},
{urls: ["<all_urls>"]},
["blocking"]
)
6、减少reflow的方法
不要一条一条地修改 DOM 的样式。与其这样,还不如预先定义好 css 的 class,然后修改 DOM 的 className:
// 不好的写法 var left = 10, top = 10; el.style.left = left + "px"; el.style.top = top + "px"; // 推荐写法 el.className += " theclassname";
把 DOM 离线后修改。如:
a> 使用 documentFragment 对象在内存里操作 DOM。
b> 先把 DOM 给 display:none (有一次 repaint),然后你想怎么改就怎么改。比如修改 100 次,然后再把他显示出来。
c>clone 一个 DOM 节点到内存里,然后想怎么改就怎么改,改完后,和在线的那个的交换一下。
不要把 DOM 节点的属性值放在一个循环里当成循环里的变量。不然这会导致大量地读写这个结点的属性。
尽可能的修改层级比较低的 DOM节点。当然,改变层级比较底的 DOM节点有可能会造成大面积的 reflow,但是也可能影响范围很小。
为动画的 HTML 元件使用 fixed 或 absoult 的 position,那么修改他们的 CSS 是会大大减小 reflow 。
千万不要使用 table 布局。因为可能很小的一个小改动会造成整个 table 的重新布局。
参考:
人类身份验证 - SegmentFaultsegmentfault.com
深刻剖析回流与重绘:
你真的了解回流和重绘吗 - 掘金juejin.im
7、微任务与宏任务与eventloop
重点记住promise在.then之前是同步任务,.then/.catch/.finally是微任务,执行完同步任务后,在异步中最先执行的就是promise
执行顺序:同步任务--->微任务--->宏任务
参考
微任务、宏任务与Event-Loop - 贾顺名 - 博客园www.cnblogs.com
8、隐式转换全部情况
!![] == true //结果是true
[] == true //结果是false
![] == [] //结果是true
针对[] == true 与!![]的解释参考:
https://blog.csdn.net/u014465934/article/details/84642329blog.csdn.net
记忆方式
[] 转为字符串是 "" // String([]) 返回""
[] 转为数字是 0 // Number([]) 返回0
[] 转为布尔值是 true // Boolean([]) 返回true
true 转为数字是 1 // Number(true) 返回1
false 转为数字是 0 // Number(false) 返回0
参考全部隐式转化规则
https://blog.csdn.net/qq_42532128/article/details/84940906blog.csdn.net
9、webstorage
着重点在于sessionstorage与localstorage的数据存储机制及处理机制。
WebStorage是什么?www.jianshu.com
10、如何使用sessionID判别用户状态
将cookie中放入响应头中携带相应sessionID通过post方式向后端发请求,后端返回结果为用户独特的sessionID与前端匹配,则不用创建新的sessionID,假若不匹配则需要创建一个新的sessionID,归根结底还是由于HTTP的无状态性,web容器生成一个sessionid来标识用户,以便获取该用户对应的session信息。
后台生成一个新sessionid的可能原因:
这是一个新用户的第一次请求
后端存在清空session的逻辑
前端没有将sessionid放到cookie或其他约定的地方传给后端
前端传了,但后端没有匹配到对应的sessionid(如果是个分布式服务,负载均衡后,后端服务没有做session同步)
11、OAuth2原理及应用
允许用户授权第三方移动应用访问他们存储在另外的服务提供者上的信息,而不需要将用户名和密码提供给第三方移动应用或分享他们数据的所有内容,OAuth2.0是OAuth协议的延续版本,但不向后兼容OAuth 1.0即完全废止了OAuth1.0。
应用场景:
原生app授权:app登录请求后台接口,为了安全认证,所有请求都带token信息,如果登录验证、请求后台数据。
前后端分离单页面应用(spa):前后端分离框架,前端请求后台数据,需要进行oauth2安全认证,比如使用vue、react后者h5开发的app。
流程:
(A)用户打开客户端以后,客户端要求用户给予授权。
(B)用户同意给予客户端授权。
(C)客户端使用上一步获得的授权,向认证服务器申请令牌。
(D)认证服务器对客户端进行认证以后,确认无误,同意发放令牌。
(E)客户端使用令牌,向资源服务器申请获取资源。
(F)资源服务器确认令牌无误,同意向客户端开放资源。
12、http://socket.io的前端使用
客户端和服务器之间的低延迟双向通信。客户端应用程序可以使用 Javascript的任何 SocketIO 官方客户端库或任何兼容的客户端来建立与服务器的永久连接。
引入http://socket.io的依赖在react框架中进行使用,自己尝试实现了一个聊天室:
testconnect=()=>{
let socket = sockjs("ws://localhost:3900", {
transports: ['websocket']
})
// /不间断尝试重连接
socket.on('reconnect_attempt',()=> {
console.log("reconnect")
socket.transports = ['websocket','polling', 'flashsocket'];
});
// 重连接时出错
socket.on('reconnect_error',(attemptNumber)=> {
console.log(attemptNumber)
});
//连接成功走这个方法
socket.on('connect',()=>{
console.log(socket.connected)
})
//报错时走这个方法
socket.on('connect_error', (error) => {
console.log(error)
});
//连接存活验证
socket.on('ping', (error) => {
console.log('ping_include')
});
// 连接成功的connect方法
socket.on("connect",function(){
// console.log(socket.broadcast)
socket.emit('join',prompt('what is your nickname'));
$('#chat').css('display','block');
socket.on('announcement',(msg)=>{
if(msg){
console.log("announcement did right")
let li = `<li class="announcement">${msg}</li>`
$("#messages").append(li);
}
})
})
// 添加获取信息的方法
$("#form").submit(()=>{
let inputan =$('#input');
console.log("submit success")
this.addmessage('me',inputan.val()) ;
socket.emit('text',inputan.val());
inputan.attr('value');
inputan.focus();
return false
} )
//不要自执行,要在调用后再执行
socket.on('text',this.addmessage)
}
// 将聊天记录添加到首页的每一个字段上
addmessage=(from,text)=>{
if(text){
let li = `<li class="message"><b>${from}</b>:${text}</li>`
$("#messages").append(li);
}
}
13、webpack的作用及核心配置
webpack配置中需要理解几个核心的概念Entry 、Output、Loaders 、Plugins、 Chunk
Entry:指定webpack开始构建的入口模块,从该模块开始构建并计算出直接或间接依赖的模块或者库
Output:告诉webpack如何命名输出的文件以及输出的目录
Loaders:由于webpack只能处理javascript,所以我们需要对一些非js文件处理成webpack能够处理的模块,比如sass文件
Plugins:Loaders将各类型的文件处理成webpack能够处理的模块,plugins有着很强的能力。插件的范围包括,从打包优化和压缩,一直到重新定义环境中的变量。但也是最复杂的一个。比如对js文件进行压缩优化的UglifyJsPlugin插件
Chunk:coding split的产物,我们可以对一些代码打包成一个单独的chunk,比如某些公共模块,去重,更好的利用缓存。或者按需加载某些功能模块,优化加载时间。在webpack3及以前我们都利用CommonsChunkPlugin将一些公共代码分割成一个chunk,实现单独加载。在webpack4 中CommonsChunkPlugin被废弃,使用SplitChunksPlugin
webpack详解 - 掘金juejin.im
webpack打包原理解析www.jianshu.com
进阶(具备手撸一个loader、plugins的能力):
干货!撸一个webpack插件(内含tapable详解+webpack流程) - 掘金juejin.im
手把手教你撸一个 Webpack Loaderjuejin.im
14、==与===的比较,===的使用情况
===的使用情况我回答是,一般在比较字符串时来使用。
权威解释:
理清JS中等于(==)和全等(===)那些纠缠不清的关系 - 掘金juejin.im
15、闭包的应用场景
函数防抖,通过立即执行函数在循环中的异步执行能够取到正确的值
权威解答:
闭包实际场景应用 - 掘金juejin.im
16、敏捷开发的全部流程
每次迭代都必须依次完成以下五个步骤。
需求分析(requirements analysis)
设计(design)
编码(coding)
测试(testing)
部署和评估(deployment / evaluation)
每个迭代大约持续2~6周。
敏捷开发入门教程 - 阮一峰的网络日志www.ruanyifeng.com
17、webpack+glup/FIS
gulp是基于流的自动化构建工具,但不包括模块化的功能,如果要用到的话,就需要引入外部文件,比如require.js等;而webpack是自动化模块打包工具,本身就具有模块化,并且也具有压缩合并的功能。
【简单理解】gulp和webpack的区别 - MaxLucio - 博客园www.cnblogs.com
三者的比较
定位不同,webpack定位是一个打包工具,模块化。其实自动化的工具更好用gulp之类解决。fis3直接定位为一个全功能工具,官方文档介绍中:解决性能优化,模块化,自动化,甚至包括代码规范,部署等问题。
个人喜欢用webpack,可以更灵活的搭配其它工具使用,且生态系统强大,当然最近比较火的可能是rollup,它打包的文件体积更小。glup+webpack自动化部署参考:
https://www.cnblogs.com/axl234/p/5845606.htmlwww.cnblogs.com
18、git常用的基本命令
最最基础的去参考我自己的文章,进阶版看这篇
git基本操作,一篇文章就够了! - 掘金juejin.im
19、jar包查看项目进程
到xxx.jar目录下执行:
nohup java -jar xxx.jar > people.log 2>&1 & -- 运行jar包并包日志写入到people.log中
tail -f people.log --查看运行日志
20、mvc与mvvm的区别
mvc
Model(模型)
View(视图)
Controller(控制器)
简单的理解:视图请求数据,将请求发送至控制器,控制器再将请求发送给模型,模型去查找数据,找到之后传给控制器,控制器再传给视图进行渲染。
mvvm
Model 代表数据模型
View 代表UI视图
ViewModel 负责监听 Model 中数据的改变并且控制视图的更新(桥梁,可以理解成mvc中的控制器) 简单理解:视图请求数据,将请求发送至控制器,在控制器的两端具有监听机制,直接调用模型的数据,一端改变全部改变,利用数据劫持,结合订阅者和发布者模式,实现数据的双向绑定
mvvm优点
MVVM比MVC精简很多,不仅简化了业务与界面的依赖,还解决了数据频繁更新的问题,不用再用选择器操作DOM元素。因为在MVVM中,View不知道Model的存在,Model和ViewModel也观察不到View,这种低耦合模式提高代码的可重用性
双向绑定的定义
一般只有UI表单控件才存在双向数据绑定,非UI表单控件只有单向数据绑定。
单向数据绑定是指:M的变化可以自动更新到ViewModel,但ViewModel的变化需要手动更新到M(通过给表单控件设置事件监听)
双向数据绑定是指念:M的变化可以自动更新到ViewModel,ViewModel的变化也可以自动更新到M
双向绑定 = 单向绑定 + UI事件监听。双向和单向只不过是框架封装程度上的差异,本质上两者是可以相互转换的。
优缺点:在表单交互较多的情况下,单向数据绑定的优点是数据更易于跟踪管理和维护,缺点是代码量较多比较啰嗦,双向数据绑定的优缺点和单向绑定正好相反。
理解MVVM在react、vue中的使用 - _林冲 - 博客园www.cnblogs.com
MVVM模式在react中的对应关系
M(odel):对应组件的方法或生命周期函数中实现的业务逻辑和this.state中保存的本地数据,如果React集成了redux +react-redux,那么组件中的业务逻辑和本地数据可以完全被解耦出来单独存放当做M层,如业务逻辑放在Reducer和Action中。
V(iew)-M(odel):对应组件中的JSX,它实质上是Virtual DOM的语法糖。React负责维护 Virtual DOM以及对其进行diff运算,而React-dom 会把Virtual DOM渲染成浏览器中的真实DOM
View:对应框架在浏览器中基于虚拟DOM生成的真实DOM(并不需要我们自己书写)以及我们书写的CSS
绑定器:对应JSX中的命令以及绑定的数据,如className={ http://this.props.xxx }、{http://this.props.xxx}等等
21、html语义化,css模块化
就是尽可能的理解要表达的内容,选择适合的标签,将内容转换成浏览器认识的语言,通过浏览器传达给用户。从这个角度来说,我们更像是“翻译”。
除了专业的人外,没人会去看我们的标签是否使用得有语义
HTML的标签还不足以表达所有可能的语义
语义化会需要增加一些额外的代码
HTML5新增的几个标签,更多的补充了目前HTML标签语义上的不足,这点也可以看出语义化是以后发展的一个方向,当然更大的目标是统一的实现标准,语义化只是为了这个目标所使用的一个方法。这可能需要相当的一段时间,而我们正经历着这个过程。
模块化
模块化就是为了减少循环依赖,减少耦合,提高设计的效率。为了做到这一点,我们需要有一个设计规则,所有的模块都在这个规则下进 行设计。良好的设计规则,会把耦合密集的设计参数进行归类作为一个模块,并以此划分工作任务。而模块之间彼此通过一个固定的接口(所谓的可见参数)进行交互,除此之外的内部实现(所谓的隐参数)则由模块的开发团队进行自由发挥。
程序模块化的目的:
1.减少循环依赖
2.减少耦合
3.提高设计效率
css模块化原则
分离结构和表现
分离容器和内容
22、标准化的javascript
JavaScript 的核心 ECMAScript 描述了该语言的语法和基本对象;
DOM 描述了处理网页内容的方法和接口;
BOM 描述了与浏览器进行交互的方法和接口。
23、前端兼容性问题总结
浏览器兼容性问题解决方案 · 总结juejin.im
24、前端性能优化
前端性能优化的常用手段 - 掘金juejin.im
25、loadash的使用
Lodash中十个常用的工具函数 - Web前端 - ITeye资讯www.iteye.com
26、前端预处理器sass的使用
Sass 是一款强化 CSS 的辅助工具,它在 CSS 语法的基础上增加了变量 (variables)、嵌套 (nested rules)、混合 (mixins)、导入 (inline imports) 等高级功能,这些拓展令 CSS 更加强大与优雅。使用 Sass 以及 Sass 的样式库(如 Compass)有助于更好地组织管理样式文件,以及更高效地开发项目。
CSS预处理器之sass的用法 - 掘金juejin.im
27、leetcode算法最优解
找不到想要的解答,从这上面搜一下
九章算法 - 帮助更多中国人找到好工作,硅谷顶尖IT企业工程师实时在线授课为你传授面试技巧www.jiuzhang.com
28、不了解的三种函数写法
https://blog.csdn.net/Prince_fmx/article/details/77864310blog.csdn.net
一篇文章搞懂toString()和valueOf() - html/css语言栏目:html.css - 红黑联盟www.2cto.com
29、react源码总结
React源码学习小结www.jianshu.com
react在使用时总结不出这么多优点,他帮你解决了面试提问的难题:
React精髓!一篇全概括(急速) - 掘金juejin.im
30、Flex布局,position,垂直水平居中三种必问前端常识
http://www.ruanyifeng.com/blog/2015/07/flex-examples.htmlwww.ruanyifeng.com
31、破碎浮点型数据的解决办法
过长的纯数字数组不能通过Number或者parseInt进行转化,这样会产生错误,要使用BigInt来解决。想要计算二元运算需要在二元运算的另一个项上加上n,参考例子与讲解均在里面:
js基本数据类型 BigInt 和 Number 的区别cloud.tencent.com
32、中级前端所有手写内容
防抖、节流
深浅拷贝
数组乱序、数组去重(各种时间空间复杂度)
数组filter
数组flat(平展一层到多层)
手写call、bind、apply(及了解这三种的区别)
八种继承及各种继承之间的特点
实现instanceof
实现new的过程
lazyman
jsonp的实现
函数的柯力化
promise、promise.all、promise.retry
(其中大厂不排除让你手写ajax的封装(百度),头条(promise.retry))
参考地址:
“寒冬”三年经验前端面试总结(含头条、百度、饿了么、滴滴等)之手写题(一) - 掘金juejin.im
“寒冬”三年经验前端面试总结(含头条、百度、饿了么、滴滴等)之手写题(二) - 掘金juejin.im
实现promise.all方法 - 掘金juejin.im
33、大厂常问的React全家桶
必须掌握、必须掌握、必须掌握!
react-router:
2. React-Router的基本使用juejin.im
redux、react-redux:
一篇文章总结redux、react-redux、redux-saga - 掘金juejin.im
拓展(强烈建议能手写出来)、几家大厂都在问:
让react用起来更得心应手--(react-router原理简析) - 掘金juejin.im
34、三分钟记牢原型,原型链,继承
function Animal(){
this.type = "animal";
}
Animal.prototype.getType = function(){
return this.type;
}
function Dog(){
this.name = "dog";
}
Dog.prototype = new Animal();
Dog.prototype.getName = function(){
return this.name;
}
var xiaohuang = new Dog();
//原型链关系
xiaohuang.__proto__ === Dog.prototype
Dog.prototype.__proto__ === Animal.prototype
Animal.prototype.__proto__ === Object.prototype
Object.prototype.__proto__ === null
35、解释下Promise与Promise.all及扩展
promise是什么?
Promise是异步编程的一种解决方案,比传统的回调函数和事件更合理和强大。
所谓Promise,简单来说就是一个容器,里面保存着某个未来才会结束的事情(通常是一个异步操作)。从语法上说,Promise是一个对象,从他可以获取异步操作的消息。
特质:
一:对象的状态不受外部影响
二:一旦状态改变,就无法再被改变。
缺点:
一旦创建promise就会立即执行
使用:
const newPromise = new promise((resolve,reject)=>{
if(success){
resolve()
}else{
reject()
}
}).then((data)=>{console.log(data)},(error)=>{console.log(error})
.catch(null,(error)=>{console.log(error)})
then方法可以接受两个回调函数作为参数,
第一个回调函数是promise对象的状态变为resolved的时候调用,
第二个回调函数是promise对象的状态变为rejected时调用。
其中第二个函数是可选的,不一定需要提供。
catch方法是.then(null, rejection)的别名,用于指定发生错误时的回调函数。
promise.all是什么?
Promise.all(iterable) 方法返回一个 Promise 实例,此实例在 iterable 参数内所有的 promise 都“完成(resolved)”或参数中不包含 promise 时回调完成(resolve);如果参数中 promise 有一个失败(rejected),此实例回调失败(reject),失败原因的是第一个失败 promise 的结果。
result = arr.map(i => {
...
const rowPromise = filtered
.sort({ create_time: -1 }) //-1降序 1升序
.skip(offset > -1 ? offset : 0)
.limit(limit <= 200000 ? limit : 200000)
.toArray()
return rowPromise
})
promise.all(result)
.then(total => resolve(total))
.catch(err => reject(err))
promise.all中传入的result一定要是一个数组。返回的是个promise实例,机制与promise一致
详细的promise.all&promise.race参考
神奇的Aym:面试问到 Promise,这样回答最完美了zhuanlan.zhihu.com
36、ES6中export与export default差异总结
export default在一个模块中只能有一个,但是export可以有多个。
通过export导出的(属性或者方法)可以修改,但是通过export default导出的是不可修改的。
export var e1='...' 是合法语句,但是export default var e2='...'是不合法的(let和const也一样)。
export default可以直接添加标识符导出,例如export default e2;export如果要导出已经声明的表示符,必须使用{},例如export {e1},注意:这里{}不是声明一个对象。
ES6中模块通过export和export default暴露出来的属性或者方式并不是普通的赋值或者引用,它们是对模块内部定义的标志符类似指针的绑定。
对于一个导出的属性或者方法,在什么地方导出不重要,在什么时候导入也不重要,重要的是:访问这这个绑定的时候的当前值。
ES6 export && export default 差异总结juejin.im
37、简述Generator函数的基本语法
Generator (生成器)函数有多种理解角度。语法上,首先可以把它理解成,Generator 函数是一个状态机,封装了多个内部状态。执行 Generator 函数会返回一个遍历器对象。
特征一:function关键字与函数名之间有一个号(*写在之间的任何位置都可以通过,不区分有几个空格)
特征二:函数体内有yield(产出)表达式,定义了不同的内部状态
function* helloWorldGenerator() {
yield 'hello';
yield 'world';
return 'ending';
}
var hw = helloWorldGenerator();
hw.next()
// { value: 'hello', done: false }
hw.next()
// { value: 'world', done: false }
hw.next()
// { value: 'ending', done: true }
hw.next()
// { value: undefined, done: true }
函数执行.next()后返回的也不是函数运行结果,而是一个指向内部状态的指针对象。每次调用next方法,内部指针就从函数头部或上一次停下来的地方开始执行,直到遇到下一个yield表达式(或return语句)为止。换言之,Generator 函数是分段执行的,yield表达式是暂停执行的标记,而next方法可以恢复执行。
function* gen() {
yield 123 + 456;
}
上面代码中,yield后面的表达式123 + 456,不会立即求值,只会在next方法将指针移到这一句时,才会求值。
yield表达式与return语句既有相似之处,也有区别。相似之处在于,都能返回紧跟在语句后面的那个表达式的值。区别在于每次遇到yield,函数暂停执行,下一次再从该位置继续向后执行,而return语句不具备位置记忆的功能。一个函数里面,只能执行一次(或者说一个)return语句,但是可以执行多次(或者说多个)yield表达式。正常函数只能返回一个值,因为只能执行一次return;Generator 函数可以返回一系列的值,因为可以有任意多个yield。
for...of循环,扩展运算符(...)、解构赋值和Array.from方法内部调用的,都是遍历器接口。这意味着,它们都可以将 Generator 函数返回的 Iterator 对象,作为参数
function* numbers () {
yield 1
yield 2
return 3
yield 4
}
// 扩展运算符
[...numbers()] // [1, 2]
// Array.from 方法
Array.from(numbers()) // [1, 2]
// 解构赋值
let [x, y] = numbers();
x // 1
y // 2
// for...of 循环
for (let n of numbers()) {
console.log(n)
}
// 1
// 2
https://es6.ruanyifeng.com/#docs/generator-asynces6.ruanyifeng.com
38、错误边界(Error Boundaries)
部分 UI 的 JavaScript 错误不应该导致整个应用崩溃,为了解决这个问题,React 16 引入了一个新的概念 —— 错误边界。
错误边界是一种 React 组件,这种组件可以捕获并打印发生在其子组件树任何位置的 JavaScript 错误,并且,它会渲染出备用 UI,而不是渲染那些崩溃了的子组件树。错误边界在渲染期间、生命周期方法和整个组件树的构造函数中捕获错误。
如果一个 class 组件中定义了
static getDerivedStateFromError()
componentDidCatch()
这两个生命周期方法中的任意一个(或两个)时,那么它就变成一个错误边界。当抛出错误后,请使用 static getDerivedStateFromError() 渲染备用 UI ,使用 componentDidCatch() 打印错误信息。
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
// 更新 state 使下一次渲染能够显示降级后的 UI
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
// 你同样可以将错误日志上报给服务器
logErrorToMyService(error, errorInfo);
}
render() {
if (this.state.hasError) { // 你可以自定义降级后的 UI 并渲染 return <h1>Something went wrong.</h1>; }
return this.props.children;
}
}
错误边界的工作方式类似于 JavaScript 的 catch {},不同的地方在于错误边界只针对 React 组件。只有 class 组件才可以成为错误边界组件。大多数情况下, 你只需要声明一次错误边界组件, 并在整个应用中使用它。
注意错误边界仅可以捕获其子组件的错误,它无法捕获其自身的错误。如果一个错误边界无法渲染错误信息,则错误会冒泡至最近的上层错误边界,这也类似于 JavaScript 中 catch {} 的工作机制。
自 React 16 起,任何未被错误边界捕获的错误将会导致整个 React 组件树被卸载。
在开发环境下,React 16 会把渲染期间发生的所有错误打印到控制台,即使该应用意外的将这些错误掩盖。除了错误信息和 JavaScript 栈外,React 16 还提供了组件栈追踪。现在你可以准确地查看发生在组件树内的错误信息:
注意
错误边界 无法捕获以下场景中产生的错误:
事件处理(了解更多)
异步代码(例如 setTimeout 或 requestAnimationFrame 回调函数)
服务端渲染
它自身抛出来的错误(并非它的子组件)
39、null与undefiend的区别
大多数计算机语言,有且仅有一个表示"无"的值,比如,C语言的NULL,Java语言的null,Python语言的None,Ruby语言的nil。
有点奇怪的是,JavaScript语言居然有两个表示"无"的值:undefined和null。
null表示"没有对象",即该处不应该有值。典型用法是:
(1) 作为函数的参数,表示该函数的参数不是对象。
(2) 作为对象原型链的终点。
Object.getPrototypeOf(Object.prototype) // null
undefined表示"缺少值",就是此处应该有一个值,但是还没有定义。典型用法是:
(1)变量被声明了,但没有赋值时,就等于undefined。
(2) 调用函数时,应该提供的参数没有提供,该参数等于undefined。
(3)对象没有赋值的属性,该属性的值为undefined。
(4)函数没有返回值时,默认返回undefined。
var i;
i // undefined
function f(x){console.log(x)}
f() // undefined
var o = new Object();
o.p // undefined
var x = f();
x // undefined
40、探究Function.__proto__===Function.prototype(自己生成自己)
对象类型的成员,标准内置构造器 Function的一个实例,并且可做为子程序被调用。
注: 函数除了拥有命名的属性,还包含可执行代码、状态,用来确定被调用时的行为。函数的代码不限于 ECMAScript。
目前存在三种创建函数的形式
demo instanceof Function
//true
上面只是创建函数的一种方式, JavaScript 中有三种创建形式,分别是:
①声明式
function fn(){ }; //这种定义的方式,无论在哪儿定义,别处都可以调用 ;
②函数的字面量或叫直接量或称表达式
var fn=function () { }; //此时函数作为表达式存在,调用只能在定义的后面;
//解释一下表达式:凡是将数据和运算符等联系起来有值得式子就是表达式。
③以new Function 的形式
var fn = new Function (arg1 , arg2 ,arg3 ,…, argN , body)
/*Function 构造函数所有的参数都是字符串类型。除了最后一个参数, 其余的参数都作为生成函数的参数即形参。
这里可以没有参数。最后一个参数, 表示的是要创建函数的函数体。
使用Function构造器生成的Function对象是在函数创建时解析的。这比你使用函数声明或者函数表达式(function)
并在你的代码中调用更为低效,因为使用后者创建的函数是跟其他代码一起解析的。
*/
问题引出
我们知道,Array,Date,Number,String,Boolean,Error甚至Object都是Function的一个实例,那么Function是谁的实例呢?
Function构造函数的prototype属性和__proto__属性都指向同一个原型,是否可以说Function对象是由Function构造函数创建的一个实例?
Function.prototype和Function.__proto__都指向Function.prototype,因此function对象又是Function构造函数创建的实例。
Function 和 Object 和其它构造函数继承 Function.prototype 而产生。
先有 Object.prototype,再有 Object
Function.proto=== Function.prototype;
Function 构造函数的 prototype 属性和__proto__属性都指向同一个原型,可以说 Function 对象是由 Function 构造函数创建的一个实例
Object instanceof Function // true
Function instanceof Object // true
Object 本身是构造函数,继承了 Function.prototype;Function 也是对象,继承了 Object.prototype。
function Person(){}
Person.prototype 是一个对象,Function.prototype 却是一个函数
结论:
在使用声明式 function的时候其实已经帮你做了new Function()这一步了,function和new Function()创建的函数都是Function的一个实例,只是方式不一样,其实本质都是一样。
明天一定会感谢今天努力的自己!
————————————————
版权声明:本文为CSDN博主「&時光」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Time_Flies_lei/article/details/116568760