前端面试前,复习大纲
把前端面试时,容易被问到的几个点做一下梳理,一些零碎的细枝末节就不说了。以后面试时也有个准备的方向。
许多问题,如果面试官换个方式问,你要明白他到底要考什么,如果不清楚,可以再问一遍。
性能优化总结
通信相关
跨域
js 相关
节流防抖
闭包
函数套函数,子函数使用父函数的参数或者变量,并且子函数被外界所引用(没释放)
这个时候,父函数的参数或者变量不会被垃圾回收机制回收,此时在浏览器(chrome)
中打印父级的返回值,在scopes下多了一个closure,closure就叫闭包。
闭包
promise
一句话总结promise原理:resolve, reject两个回调函数控制promise内部状态,promise.then()根据状态执行不同的逻辑,实现异步。并返回已固定状态的新 promise,完成 then 链。
promise
发布订阅模式和观察者模式 ???
this的指向问题
事件循环
主线程中的所有同步任务都执行完毕之后,就会去任务队列中按照顺序读取一个宏任务放入到主线程中执行,每执行一个宏任务之后,都会清空一次微任务,之后会判断DOM是否需要重新渲染。之后再次读取一个宏任务,依次循环,直到没有可执行的任务为止。
JS 事件循环机制(宏任务、微任务)
变量提升问题(笔试的时候有)
判断数据类型的方法有哪些?
call apply bind
call() / apply() / bind() 的区别和作用
原型和原型链的原理
实例.__proto__ === 构造函数.prototype
原型链是JS的一个特性,它实现的核心机制是:
1、访问一个实例的属性(方法)时,若实例本身不存在该属性(方法),则会通过该实例的原型链访问到构造函数的原型;
2、构造函数的原型也是一个对象。访问的属性(方法)依旧不存在于该原型,则会继续通过 构造函数的原型下的原型链,访问到 Object 的原型
3、再没有就是(undefined),函数(报错)。
正是因为这样,我在使用每一个实例的时候,就不需要把所有的属性(方法)都重新写一遍。从而提升性能
原型和原型链
继承的原理
首先要明白,new 了一个构造函数,产生一个实例,并不是实例继承了构造函数,而是,实例 与 构造函数 建立起来 原型链和原型 的联系。
继承是子类获得父类的属性和方法的过程。(一般我们把方法挂在 构造函数 的原型上,属性放在类里)
一般我们可以通过 拷贝父类的原型,来获得父类的方法
Coder.prototype = Object.create(Person.prototype);
Coder.prototype.constructor = Coder; // 需要手动修改 constructor 指向
用 call 方法获得父级的属性
function Coder(name, age) {
Person.call(this, name, age);
}
继承的方式有很多,尤其是 ES6 提供了 class ,使代码更据可读性。
继承
DOM BOM 相关
事件流
换个方式问:事件的触发机制是什么,事件的触发原理是什么?
捕获 -> 目标 -> 冒泡
事件流,也叫事件模型、事件轮询、事件委托
这里有个容易搞混的,【事件循环机制】,考的是:主队列,任务队列,任务队列又分微任务和宏任务,每执行一次宏任务,都要清空一次微任务。
react 相关
生命周期
react 的渲染机制
换个方式问可以是:
- 为什么 react 渲染 DOM 比较优秀?
- react 和直接操作 DOM 谁比较好。
这类问题其实就是问 Virtual DOM 和 Diff算法。
react hook
- 为何要将 useState 写在最上面?
因为用它定义的状态和改变状态的方法会被下文使用到,写在上面,防止获取不到。 - 你使用过的 hook 有哪些,他们的作用是什么?
- react hook函数式编程的优缺点:
- 好处: 代码清晰、简洁、更容易复用代码。
- 缺点:使用定时器时会产生闭包,拿不到更新后的状态。状态更新后也不像类组件的
this.setState({}, ()=> {})
有对应的回调函数,不方便获取更新后的状态。
react 的数据传递
基础题,就是问父子之间的数据传递,往往会由此过渡到 redux,及其中间件的使用。
react-router原理
简单回答:监听 url 变化或者重写 history.push ,在重写的函数里增加回调。这样就能在url变化的时候获取url,解析url,匹配路径所对应的组件,展示他。
redux
- 实现原理(或者说实现流程,都是一个意思)
- 首先是dispatch一个action。然后reducer会收到这个action, 根据这个action对状态state进行修改。状态修改以后会被处理容器捕捉到。从而对相关的界面进行更新。
- 中间件thunk
- 作用:通过中间件 thunk 可以让程序员在 action 中调用接口。
- 原理:Redux-Thunk 其实就是把 Store 中的 dispatch 方法重写了。如果 dispatch 的参数是正常的 Action,也就是说是个对象,那就直接 dispatch 它。如果参数是一个方法,那就传入 dispatch 和 getState 并执行它,而 dispatch 和 getState 是在 createStore 时以闭包的方式注入的。
react 优化
vue 相关
我学过,但不怎么用vue
webpack 相关
基础题
各种浏览器的内核是什么?(详情请百度)
* IE: trident内核
* Firefox:gecko内核
* Safari: webkit内核
* Opera: 以前是presto内核,Opera现已改用Blink内核(和Google共同开发)
* Chrome: Blink【基于webkit内核(渲染DOM) + V8引擎(解析js)】
浏览器渲染页面的底层机制
htrtp 状态码(Status Code)
Cookie、 sessionStorage、localStorage 的异同
Cookie、 sessionStorage、localStorage 的异同
特性 | Cookie | localStorage | sessionStorage |
---|---|---|---|
数据的生命期 | 一般由服务器生成,可设置失效时间。如果在浏览器端生成Cookie,默认是关闭浏览器后失效 | 除非被清除,否则永久保存 | 仅在当前会话下有效,关闭当前页面或浏览器后被清除 |
存放数据大小 | 4K左右 | 一般为5MB | 同 localStorage |
与服务器端通信 | 每次都会携带在HTTP头中,如果使用cookie保存过多数据会带来性能问题 | 仅在客户端(即浏览器)中保存,不参与和服务器的通信 | 同 localStorage |
易用性 | 需要程序员自己封装,源生的Cookie接口不友好 | 源生接口可以接受,亦可再次封装来对Object和Array有更好的支持 | 同 localStorage |
对象位置 | document.cookie | window.localStorage | window.sessionStorage |
跳转页面的方式
window.location / window.history / 以及相关事件
window.location / window.history / 以及相关事件
零散的问题
问题1:对象能否是箭头函数,或者能否用箭头函数创建一个类,或者es6中的箭头函数是否可以使用new实例化?
箭头函数,没有prototype、没有自己的this指向、不可以使用arguments、自然不可以new,一new就报错。
问题2:函数表达式和函数声明的区别
问题3:作用域和变量提升
hooks 函数是做什么用的?
让静态组件动态化
冷门题
xss漏洞
[xss漏洞](https://www.cnblogs.com/MrZhujl/p/14682348.html)
白马一面,基础题(2022-3-18)
一、CSS
元素居中
- 绝对定位,四个方向偏移量为 0 ,然后 margin 设置为 auto
- 绝对定位,上和左移动50%,再利用 margin 反向移动宽高的一半
- 绝对定位,上和左移动50%,再利用 translate 反向移动50%
- 父级 flex 布局
display: flex; justify-content: center; align-items: center;
二、JS
如何判断一个对象是否为空对象
- for in 循环,用 hasOwnProperty 来检测对象本身的属性,而不是来自继承的属性。
let obj = {}
Object.prototype.say = "123"
console.log(obj);
function xx() {
for (let i in obj) {
if (obj.hasOwnProperty(i)) {
return "非空对象";
}
}
return "空对象";
}
console.log(xx());
- 用 JSON.stringify(obj),判断是否等于 "{}"
let obj = {}
console.log(JSON.stringify(obj) === "{}");
- Object.keys(),拿到属性名的集合,判断集合的长度
let obj = {}
console.log(Object.keys(obj).length);
继承
上文有
节流防抖
上文有链接
promise.all() 如何实现?
这个放弃作答,我清楚如何用,真要自己实现一个,得不少时间。面试的时候,临时回答这种问题,只能放弃。
换个换个回答方式,从它的特点入手:
- 先判断传入是否为一个数组,数组的每一项都是 promise 对象,
- promise.all([a,b,c...]).then方法之后的结果是一个数组,返回的数组是参数中依次执行的返回值
- 参数中的 promise 有一个失败则全部失败
代码就不帖了,网上很多,面试的时候也不能口述代码呀。
this指向问题
举了个反人类的题目:
class A {
a = 1;
fn1 = () => {
console.log(this.a);
}
fn2() {
console.log(this.a);
}
}
var a = new A()
var { fn1, fn2 } = a;
fn1()
fn2()
我敢说 80% 的人都会答错。
map 和 forEach 的区别
map 返回一个数组,数组里面的每一项就是 return 后面的内容
forEach 没有返回。
三、浏览器基础
什么是重排重绘,如何优化
重排:当一个元素的大小发生改变,会印象到其它元素的位置时,浏览器要重新排布所有受影响的元素,这个过程叫做重排。
重绘:当一个元素的外观发生改变,但没有改变布局,重新把元素外观绘制出来的过程,叫做重绘。
如何优化:
- react 的 虚拟DOM 和 diff算法 就是一个很好的优化手段。
- 其次,我们可以把经常发生重排重绘的块,使其脱离文档流,减少被影响的元素
- 不要使用 table 布局,
- ...
浏览器的GUI渲染原理
- 生成‘DOM tree’
- 生成‘CSSOM tree’
- 把生成的‘DOM tree’和‘CSSOM tree’合并在一起,共同创建为‘render tree’渲染树
- 浏览器开始按照‘render tree’进行渲染
四、React框架、webpack 相关
热更新的原理
(网上写的都太长,面试的时候,臣妾不可能记住啊,下面简单说一下,应付面试:)
- webpack-dev-server 开启本地服务,
- 将本地文件打包好保存JavaScript内存中,
- 监听代码和静态文件的变化,重新打包。
- 通过websocket,可以建立本地服务和浏览器的双向通信。这样就可以实现当本地文件发生变化,立马告知浏览器可以热更新代码啦!
webpack 优化
上文有链接
react 优化
我只简述了通过生命周期、PureComponent、memo、useCallback、useMemo,这些常规的方式。
history.push 和 history.replace 的区别
首先要知道这里的 history 不是原生 window 下的, 而是 react 中的,一共有 let {push, go, replace} = history
react-router 的原理 react-router 通过重写了 history ,从而达到监听 URL 路由的变化。
- history.push 这个方法会向history栈里面添加一条新记录,这个时候用户点击浏览器的回退按钮可以回到之前的路径。
- history.go 这个方法的参数是一个整数,意思是在 history 记录中向前或者后退多少步,类似 window.history.go(n)
- history.replace 跟 history.push 很像,唯一的不同就是,它不会向 history 添加新记录,而是跟它的方法名一样 —— 替换掉当前的 history 记录。
五、项目经验
封装过什么组件
(根据个人情况回答)
微前端
将一个庞大的项目,拆分成多个子项目,或者多个子页面来实现。
常用的有:iframe、前端路由。
通信方式:路由参数(查询信息)、React的单向数据流模型