前端面试小册
常考面试题一
1、原始类型有那种?nulll是对象吗?
原始数据类型主要分为: number,string,Boolean,null,undefind null是对象
2、对象类型和基础类型的不同之处,函数参数是对象类型和基础类型分别会如何?
基础类型按值储存在栈内存中 对象类型(引用类型)储存在堆内存中。以指针方式去使用 函数参数和复制操作: 基础数据类型在重新创建一份新值。改变其中任何一个,另一个不受影响 引用数据类型。变量对象也会为其开辟空间,但复制的是指针,都指向内存的值,一个改变,另一个也回受影响
3、typeof 与 instanceof?
typeof 与 instanceof都是判断数据类型的。区别如下: typeof判断基础数据类型。当判断null的时候将返回objcet instanceof判断引用数据类型,原理根据原型链追踪去实现
4、类型转换?
-
转数字?
null=》0 undefined=》NaN Boolean true =》1 false=》0 Sting 数字=》数字 字母=》NaN 空字符串=》0 数组 空数组=》0 一个元素且为数字=》数字 其他=》NaN 引用类型 NaN
-
转字符串
underfind=》‘underfind’ null=》‘null’ Number '数字' Boolean ‘true’ ‘false’ 数组 ‘【12.43,323】’=>12.43,323 对象 [object Object] function function(){console.log(212)}
-
转布尔值?
null false underfind false Number 0,-0,NaN=>false 其他=>true String ''=>false 其他=>true 引用类型 true
5、对象转基础数据类型?
转字符串类型直接调用toString() 转其他类型先转valueOf()
6、四则运算?
运算中其中一方是字符串,另一个方也将转换成字符串 如果一方不是字符串数字。那么会将它转成数字或者字符串 除了加减运算之外。一方为数字,另一方转为数字
7、比较运算符?
如果是对象,就通过 toPrimitive 转换对象 如果是字符串,就通过 unicode 字符索引来比较
8、如何判断this指向,箭头函数中this指向那里?
-
全局this
window
-
函数中的this
对象调用,则指向这个对象 独立调用,指向window
-
使用call,apply显示指定this
apply.call,bind动态this
-
构造函数与原型方法上的this
指向当前实例化后的对象。
-
箭头函数中的this
调用箭头函数外层第一个普通函数的this
常考面试题二
==和===的区别?
-
==
先判断数据类型是否相同,一致判断值大小 类型不同,进行类型转换 先判断是否是null和underfind的比较,是返回true 判断是否是string和number的比较,是先将字符串转成对应的数字进行比较 判断一方是否为布尔值,是则把布尔值换成number进行比较 判断一方是否为object,且另外一方为string,number,是则把object转成基础类型进行判断
-
===
不会尽享类型转换,直接对比值的大小
闭包
-
什么是闭包?
在函数执行上下A 在执行上下文A中的函数B 调用了A中的变量。闭包产生
-
闭包的好处?以及和垃圾回收机制的关系?
在js中,函数上下文执行完之后,生命周期结束后。垃圾回收机制就会回收内部不被使用的变量,也就是内存中失去引用的变量,对其进行回收。闭包会阻止此过程 js中具有自动垃圾回收机制,对于函数内部的变量失去引用之后,很快会被回收,但是处于全局的变量,js不会回收,除非引用完及时释放,尽量少使用全局变量
浅拷贝和深拷贝
-
浅拷贝
基础类型值的拷贝 引用类型拷贝的引用地址(指针) 一个改变另一个必受影响 Object.assign()和...都是浅拷贝
-
深拷贝
重新开辟内存空间,互相不影响
function deepClone(obj) { function isObject(o) { return (typeof o == 'object' || typeof o == 'function') && o !== null } if (!isObject(obj)) { throw new Error('this is not objcet') } let isArray = Array.isArray(obj) let newObj = isArray ? [...obj] : { ...obj } Reflect.ownKeys(newObj).forEach(key => { newObj[key] = isObject(obj[key]) ? deepClone(obj[key]) : obj[key] }) return newObj }
原型链
对象的 proto 属性指向原型, proto 将对象和原型连接起来组成了原型链
- 构造函数
- 原型
- 原型
es6常考知识点
什么是提升?什么是暂时性死区?var、let 及 const 区别?
-
提升
当控制器执行到可执行的代码的时候,js就会创建执行上下文 执行上下文的创建阶段会创建变量对象。此时 此时会先创建arguments对象 检查函数,以函数声明并创建属性 检查var声明的变量,复制underfind 其实这个就是所谓的变量提升阶段
-
var 、const、let的区别?
区别: var存在变量提升 可以重复声明 可以用window去调用 const、let 不存在变量提升 不可重复声明 拥有块级作用域 不可通过window去调用 const赋值不可更改
-
暂时性死区
当变量未声明之前。去调用此变量,被叫做暂时性死区
原型如何实现继承?Class 如何实现继承?Class 本质是什么?
-
原型继承
-
组合继承
构造函数继承通过 call改变this指向去继承上面的方法和属性 原型上的继承 将子类的原型指向父级的实例话对象
-
寄生继承
构造函数继承同样使用call改变指向进行继承 原型继承则通过Object.create()进行继承
-
-
class继承
class 实现继承的核心在于使用 extends 表明继承自哪个父类 并且在子类构造函数中必须调用 super,因为这段代码可以看成 Parent.call(this, value)
-
class本质
class 的本质就是函数。
为什么要使用模块化?都有哪几种方式可以实现模块化,各有什么特点?
-
模块化的使用
解决命名冲突 实现复用 提高代码的可维护程度 避免变量全局污染
-
匿名函数自执行
-
ES Module
不支持动态引入
Proxy 可以实现什么功能?
-
对象的代理
代理,可是实现数据的双向绑定
let handler = { get(target, property, receiver) { getLogger(target, property) return Reflect.get(target, property, receiver) }, set(target, property, value, receiver) { setBind(value, property) return Reflect.set(target, property, value) } } return new Proxy(obj, handler) } let p = onWatch( obj, (v, property) => { console.log(`监听到属性${property}改变为${v}`) }, (target, property) => { console.log(`'${property}' = ${target[property]}`) } ) p.a = 2 // 监听到属性a改变 console.log(p.a)
-
表单校验
-
阅后即焚
-
过滤不存在的属性
map, filter, reduce
-
map
返回一个新数组。可以在这个函数中加逻辑处理返回 接受三个参数 当前的元素 index 愿数组
-
filter
返回一个新数组。对符合条件元素进行返回 接受三个参数 当前的元素 index 愿数组
-
reduce
数组的计算 接受两个参数,分别是回调函数和初始值
性能优化琐碎事
图片优化
常考算法知识点
Vue 常考基础知识点
生命周期
父子组建传旨
设计模式
工厂模式
隐藏了这个复杂的过程,只需要一句代码调用就能实现功能。
单例模式
隐藏了这个复杂的过程,只需要一句代码调用就能实现功能。
适配器模式
适配器用来解决两个接口不兼容的情况,不需要改变已有的接口,通过包装一层的方式实现两个接口的正常协作。 ``` class Man { getName() { return '港版插头' } } class Son { constructor() { this.proxy = new Man() } getName() { return this.proxy.getName() + 'hahahahh' } static create(name) { console.log(name) } } let s = new Son() console.log(s.getName())
```
装饰模式
代理模式
代理是为了控制对对象的访问,不让外部直接访问到对象。在现实生活中,也有很多代理的场景。比如事件代理
发布-订阅模式
发布-订阅模式也叫做观察者模式。通过一对一或者一对多的依赖关系,当对象发生改变时,订阅方都会收到通知。
外观模式
JS 异步编程及常考面试题
并发(concurrency)和并行(parallelism)区别?
并发是一段时间相继完成,比如A和B,一段时间内切换完成类似早上起床前。洗漱,吃饭,出门。一段时间完成的一些事 并行是同时进行,比如边看手机边吃饭
什么是回调函数?回调函数有什么缺点?如何解决回调地狱问题?
当我们异步请求成功时会在回调函数中写我们的逻辑。当然这里的逻辑还涉及到进一步的请求,不断嵌套就会出现回调地狱 回调函数缺点: 嵌套过深,耦合度高,不易维护 难以捕捉错误 不能使用try。。catch 使用Generator和promise以及async都可以
你理解的 Generator 是什么?
天然的迭代器,可以是遍历停下来 可控制迭代器的函数,可以暂停,也可以选择任何时候恢复 使用场景: 抽奖 小游戏 斐波那契数列
Promise 的特点是什么,分别有什么优缺点?什么是 Promise 链?Promise 构造函数执行和 then 函数执行有什么区别?
特点: Promise三个状态,padding,resolve和reject。状态不可逆,一旦确认,无法改变 Promise链: 通过then方法去传递执行,执行then方法之后会返回一个promise对象,来完成链式操作 构造函数和then函数执行有哪些区别? 构造函数内的内容立即执行。 then的函数当状态改变在进行执行
async 及 await 的特点,它们的优点和缺点分别是什么?await 原理是什么?
优化了promise链式调用,以同步的写法去操作异步代码 原理其实是promise的语法糖,await 内部通过promise静态方法Promise.resove()返回一个新的promise
setTimeout、setInterval、requestAnimationFrame 各有什么特点?
JS 进阶知识点及常考面试题
apply
Function.prototype.myApply = function (context, arr) {
if (typeof this !== 'function') {
throw new Error('error')
}
context = context || window
context.fn = this
let reslut;
if (arr) {
reslut = context.fn(...arr)
} else {
reslut = context.fn()
}
delete context.fn
return reslut
}
call
Function.prototype.myCall = function (context) {
if (typeof this !== 'function') {
throw new Error('error')
}
context = context || window
context.fn = this
let args = [...arguments].slice(1)
let reslut = context.fn(...args)
delete context.fn
return reslut
}
bind
Function.prototype.myApply = function (context, arr) {
if (typeof this !== 'function') {
throw new Error('error')
}
context = context || window
context.fn = this
let reslut;
reslut = arr ? context.fn(...arr) : context.fn()
delete context.fn
return reslut
}
new
function news() {
let obj = new Object()
let Constructor = [...arguments].shift()
obj.__proto__ = Constructor.prototype
let res = constructor.apply(obj, arguments)
return typeof res === 'object' ? ret : obj
}
instanceof
function instanceofs(left, right) {
let prototype = right.prototype
left = left.__proto__
while (1) {
if (left == null || left == undefined) {
return false
}
if (left == prototype) {
return true
}
left = left.__proto__
}
}
垃圾回收机制
v8实现了精确式GC,GC算法采用分代垃圾回收机制,因此。v8将内存(堆)分为新生代和老生代两部分
-
新生代算法
对象存活时间较短,使用 Scavenge GC 算法 在新生代内存空间分为2部分,分别是from空间和to空间,在这2个空间其中必然有一个是空闲的。新分配的对象会放到from空间,当from空间被占满的时候,新生代GC就会启动,算法会检查from空间的存活对象,将他们复制到to空间,其中失去存活的对象就会被销毁,将复制完,from和to空间互换,
- from空间
- to空间
-
老生代算法
-
什么时候启动标记清除算法?
某一个空间没有分块时 空间中被对象超过一段限制时 空间不能保证新生代对象转到老生代中 这个时候遍历堆中所有活的对象,在标记完成后,销毁那些没有标记的对象。
-
标记整理算法
清除对象后会造成堆内存出现碎片的情况 当碎片超过一定限制的时,会启动压缩算法。在压缩过程中,将活的对象像一端移动,直到所有对象都移动完成然后清理掉不需要的内存。
-
什么时候对象会出现老生代算法中?
新生代中的对象是否已经经历过Scavenge算法。如果经历过,会将新生代空间转到老生代空间中 当to空间的对象占空间大小的25%,这样情况下。为了不影响内存分配。会将对象从新生代的空间转老生代空间中
-
浏览器基础知识点及常考面试题
跨域
-
什么是跨域?
浏览器出与安全考虑。有同源策略。也就是当协议。域名。端口号任何一个不同就是跨域。Ajax就会请求失败
-
为什么浏览器要使用同源策略?
其实主要是用来防止 CSRF 攻击的。简单点说,CSRF 攻击是利用用户的登录态发起恶意请求。
-
你有几种方式可以解决跨域问题?
jsonp cors document.domain postMessage
-
了解预检请求嘛?
对于复杂请求来说,首先会发起一个预检请求,该请求是 option 方法的,通过该请求来知道服务端是否允许跨域请求。
事件
-
事件处理程序
-
IE事件处理程序
增加和和删除事件: element.attachEvent('on'+事件类型,处理函数) element.detachEvent(‘on’+事件类型,处理函数)
-
chrome事件处理程序
element.addEventListener('click',处理函数,是否冒泡) false(默认冒泡) true(捕获) element.removeEventListener('click',处理程序,是否冒泡) 同添加事件一致
-
-
事件对象
-
IE事件对象
cancelBubble =》默认值为false,但设置true就可以取消事件冒泡 returnValue =》默认true,设置为false,,就可以取消事件的默认行为 srcElement =>事件目标 type=>事件类型
-
chrome事件对象
stopPropagation =》取消事件冒泡 preventDefault =》取消事件的默认行为 target =>事件目标 type=>事件类型
-
-
事件代理
如果一个节点中子节点是动态生成的,那么子节点需要注册事件的化应该注册在父节点上 好处: 节省内存空间 不需要给子节点注销事件
-
事件的触发过程是怎么样的?知道什么是事件代理嘛?
事件触发有三个阶段: window往事件触发传播。遇到注册的捕获事件会触发 传播到事件触发时触发注册事件 从事件触发之处向window传播。遇到注册的冒泡会触发 从捕获到目标阶段再到冒泡的过程
-
事件捕获
从上向下执行的一个过程 Document=》html=》body=》div
-
事件执行阶段
-
事件冒泡
从当前事件触发向上查找过程 div=>body=>html=>document
-
存储
cookie已经不建议存储了,如果没有大量数据存储需要,使用localStorage和sessionStorage 对于不怎么改变的数据存使用localStorage。否则使用sessionStorage
-
cookie
作用:主要用于储存用户的登陆信息, 生命周期:一般有服务器生成,可以设置过期时间 数据储存大小:4k 与服务端通信:每次都会携带在headr中,对于请求性能影响
属性 作用 value 如果用于保存登陆状态,应加密,不能使用明文的用户标示 http-only 不能通过js访问cookie,减少xss的攻击 secure 只能在协议为https的请求中携带 same-site 规定浏览器不能在跨域请求中携带cookie,减少CSRE攻击 -
localStorage
生命周期:除非被清理,否则一直存在 数据存储大小:5M 与服务端通信:不参与
-
sessionStorage
数据生命周期:页面关闭就清理 数据存储大小:5M 与服务端通信:不参与
-
indexDB
数据生命周期:除非被清理,否则一直存在 数据存储大小:无限 是否与服务端通信:不参与
Service Worker
service worker是一段脚本,与web worker一样,也在后台运行,作为一个独立的线程。运行环境和普通脚本不同,所以不能直接参与web交互行为。native app可以做到离线使用,消息推送。后台自启动,service worker的出现为了是web app 也有类似的能力
-
使用场景
-
后台消息传送
-
网络代理转发请求。伪造响应
-
离线缓存
- 离线缓存
-
消息推送
-
浏览器缓存机制
性能优化领域 缓存可以说是性能优化中最简单高效的一种方式了。他以最高减少网络传输所带来的损耗 数据请求: 网络请求 后端处理 浏览器响应 直接使用缓存,而不发请求 或发起请求后端存储的数据和前端一致,那么就没必要将数据回传过来,这样可以减少响应数据
缓存位置
-
Service Worker
优点: 它的缓存和其他内建的缓存机制不同。它可以由我们自定缓存那些文件,如何匹配缓存,如何读取缓存,并且缓存是持久性的
-
Memory Cache
优点: 内存中的缓存。读取内存中的数据比磁盘要快很多 访问过页面之后,再次刷新页面,可以发现之前很多数据都来自内存缓存 缺点: 持续性短,随着进程的释放而释放 大文件一般都是不会储存内存中,反之优先
-
Disk Cache
优点: 储存在硬盘中。覆盖率基本是最大的,什么都可以存入 跟内存相比。容量和储存时效性超级好
-
Push Cache
储存在会话中,一旦会话结束就会被释放
缓存策略
-
强缓存
-
Expires
是HTTP/1的产物,表示资源的过期时间,并受限与本地时间。如果修改了时间,缓存失效
-
Cache-control
出现于HTTP/1.1的产物,优先级比Expires要高 该属性可以调整设置时间 Cache-control可以在请求头或者响应中设置,并且可以组合多种指令 private=>响应可以被客户端缓存 pablic=》可以同被客户端和代理服务器缓存 no-cache=》资源会被缓存,但立即失效。下次发起请求会验证是否过期
-
-
协议缓存
如果缓存过期了。就需要发起请求验证资源是否更新,协议缓存可以通过2个http-header实现:Last-Modified+ETag 当浏览器发起请求验证资源时,如果资源没有做出改变,那么服务器会返回304状态吗。并且更新缓存有效期 如果资源有所改变,更新资源
-
Last-Modified
表示本地文件最后更改的日期。If-Modified-Since会将last-Modified的值发送给服务器,询问服务器在该日期更新后资源是否有变动,有更新,返回更新后的信息,反之,返回状态码 弊端: 如果是本地打开缓存文件,即使没有对文件进行修改,但还是会造成last-Modified的修改。服务端不能命中缓存导致发送相同的资源 因为last-Modified只能以秒计时。如果在不可感知的时间你内完成了这个文件,那么会造成服务端认为资源被秒中,不会返回正确值
-
ETag
类似指纹,If-None-Match会将ETag发送给你服务器,询问服务器资源ETag是否改变,如有改变,将更新的资源返回来,ETag比Last-Modified的优先级高
-
浏览器渲染机制
浏览器接收到 HTML 文件并转换为 DOM 树
首先浏览器打开一个网页的时候,首先会解析他对应的html,在网络传输中我们平时所写的js+css+html都都是以子节数据(0-1)进行传输 转子节转为字符串。 字符串通过词法解析为标记(token),这一过程也被称为标记法。 将结束标记之后,将会把标记转为node 根据node之前的联系转成dom
将 CSS 文件转换为 CSSOM 树
首先这一过程是非常耗性能的,因为浏览器会确定每一个节点样式分别是什么,需要递归匹配到数据的变化 子节数据 字符串 标记(token) node cssom
生成渲染树?
当我们生成dom树和cssom树的时候,就需要将这2个树和成渲染树 在这一过程中,将包括需要的节点和这些节点的样式去渲染出来 当浏览器生成渲染树之后,浏览器根据渲染树布局,然后GPU绘制。合成图层
为什么操作 DOM 慢?
因为dom属于渲染引擎,js属于js引擎,面对两个线程之前的通信,操作dom次数一多,也就等同于进行线程之前的切换,并且操作dom可能带来回流。
什么情况阻塞渲染?
渲染的前提是生成渲染树,所有html和css肯定会堵塞渲染 降低一开始需要渲染的文件大小 并且扁平化。优化选择器 当浏览器在执行到script标签时,就会暂时dom,完成后从暂停处继续执行, 首评加载的越快,就不该在首评加载js。建议将script放到body下面的原因 async(适合没有依赖的文件) js文件下载和解析不会阻塞渲染 defer 并行下载,会等到html执行完毕之后在进行执行
重绘(Repaint)和回流(Reflow)
回流一定会引起重绘 但重绘不一定会引起回流
-
重绘(Repaint)
当改变节点的样的时候。不会改变布局的时候,比如修改color样式。
-
回流(Reflow)
一般布局修改,dom操纵一般会触发回流
减少重绘和回流的方式?
使用 transform 替代 top 使用 visibility 替换 display: none ,因为前者只会引起重绘,后者会引发回流(改变了布局) 不要把节点的属性值放在一个循环里当成循环里的变量 不要使用 table 布局,可能很小的一个小改动会造成整个 table 的重新布局 动画实现的速度的选择,动画速度越快,回流次数越多,也可以选择使用 requestAnimationFrame CSS 选择符从右往左匹配查找,避免节点层级过多
不考虑缓存和优化网络协议的前提下,考虑可以通过哪些方式来最快的渲染页面?
从文件大小 从script标签上使用来考虑 从html和css代码书写上来考虑 从需要下载的内容是否需要在首屏使用上来考虑
安全防范知识点
xss
想尽一切办法将可执行的代码注入网页中
-
持久型攻击
攻击的代码被服务器写日数据库,这种危害会很大,如果网站访问量大的话,会导致正常访问页面的用户都收到攻击 一般会以评论方式去注入
-
非持久型攻击
一般以修改URL参数的方式进行攻击 诱导用户访问链接从而实现攻击
转义字符
对于用户输入的东西永远不要相信,最普通的做法是对用户输入的内容进行转译。 引号。尖括号。斜杠等进行转译‘ 或者使用白名单也可以,js-xss来实现
cors
跨站伪造请求,攻击者构造出一个向后端请求的地址,诱导用户点击或者通过某种途径自动发起请求,如果用户是在登陆的情况下,后端以为是用户操作,从而进行诱导。 常用方式: 加入网站中有个get请求提交表单的接口。那么攻击者会在钓鱼网站加入一个图片,图片的地址就是这个评论的接口 防御: get请求不对数据进行修改 不让第三方访问到用户的cookie(some-site) 阻止第三方网站请求接口(验证refrer) 请求是附带验证信息,比如token或者验证码,进行判断
点击劫持
攻击者通过将要攻击的网站通过iframe的方式放入自己的网站中,并将iframe设为透明,诱导用户点击 防御: js判断,删除页面中的iframe
中间人攻击
是指攻击方同时将服务端和客户端同时进行连接。并让对方认为都是安全的,但实际上整个过程中,都是被控制了,攻击者可以同时修改用户的信息和数据库中的内容 防御: 尽量避免在公众场合使用Wi-Fi。避免被攻击
v8下的js性能优化
XMind: ZEN - Trial Version