面试
1. css的重绘与回流
重绘:
当节点需要更改外观而不会影响布局。
回流:
DOM结构的修改引发DOM几何尺寸变化的时候,发生回流。
常见的几何属性有width、height、padding、margin、left、top、border 或者是DOM节点发生增减移动。
减少重绘和回流的办法。
1.使用css3新增属性:translate替代top等方向值。
2.避免频繁使用style,而是采用class。
2. 两种盒模型分别说一下
content-box:width == 测量width和height属性只包括的内容
border-box:width == width和height属性包括内容和padding以及border
3. rem、em的区别?移动端适配还有什么方法?
4. 如何垂直居中?
5. js事件循环机制 (扩展宏任务,微任务)
image.png- 同步和异步任务分别进入不同的执行"场所",同步的进入主线程,异步的进入Event Table并注册函数
- 当指定的事情完成时,Event Table会将这个函数移入Event Queue
- 当栈中的代码执行完毕,执行栈(call stack)中的任务为空时,就会读取任务队列(Event quene)中的事件,去执行对应的回调
- 如此循环,形成js的事件循环机制(Event Loop)
6. 讲一下let、var、const的区别
- var 没有块级作用域,支持变量提升。
- let 有块级作用域,不支持变量提升。不允许重复声明,暂存性死区。不能通过window.变量名进行访问.
- const 有块级作用域,不支持变量提升,不允许重复声明,暂存性死区。声明一个变量一旦声明就不能改变,改变报错。
7. Promise、Promise.all、Promise.race 分别怎么用?
- 背代码 Promise 用法
function fn(){
return new Promise((resolve, reject)=>{
成功时调用 resolve(数据)
失败时调用 reject(错误)
})
}
fn().then(success, fail).then(success2, fail2)
- 背代码 Promise.all 用法
Promise.all([promise1, promise2]).then(success1, fail1)
promise1和promise2都成功才会调用success1
- 背代码 Promise.race 用法
Promise.race([promise1, promise2]).then(success1, fail1)
promise1和promise2只要有一个成功就会调用success1
8.闭包
闭包就是有权访问一个函数内部变量的函数,也就是常说的函数内部嵌套函数,内部函数访问外部函数变量,从而导致垃圾回收机制没有将当前变量回收掉。这样的操作,有可能会带来内存泄漏。好处就是可以设计私有的方法和变量。
9.垃圾回收机制(闭包的延伸)
js拥有特殊的垃圾回收机制,当一个变量在内存中失去引用,js会通过特殊的算法将其回收,并释放内存。
分为以下两个阶段:
1.标记阶段
:垃圾回收器,从根对象开始遍历,访问到的每一个对象都会被标示为可到达对象。
-
清除阶段
:垃圾回收器在对内存当中进行线性遍历,如果发现该对象没有被标记为可到达对象,那么就会被垃圾回收机制回收。
这里面牵扯到了引用计数法,每次引用都被会‘➕1’ 如果标记清零,那么就会被回收掉。
10. 手写函数防抖和函数节流
防抖:
- 如果下达该命令后,在t毫秒内再次下达该命令,则取消刚刚下达的命令,只执行新命令
- 最终效果: 对于连续动作(动作间的时间间隔小于t),以最后一次为准
function debounce(fn, wait) {
let timer = null
return function() {
if(timer) {
clearTimeout(timer)
}
timer = setTimeout(() => {
fn.apply(this, arguments)
timer = null
}, wait)
}
}
let fn = () => console.log('这里只执行很少次')
fn = debounce(fn, 1000)
document.body.onscroll = fn
节流:
- 从上一次命令结束开始的一定时间范围t内,如果多次连续下达命令,则只执行当前时间段t内第一次命令。
- 最终效果:对于连续动作,会过滤出部分动作,让这些过滤后的动作之间的执行间隔大于等于t
// 节流(一段时间执行一次之后,就不执行第二次)
function throttle(fn, delay){
let canUse = true
return function(){
if(canUse){
fn.apply(this, arguments)
canUse = false
setTimeout(()=>canUse = true, delay)
}
}
}
const throttled = throttle(()=>console.log('hi'), 1000)
throttled()
11. call、apply区别
相同点:都是重定向this指针的方法。
不同点:call和apply的第二个参数不相同,call是若干个参数的列表。apply是一个数组
bind
bind方法是直接返回一个新的函数,需要手动去调用才能执行。
12.简述cookie、localstorage、seesionstorage
image.png13.js跨域如何解决
目前暂时已知的跨域方法是:
- jsonp跨域,原理:script标签没有跨域限制的漏洞实现的一种跨域方法,只支持get请求。安全问题会受到威胁。
- cors跨域,通过后端服务器实现,Access-Control-Allow-Origin。
- postMessage window的一个属性方法。
- websocket
- nginx反向代理
- iframe跨域
webpack proxy跨域
首先需要明白webpack proxy跨域只能用作与开发阶段,临时解决本地请求服务器产生的跨域问题。并不适合线上环境。配置在webpack的devServer属性中。webpack中的devsever配置后,打包阶段在本地临时生成了一个node服务器,浏览器请求服务器相当于请求本地服务。
14. http和https区别
image.png15. ssl加密
分为对称和非对称加密
- 对称加密。 客户端和服务端公用一个密钥对消息加解密。(客户端和服务端约定好一个加密钥匙。客户端在发消息浅用该密匙对消息加密,发送给服务器,服务器在用该密匙进行解密拿到消息)
- 非对称加密。客户端和服务端都有公钥和私钥。公钥加密的内容只有对应的私钥解密。私钥自己留着,公钥发给对方。这样发送消息之前,对方的公钥对消息进行加密,受到后在用自己的私钥进行解密。
16. HTTP 状态码知道哪些?分别什么意思?
200 OK 正常返回信息
301 Moved Permanently 请求的网页已永久移动到新位置。
302 Moved Permanently 请求的网页已临时移动到新位置。
- 302重定向只是暂时的重定向,搜索引擎会抓取新的内容而保留旧的地址,因为服务器返回302,所以,搜索搜索引擎认为新的网址是暂时的。
- 而301重定向是永久的重定向,搜索引擎在抓取新的内容的同时也将旧的网址替换为了重定向之后的网址。
403 Forbidden 禁止访问。
404 Not Found 找不到如何与 URI 相匹配的资源。
500 Internal Server Error 最常见的服务器端错误。
17.强缓存和协商缓存(回去百度)
-
强缓存和协商缓存。强缓存通过响应头实现:expires和cache-control。它表示在缓存期间不需要在发起请求。协商缓存:如果缓存过期,可以使用协商缓存解决问题。
-
协商缓存ETag 是需要发起请求。协商缓存需要客户端和服务端共同实现。
18. export和export default区别
export的使用
1.直接输出
export let words = 'hello world!!!'
export function output() {
// ...
}
2.先定义再输出
let firstWords = 'hello'
let secondWords = 'world'
let thirdWords = '!!!'
function output() {
// ...
}
export {firstWords, secondWords, thirdWords, output}
export default的使用
1.export default 用于规定模块的默认对外接口
2.很显然默认对外接口只能有一个,所以 export default 在同一个模块中只能出现一次
3.export default只能直接输出,不能先定义再输出。
4.其在 import 方式上也和 export 存在一定区别
(1)export的输出与import输入
export function output() {
// ...
}
import {output} from './example'
(2)export default的输出与import输入
export default function output() {
// ...
}
import output from './example'
从以上两种 import 方式即可看出,export default 的 import 方式不需要使用大括号包裹。因为对于 export default 其输出的本来就只有一个接口,提供的是模块的默认接口,自然不需要使用大括号包裹。
18.webpack热更新原理
核心就是客户端从服务端拉取更新后的文件,进行一个替换;
实际上 WDS 与浏览器之间维护了一个 Websocket,当本地资源发生变化时,WDS 会向浏览器推送更新,并带上构建时的 hash,让客户端与上一次资源进行对比。客户端对比出差异后会向 WDS 发起 Ajax 请求来获取更改内容(文件列表、hash),这样客户端就可以再借助这些信息继续向 WDS 发起 jsonp 请求获取该chunk的增量更新。
19.英语题:loader 和 plugin 的区别是什么?
-
Loader
直译为"加载器"。Webpack将一切文件视为模块,但是webpack原生是只能解析js文件,如果想将其他文件也打包的话,就会用到loader。 所以Loader的作用是让webpack拥有了加载和解析非JavaScript文件的能力。
2.Plugin
直译为"插件"。Plugin可以扩展webpack的功能,让webpack具有更多的灵活性。 在 Webpack 运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果。
20.如何实现图片懒加载
当访问一个页面的时候,先把img元素或是其他元素的背景图片路径替换成一张大小为1*1px图片的路径(这样就只需请求一次),只有当图片出现在浏览器的可视区域内时,才设置图片真正的路径,让图片显示出来。这就是图片懒加载。
21.script标签如何实现异步加载
- defer:等到整个页面在内存中华正常渲染结束(DOM结构完全生成,以及其他脚本执行完成),才会执行;
- async是一旦下载完成,渲染就会中断,执行这个脚本之后,再继续渲染。
总结就是:defer是渲染完在执行。async是下载完就执行。
另外值得注意的就是:deger脚本会按照在页面出现的顺序加载,而async是不能保证加载顺序的。
vue双向绑定
Vue是采用数据劫持结合发布/订阅模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
个人理解:
在new Vue的时候,在Observer中通过Object.defineProperty()达到数据劫持,代理所有数据的getter和setter属性,在每次触发setter的时候,都会通过(订阅器)Dep来通知Watcher,Watcher作为Observer数据监听器与Compile模板解析器之间的桥梁,当Observer监听到数据发生改变的时候,通过Updater来通知Compile更新视图
vue的created和mounted的区别
created:
在模板渲染成html前调用,即通常初始化某些属性值,然后再渲染成视图。
mounted:
在模板渲染成html后调用,通常是初始化页面完成后,再对html的dom节点进行一些需要的操作。
vue中data为什么不是一个对象而是一个函数
为什么组件的 data 是一个回调函数
组件就是一个 vue 实例。在 js 中,实例是通过构造函数 new 出来的,每个实例都会继承原型上的方法和属性。
- 组件的 data 若使用对象:对象是内存地址的引用,直接使用对象的话组件之间的 data 都会指向同一个内存地址,会造成组件之间数据的相互影响。
- 组件的 data 使用函数:在 vue 源码中可以看到,若 typeof data === 'function' 则使用的是 getData() 函数,该函数内部通过 call 方法把 this 指向 vm 实例本身。
vue中组件之间传值的方式
- 父子组件:使用 v-on 通过事件通信
- 爷孙组件:使用两次 v-on 通过爷爷爸爸通信,爸爸儿子通信实现爷孙通信
- 任意组件:使用 eventBus = new Vue() 来通信
- 任意组件:使用 Vuex 通信
- $ref改变组件的值
Vue.set 是做什么用的?Vue.nextTick 的原理和用途?
如果在实例创建之后添加新的属性到实例上,它不会触发视图更新,但是使用vue.set或者this.$set的方式可以使得新添加的属性也是响应式的,并触发视图更新。仅此而已。
1.在Vue生命周期的created()钩子函数进行DOM操作一定要放到Vue.nextTick()的回调函数中。
2.在数据变化后要执行的某个操作,而这个操作需要使用随数据改变而改变的DOM结构的时候,这个操作都应该放进Vue.nextTick()的回调函数中。
vue-router query和params传参(接收参数)route的区别
https://segmentfault.com/a/1190000012735168
1. 输入URL发生了什么
2. 常见的网站漏洞有哪些?
有跨站脚本攻击(XSS)
跨站请求伪造(CSRF)
SQL注入
3. 性能优化方法
- dns预解析
- 浏览器缓存,强缓存和协商缓存
- 预加载 将一些不影响首屏但重要的文件延后加载 preload
- 预渲染 prerender
- 懒加载
- 文件优化
- webpack优化 使用到tree shaking。各种loader等等
4.Http2.0有了解过吗
多路复用
上面提到HTTP/1.1的线头阻塞和多个TCP连接的问题,HTTP2的多路复用完美解决。HTTP2让所有的通信都在一个TCP连接上完成,真正实现了请求的并发。我们来看一下HTTP2具体是怎么实现的:
头部压缩
头部压缩也是HTTP2的一大亮点。在1.X版本中,首部用文本格式传输,通常会给每个传输增加500-800字节的开销。现在打开一个网页上百个请求已是常态,而每个请求带的一些首部字段都是相同的,例如cookie、user-agent等。HTTP2为此采用HPACK压缩格式来压缩首部。头部压缩需要在浏览器和服务器端之间:
维护一份相同的静态字典,包含常见的头部名称,以及常见的头部名称和值的组合
维护一份相同的动态字典,可以动态的添加内容
通过静态Huffman编码对传输的首部字段进行编码
服务器端推送
服务器端推送使得服务器可以预测客户端需要的资源,主动推送到客户端。
客户端了解到服务器端打算推送哪些资源,就不会再为这些资源创建重复请求。当客户端收到index.html的响应时,script.js和style.css已经位于缓存。