2020秋招金山前端面试
1. 什么是闭包
2. CSS上下左右居中
3. Async、Await的实现原理
解决函数回调经历了几个阶段, Promise 对象, Generator 函数到async函数。
async函数目前是解决函数回调的最佳方案。
async函数是Generator函数的语法糖,async/await语法糖就是使用Generator函数+自动执行器来运作的。
Generator是ES6标准引入的新的数据类型。Generator可以理解为一个状态机,内部封装了很多状态,同时返回一个迭代器Iterator对象。可以通过这个迭代器遍历相关的值及状态。 Generator的显著特点是可以多次返回,每次的返回值作为迭代器的一部分保存下来,可以被我们显式调用。
Generator函数提供了3个方法,next/return/throw
next方式是按步执行,每次返回一个值,同时也可以每次传入新的值作为计算
return则直接跳过所有步骤,直接返回 {value: undefined, done: true}
throw则根据函数中书写try catch返回catch中的内容,如果没有写try,则直接抛出异常
async 函数返回一个 Promise 对象,当函数执行的时候,一旦遇到 await 就会先返回,等到触发的异步操作完成,再接着执行函数体内后面的语句。
// 定义了一个promise,用来模拟异步请求,作用是传入参数++ function getNum(num){ return new Promise((resolve, reject) => { setTimeout(() => { resolve(num+1) }, 1000) }) } //自动执行器,如果一个Generator函数没有执行完,则递归调用 function asyncFun(func){ var gen = func(); function next(data){ var result = gen.next(data); if (result.done) return result.value; result.value.then(function(data){ next(data); }); } next(); } // 所需要执行的Generator函数,内部的数据在执行完成一步的promise之后,再调用下一步 var func = function* (){ var f1 = yield getNum(1); var f2 = yield getNum(f1); console.log(f2) ; }; asyncFun(func);
首先async和await函数是generator函数的语法糖
generator函数可以看做一个状态机,内部有多种状态,程序员可以通过调用next()方法来驱动generator函数来执行,每次执行会返回一个迭代器,包含当前执行的结果 value 和 是否完成 done {value,done}
async函数就是generator函数加上自动机
定义一个asyncFun函数,参数是传递一个generator函数,在asyncFun内又定义了一个next方法,判断函数是否执行结束,如果结束则返回结果,如果没有结束则等待promise函数执行完毕后在then方法中递归调用generator函数的next方法
在执行的过程中,判断一个函数的promise是否完成,如果已经完成,将结果传入下一个函数,继续重复此步骤。
4. Promise,发送1、2、3请求后,再发送4、5、6的请求怎么实现?或者说有100个promise请求。怎么分组按序执行?
5. 项目中的头像的剪裁怎么做的?
6. 预览图居中怎么用CSS实现?未知宽高的预览图在指定大小的框框内居中,像微信朋友圈那样。
使用css3的background属性来设置
<style>
#mydiv {
width: 200px;
height: 200px;
background: url(./1.jpg) center;
}
</style>background-position: 规定图像背景的位置
background-size: 规定图像背景的尺寸
background-repeat:规定如何重复图像背景
background-origin:规定背景图片的定位区域
background-clip:规定背景图片的绘制区域
7. Vue的生命周期
8. v-if 和 v-show 的区别,什么时候用v-if、什么时候用v-show
v-if
是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。
v-if
也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。相比之下,
v-show
就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。一般来说,
v-if
有更高的切换开销,而v-show
有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用v-show
较好;如果在运行时条件很少改变,则使用v-if
较好。
9. v-for 只循环数组内对象有a属性的元素如何实现
v-for 和 v-if 可以一同使用
<li v-for="todo in todos" v-if="!todo.isComplete"> {{ todo }} </li>
10. vue 的 computed 属性和 watch 属性,还有其他哪些属性?
生命周期函数
data:vue实例观察的数据对象
methods:自定义方法
el:指定vue实例的DOM根元素
compute: 计算属性
watch: 监听属性
refs: vm.$refs:类型(Object),一个对象,其中包含了所有拥有 ref 注册的子组件;
11. vue的DOM树的查找(DIFF算法)、双向数据绑定原理
12. 你认为接下来的前端要往哪个方向发展,发展趋势? 你的学习方向是怎样的?一个优秀的前端工程师是怎样的?
13.函数声明和函数表达式的区别?
实际上,解析器在向执行环境中加载数据的时候,对函数声明和函数表达式并非一视同仁,解析器会率先读取函数声明,并使其在执行任何代码之前可用(可以访问);至于函数表达式,则必须等待解析器执行到它所在的代码行,才会真正地被解释执行。
alert(sum(10,10)) function sum(num1,num2) { return num1 + num2; }
以上的代码可以正常运行,因为在代码开始执行前,解析器就已经通过一个名为函数声明提升的过程,并将函数声明添加到执行环境中。
alert(sum(10,10)) // 报错 var sum = function (num1,num2) { return num1 + num2; }
以上的代码则会导致运行时的报错。
1.函数声明中函数名是必须的;函数表达式中则是可选的
2.用函数声明定义的函数,函数可以在函数声明之前调用,而用函数表达式定义的函数只能在声明之后调用。
3.以函数声明的方法定义的函数并不是真正的声明,它们仅仅可以出现在全局中,或者嵌套在其他的函数中, 但是它们不能出现在循环,条件或者try/catch/finally中,而 函数表达式可以在任何地方声明.
补充:
函数的内部属性:arguments、this、arguments.callee()
函数的递归和闭包
14. v-on:click 或者 @click 如何阻止事件冒泡?
事件流:事件流描述的是从页面中接收事件的顺序。
有两种事件流:事件冒泡、事件捕获
事件冒泡:事件由具体的元素接收,然后逐级向上传播到较为不具体的节点。
事件捕获:事件从不太具体的节点传播到具体的节点。
DOM事件流:事件捕获到处于目标阶段再到事件冒泡阶段。
1. 利用原生的方法阻止事件冒泡
<div>
<button id="btn"/>
</div>
div 也注册了点击事件, event.stopPropagation() 可以阻止事件冒泡导致div的点击事件被触发
div.onclick = function(event) {
alert('body clicked');
}
btn.onclick = function(event) {
alert('btn click');
event.stopPropagation();
}
event.cancelBubble = true; IE 阻止事件冒泡
event.stopPropagation(); DOM 阻止事件冒泡
return false; 同时阻止事件冒泡和事件默认行为。2. 利用vue封装的方法来阻止事件冒泡
<div @click.stop="show2()">点击我呀</div>
附阻止默认行为
<div @contextmenu.prevent="show2()">右键点击我呀</div>
15. 你是如何学习前端的?
16. JavaScript 单线程事件循环机制
单线程中,事件监听和其他异步有什么区别
你对事件的看法是什么
JavaScript语言是单线程的,同一个时间只能做一件事;
遵循事件循环机制,当JS解析执行时,会被引擎分为两类任务,同步任务(synchronous) 和 异步任务(asynchronous)。对于同步任务来说,会被推到执行栈按顺序去执行这些任务。对于异步任务来说,当其可以被执行时,会被放到一个 任务队列(task queue) 里等待JS引擎去执行。当执行栈中的所有同步任务完成后,JS引擎才会去任务队列里查看是否有任务存在,并将任务放到执行栈中去执行,执行完了又会去任务队列里查看是否有已经可以执行的任务。这种循环检查的机制,就叫做事件循环(Event Loop)。对于任务队列,其实是有更细的分类。其被分为 微任务(microtask)队列 & 宏任务(macrotask)队列。
await等到之后,做了一件什么事情?
那么右侧表达式的结果,就是await要等的东西。
等到之后,对于await来说,分2个情况
不是promise对象
是promise对象
如果不是promise,await会阻塞后面的代码,先执行async外面的同步代码,同步代码执行完,再回到async内部,把这个非promise的东西作为await表达式的结果。
如果它等到的是一个promise对象,await也会暂停async后面的代码,先执行async外面的同步代码,等着Promise对象fulfilled,然后把resolve的参数作为await表达式的运行结果。
JavaScript的单线程,与它的用途有关。作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?
为了利用多核CPU的计算能力,HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程,但是子线程完 全受主线程控制,且不得操作DOM。所以,这个新标准并没有改变JavaScript单线程的本质。
其他人的金山前端面试题:
1. 如何判断前端性能,时间指标(白屏时间、dom树构建、整页时间)
2. web工程化,快速构建web项目
3.前端安全和性能优化
4.如何判断浏览器是否支持某个方法(兼容性)
5.css画一个三角形