深圳某某网前端开发面试
面试时间: 2020年12月8日上午10点-12点
面试形式: 笔试+技术面+项目面
笔试题
- position的值有哪些?
A. static B.relative C. absolute D. flex E.fixed F.table
答案:ABCE
解析:
取值 | 定位类型 | 相对于哪个定位 |
---|---|---|
absolute | 绝对定位 | 相对于static定位以外的第一个父元素进行定位 |
fixed | 固定定位 | 相对于浏览器窗口进行定位 |
relative | 相对定位 | 相对于其正常位置进行定位 |
static | 默认值,没有定位 | 元素出现在正常的流中 |
sticky | 粘性定位 | 基于用户滚动的位置 |
inherit | 设置该属性为默认值 |
- 请选择结果为真的表达式
A. null instanceof Object
B. null === undefined
C. null == undefined
D. NaN == NaN
答案:C
解析:
A instanceof为真的情况:判断右边的值是否是左边对象的构造函数或原型对象上的构造函数即可 - var arr = [], typeof arr 的结果是
A. array
B. function
C. object
D. undefined
答案:C
解析:
typeof返回的数据类型为undefined,string,boolean,number,object,function - 以下代码输出结果是什么?
[“1”, “2”, “3”].map(parseInt)
A. [“1”, “2”, “3”]
B. [1, 2, 3]
C. [0, 1, 2]
D. other
答案: D
解析:正确结果为[1, NaN, NaN]
parseInt(string, radix): radix 表示要解析的数字的基数。该值介于 2 ~ 36 之间。
parseInt(‘1’, 0); // radix为0时,使用默认的10进制。
parseInt(‘2’, 1); // radix值在2-36,无法解析,返回NaN
parseInt(‘3’, 2); // 基数为2,2进制数表示的数中,最大值小于3,无法解析,返回NaN - js存储方式有哪几种方式?他们之间的区别是什么?
参考答案:
js有三种存储方式:cookie,sessionStorage, localStorage
不同点
不同点 | cookie | sessionStorage | localStorage |
---|---|---|---|
传递方式不同 | 在浏览器和服务器间来回传递 | 仅在本地保存 | 仅在本地保存 |
数据大小不同 | 不能超过4k | 可以达到5M | 可以达到5M |
数据有效期不同 | 在设置的过期时间之前一直有效 | 当前浏览器窗口关闭前有效 | 始终有效 |
作用域不同 | 所有同源窗口中共享 | 不在不同的浏览器窗口共享 | 所有同源窗口中共享 |
- 你知道哪些http状态码?常用的有哪些?
参考答案:
分类描述
1XX:1开头的是信息状态码
2XX:2开头的是请求成功
3XX:3开头的是重定向
4XX:4开头的是客户端错误
5XX:5开头的是服务器错误
状态码 | 英文名称 | 中文描述 |
---|---|---|
100 | Continue继续 | 客户端应继续其请求 |
200 | OK请求成功 | 一般用于GET与POST请求 |
301 | Moved Permanently永久移动 | 请求的资源已被永久的移动到新URI,浏览器会自动定向到新URI,今后任何新的请求都应使用新的URI代替 |
302 | Found临时移动 | 资源临时被移动,客户端应继续使用原URI |
304 | Not Modified未修改 | 所请求的资源未修改,服务器返回此状态码时,不会返回任何资源 |
400 | Bad Request | 客户端请求的语法错误,服务器无法理解 |
401 | Unauthorized | 请求要求用户的身份认证 |
403 | Forbidden | 服务器理解客户端的请求,但是拒绝执行此请求 |
404 | Not Found | 服务器无法根据客户端的请求找到资源 |
500 | Internal Server Error | 服务器内部错误,无法完成请求 |
- 什么情况下会碰到跨域问题?有哪些解决方法?
参考答案:
由于浏览器出于安全考虑,有同源策略。同源是指协议+域名+端口三者相同。Ajax请求会失败
解决方法:
一 JSONP
基本原理:利用script的src属性没有跨域的限制
执行过程:
前端设置好回调参数,并将其作为URL的参数
服务器端收到请求后,通过该参数获取到回调函数名,并将数据放在参数中返回
收到结果后因为是script标签,所以浏览器当做脚本运行
优点:使用简单且兼容性不错,在一些古老的浏览器中都可以运行
缺点:只能进行GET请求
二 CORS 跨域资源共享
实现cors的关键是服务器,只要服务器实现了cors接口,就可以跨域通信
前端逻辑很简单,正常发起ajax请求即可,成功的关键在于服务器Access-Control-Allow-Orign是否包含请求页面的域名。
cors请求分为两类:简单请求和非简单请求,简单请求是不会触发cors的预检请求的,而非简单请求会。
预检请求要求必须首先使用OPTIONS方法发起一个预检请求到服务器,以获取服务器是否允许该请求
三 代理跨域: Nginx代理跨域,Node中间件代理跨域
四 其他:postMessage跨域;WebSocket跨域;document.domain + iframe;location.hash + iframe; window.name + iframe - 以下代码的输出结果是什么?
setTimeout(function(){
console.log(1);
});
new Promise(function(resolve, reject){
console.log(2)
resolve(3)
}).then(function(val){
console.log(val);
})
console.log(4);
答案: 2 4 3 1
解析: 执行顺序: 同步代码(2 4)–> promise.then(3)–>settimeout(1)
9. 下面这个ul,请写出代码,让点击每一列的时候alert其index?
<ul id='test'>
<li>这是第一条</li>
<li>这是第二条</li>
<li>这是第三条</li>
</ul>
参考答案:
// 方法一:
var lis = document.getElementById(“test”).getElementsByTagName(“li”);
for (var i = 0; i < 3; i++) {
lis[i].index = i;
lis[i].onclick = function() {
alert(this.index);
};
}
//方法二:
var lis = document.getElementById(“test”).getElementsByTagName(“li”);
for (var i = 0; i < 3; i++) {
lis[i].index = i;
lis[i].onclick = (function(a) {
return function() {
alert(a);
};
})(i);
}
技术面
-
自我介绍
参考模板:
你好,我是XX,毕业于XX大学。现就职于XX公司,有X年开发经验,公司主要使用技术栈为React+AntDesign+Redux进行开发 -
介绍下你们公司项目
回答:公司项目是内部ERP项目,主要是web端;包含XX系统,XX系统,XX系统,XX系统,XX系统,XX系统等X个业务模块;
前端主要使用技术为React+AntDesign+Redux+ES6进行开发;
技术选型:
前端数据展示:react,react-router-dom,antd, redux
前后台交互:ajax请求: promise/async/await ;接口测试工具:postman
模块化: ES6
工程化: Webpack
其他:富文本编辑器,图表库(echart, echart-for-react) -
讲一下react生命周期
目前公司项目使用的react版本生命周期:
挂载阶段:
componentWillMount
componentDidMount: 组件渲染之后调用,只调用一次;发送ajax请求获取数据在此,原因:在 componentWillMount 里进行网络请求会阻碍组件的渲染;componentWillMount 调用 setState 不会出发重新渲染;componentDidmount 是在组件完全挂载后才会执行,在此方法中调用setState 会触发重新渲染,最重要的是,这是官方推荐的!
更新阶段:
componentWillReceiveProps:组件接受新的props时调用
shouldComponentUpdate: react性能优化重要一环;组件接受新state或者新props调用;再次比较前后两个state和props是否相同,如果相同,则返回false阻止更新
componentWillUpdate
componentDidUpdate
销毁阶段
componentWillUnmount:事件监听和定时器需要在此清除
有了解到react升级后的声明周期:
去掉了 componentWillMount
去掉了 componentWillReceiveProps 使用getDerivedStateFromProps
去掉了 componentWillUpdate 使用getSnapShotbeforeUpdate -
react组件间通讯
父组件向子组件通信:父组件向子组件传递props,子组件得到props后进行相应的处理
子组件向父组件通信:利用回调函数:父组件将一个函数作为props传递给子组件,子组件调用该回调函数
跨级组件之间通信:中间组件层层传递props;使用context对象:上级组件声明自己支持context,并提供一个函数来返回一个context对象;子组件需要声明自己需要使用context
非嵌套组件间通信:利用二者共同父组件context进行通讯;使用自定义事件方式:典型的发布/订阅模式,通过向事件对象上添加监听器和触发事件来实现组件通讯
状态管理工具 Redux -
看过react源码吗?谈一下对react的理解
一 组件的实现和挂载
组件:声明组件是继承ReactComponent类的子类,ReactComponent包含props(子结构相关信息和组件属性), context,refs(真是DOM引用)和updater;原型上方法有setState和forceUpdate
组件初始化:执行React.createElement方法创建出ReactElement类型的js对象
组件的挂载:通过ReactDom.render(component, mountNode)的形式对自定义组件,原生DOM,字符串进行挂载;根据组件类型,内部会创建四大类封装组件:ReactEmptyCompoment(空), ReactDomComponent(虚拟DOM), ReactCompositeComponent(react组件),ReactTextComponent(字符串和数字);解析ReactElement对象获得HLML;将HTML插入真实DOM中
二 组件的类型和生命周期
ReactEmptyCompoment(空), ReactDomComponent(虚拟DOM) ,ReactTextComponent(字符串和数字)通过mountComponent 解析ReactElement对象获得HLML;将HTML插入真实DOM中
ReactCompositeComponent(react组件)通过mountComponent 先处理props;根据render的有无判断是有状态组件还是无状态组件;处理state;执行componentWillMount;执行render,获取html;执行componentDidmount,对子组件重复上述流程;解析ReactElement对象获得HLML;将HTML插入真实DOM中
三 diff算法
传统diff算法复杂度是O(n^3),react基于三个基础假设,将时间复杂度优化为o(n)
基础假设:DOM节点跨层级移动的操作很少,忽略不计;两个不同类型的元素会产生不同的树;同一层级的一层子节点可以通过唯一的key进行区别
tree diff:
概念:将新旧两颗虚拟DOM树,按照层级对应关系,从头到尾遍历一遍,就能找到哪些是需要更新的;
注意:只对同级的DOM进行比较,及同一父节点下的子节点;发现节点不存在,则直接删除此节点及子节点,不会进行进一步的对比
component diff:
概念:对比每一层及的时候,会有自己的组件
注意:如果类型相同,暂时不更新;如果类型不同,需要更新:删除旧组件,创建新组件,插入到删除组件的位置
element diff:
概念:在类型相同的组件内,再继续对比组件内部的元素,查看元素内部是否相同
三种节点操作:
插入:新的component类型不在老集合中,需要对新节点进行插入操作
移动:老的集合包含新的component类型,复用以前节点,进行移动
删除:老的component不在新集合中,需要删除 -
react-router类型及区别?
区别 | HashRouter | BrowserRouter |
---|---|---|
原理 | 路径中包含了#,相当于HTML的锚点定位 | 使用的是HTML5的新特性History,没有HashRouter(锚点定位)那样通用,低版本浏览器可能不支持 |
用法 | 组件跳转时不能传递参数(除非手动拼接URL字符串),因此一般配合Redux使用,实现组件间的数据通信。 | 组件跳转时可以传递任意参数实现组件间的通信 |
生产实践 | 如果后端没有覆盖到路由就会产生404错误,解决:加入中间件,放在服务器端路由匹配的最后,如果前面的API接口都不匹配,则返回index.html页面。 |
-
数组循环注意什么
要点:循环每项加key,元素复用性 -
组件封装注意事项(抽离组件注意事项)
参考答案:
可扩展性强:如果不能拓展,失去代码的灵活性
文档详细清楚:适当的注释
颗粒度合适,适度抽象:尽量保证一个组件完成的功能是单一的,不是多个功能的结合体
留一个slot:组件完成80%功能,剩余20%让父组件通过slot完成
异常处理:可疑区增加try catch;全局监控js异常window.onerror;React的componentDidCatch -
平时怎么调试代码(bug)
回答:console.log, debugger ;对于断点调试找不到的,需要梳理整体逻辑进行调试;找同事或者领导帮忙 -
平时有用过webpack和Nginx吗?有写过相关项目吗?
回答:没有。。。(明显减分了) -
重构或者升级项目从业务层面和代码规范的注意点
回答:代码规范层面(明显不是面试官想要的答案)
删除无用代码,精简代码
代码规范化:内联样式提取到单独css文件中;代码首行缩进;修改不支持的标签
代码模块化:按模块分离js代码
提高页面加载性能:不需要首页展示的js代码延后加载;js按需加载;图片合并等 -
职业规划
回答:先夯实基础,在此之上,更加深入,希望在前端领域有所建树 -
你的优点
回答:从领导和同事评价来看,我是一个很靠谱的人,对答应的事情和分配的任务都能高质高效完成,认真负责 -
平时怎么学习的
多做练习,多写代码,从错误中学习
多思考,多总结
多和其他人沟通思想和知识点 -
和其他人意见分歧怎么处理
回答:首先认真听对方的需求,然后心平气和的沟通;开会沟通;拉上leader开会沟通
项目面
-
自我介绍 同上
-
介绍下公司项目 同上
-
介绍下你简历上的项目
-
以不同审批为例,你们公司是怎么使用通用组件的?
组件封装好后,放在公用组件中,使用时,引入组件,配置响应的props -
跨域 同上
-
你还有什么要问我的吗?
现在公司具体项目有哪些?