哈喽哈喽,这里是小菜不拖延博主,博主最近开始面试了,刚刚面完小红书,还没出结果先出一篇凉经,总的来说问的不难,但是也不妨碍我不会(sos,平时不注重理论就是这个结果),大抵是凉了的
- 自我介绍
- 项目难点
- 为什么选择做前端
- 其他:问了实验室的一些情况、做的小程序是什么、做的是什么项目(政府的还是企业的)
- 代码题数组去重,还有什么别的实现方法吗越多越好
- src和herf的区别
- script标签执行有几种形式(当时都没听懂这个是干嘛)
- 说一下事件循环
- data为什么是一个函数
- 还有什么其他的优化技术
- call、bind、apply函数的区别
- 强制缓存和协商缓存
ps:由于一个问题补充芝士太多了,我们分成几部分讲叭
事件循环
- 同步代码:放入js引擎当中立即执行并且原地等到结果
- 异步代码:先放入宿主环境,不必原地等待结果
同步代码放入执行栈,立即执行
异步代码交给宿主环境
异步代码等待结束之后放入队列任务
当执行栈里面的同步任务执行完成之后,就会到任务队列当中查看有没有需要执行的异步任务,有就放入执行栈执行,从执行栈到任务队列当中反复查看的这个过程就叫做事件循环
面试回答要点:
js当中的异步任务又被分为:
宏任务
宏任务是由宿主环境发起的,比如浏览器,宏任务比如由script代码块,setTimeout定时器等
微任务
是由js引擎发起的任务,例如promise,promise本身是同步的,但是他的catch、then的回调函数是异步的async/await
那么知道了他的执行顺序,我们来做一个题目
console.log(1)
setTimeout(function(){
console.log(2)
},0)
const p =new Promise((resolve,reject)=>{
console.log(3)
resolve(1000)
console.log(4)
})
p.then(data=>{
console.log(data)
})
console.log(5)
执行结果:
data为什么是一个函数
因为我们组件可能是会被复用的,假如我们把data写成一个对象,对象是引用数据类型,共用一个内存地址,也就是如果我们要复用这个组件,我们的data里面的数据是会因为某一处调用的改变而导致其他地方的调用也改变的,但是如果data是一个函数,数据是以函数返回值的防止定义的,这样每一次组件被调用的时候都是返回新的data,调用之间是不会被相互影响的,所以总的来说data是函数是为了防止产生数据污染
缓存
由于面试问到了缓存,那么我们就一起复习叭!这里我们就一起把所有缓存都复习了叭
http缓存
强缓存
就是浏览器访问某个某个资源的时候会判断是否使用本地缓存里已经存在的资源,如果使用的话,就不会发送请求到服务器,从而达到减轻服务器访问压力的作用,在强缓存当中是否使用缓存是有浏览器来确定的
- 强缓存的优先级大于协商缓存
使用:
在响应头当中设置Cache-Control
max-age=31536000,max-age代表缓存时间,单位为秒,意味着在一年内浏览器不会再向服务器发送请求- no-cache: 不使用强缓存(但仍会使用协商缓存)。
- no-store: 不使用缓存(不使用强缓存也不使用协商缓存),每次都向服务器发送资源请求。
- private: 只允许客户端使用缓存,不允许其他代理服务器进行缓存。
- public: 客户端和代理服务器都可缓存。
- s-maxage: 与max-age类似,区别是s-maxage是设定代理服务器的缓存时间。
缓存资源位置
磁盘缓存(disk cache)和内存缓存(memory cache)
较大资源--磁盘缓存,较小资源--内存缓存
内存缓存速度>磁盘缓存速度
Expires也可以实现强缓存,但是Expires版本低于Cache-Control
协商缓存
协商缓存是服务器告诉浏览器是否使用缓存,也就是说每一次的请求都会发送到服务器
使用:
浏览器初次请求资源,服务器返回资源的同时会生成一个Etag携带在响应头当中返回给浏览器,当浏览器再次请求资源的时候会在请求头里携带If-None-Match,他的值是之前服务器返回的Etag的值,服务器拿到If-None-Match的值会和之前的Etag值进行比对,如果:
- 没有变化返回304,就告诉浏览器使用缓存,不会返回资源文件
- 发生变化返回200,返回最新资源给浏览器使用
浏览器缓存
cookie
随浏览器关闭失效,数据很小4kb左右
//设置
document.cookie = 'username=John;
//获取
document.cookie
//删除,要重新设置cookie的过期时间为一个过去的时间,使其失效
document.cookie = 'username=;
expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/'
以下是webStorage,为HTML5的新特性
localStorage 除非手动删除,否则理论上来说是永久有效的,5mb左右
//存储
localStorage.setItem('username', 'John')
//获取
localStorage.getItem(key)
//删除
localStorage.removeItem('username')
sessionStorage
随网页关闭而被清除 使用方法和localStorage相同
call、bind、apply函数的区别
- 三种方法都是改变this指向的方法
- 三者第一个参数都是this要指向的对象,如果如果没有这个参数或参数为undefined或null,则默认指向全局window
- 三者都可以传参,但是apply是数组,而call是参数列表,且apply和call是一次性传入参数,而bind可以分为多次传入
- bind 是返回绑定this之后的函数,便于稍后调用;apply 、call 则是立即执行
call
注意是一个一个传参func.call(thisArg, arg1, arg2, ...)
//修改greet函数的this指向为obj
let obj = {name: 'Tom'};
function greet(message) {
console.log(`${message}, ${this.name}!`);
}
greet.call(obj, 'Hello');
// 输出: Hello, Tom!
apply
注意传参通过数组func.apply(thisArg, [arg1, arg2, ...])
let person = {name: 'Alice'};
function say(something, toWhom) {
console.log(`${this.name} says ${something} to ${toWhom}`); }
say.apply(person, ['Good morning', 'Bob']);
bind
bind方法返回的是一个新函数,不会立即执行
function fn(...args) {
console.log(this, args)
}
let obj = {
myname: '张三',
}
const bindFn = fn.bind(obj) // this 也会变成传入的obj ,bind不是立即执行需要执行一次
bindFn(1, 2) // this指向obj
fn(1, 2) // this指向window
阅读参考: