自己整理的八股文,不足之处还请指教
js的三大组成部分
ECMAScript:JS的核心内容,描述了语言的基础语法,比如var,for,数据类型(数组、字符串)
文档对象模型(DOM):DOM把整个HTML页面规划为元素构成的文档
浏览器对象模型(BOM):对浏览器窗口进行访问与操作
JS有哪些内置对象
String、Boolean、Array、Date、Math、Object、RegExp、Function...
Math:abs()、sqrt()、max()、min()
Date:new Date()、getYear()
Array:push()、pop()、sort()、join()
String:concat()、length、slice()、split()
操作数组的方法有哪些
push、pop、sort、join、map、some、every、splice、shift、unshif、concat、filter、reverse...
哪些方法可以改变原数组?
push、pop、unshift、shift、sort、reverse、splice
JS对数据类的检测方法有哪些
typeOf:只能判断基础数据类型,不能判断引用数据类型
instanceOf:只能判断引用数据类型,不能判断基础数据类型
constructor:几乎可以判断基础数据类型和引用数据类型,如果声明了一个构造函数,并把它的原型指向了Array
Object.prototype.tostring.call():可以判断基础数据类型和引用数据类型
说一下闭包?闭包有什么特点
什么是闭包?
闭包是指有权访问另一个函数作用域中变量的函数。函数嵌套函数,内部函数被外部函数返回并保存下来时,就产生了闭包
特点:可以重复利用变量,并且这个变量不会污染全局的一种机制,这个变量是一直保存在内存中,不会被垃圾回收处理
缺点:闭包较多时,会消耗内存,导致页面的性能下降,在IE浏览器中才会导致内存泄漏
使用场景:防抖,节流,函数嵌套函数避免全局污染的时候
前端的内存泄漏怎么理解
JS里已经分配内存地址的对象,由于长时间未被释放或者难以清除,造成长期占用内存的现象,会让资源大幅度浪费,最终导致运行速度慢,甚至崩溃的情况
垃圾回收机制,如果机制遇到问题,则无法回收,就会造成内存泄漏
引起内存泄漏的因素:一些未被声明直接赋值的变量;一些未销毁的计时器;使用过多的闭包,一些引用元素没有被清除
事件委托是什么
事件委托,又叫事件代理,原理是利用事件冒泡的机制来实现的。也就是说把子元素的事件绑定到父元素身上。如果子元素阻止了事件冒泡,那么事件委托也就不成立
阻止事件冒泡
event.stopPropagation()
addEventListener('click',函数名,true/false) 默认是false事件冒泡,true事件捕获
基本数据类型和引用数据类型的区别
基本数据类型:Number,Boolean,String,null,undefined,init...
基本数据类型保存在栈内存中,保存的是一个具体的值
引用数据类型:Array,Object,Function
引用数据类型保存在堆内存中,声明一个引用数据类型的变量,保存的是引用数据类型的地址
注:当两个引用数据类型指向同一个地址时,改变其中一个值,另一个也会改变
说一下原型链
1、原型就是一个普通对象,他是为构造函数的实例共享属性和方法;所有实例中引用的都是同一个对象
2、使用prototype可以把方法挂在原型上,保存一份内存地址
3、_proto_是一个指针,实例对象中的属性,指向了构造函数的原型
一个实例对象调用方法和属性时,会依次从实例本身,构造函数原型,原型的原型上去查找,从而形成了原型链
new操作符具体做了什么
1、创建一个空对象
2、把空对象和构造函数通过原型链进行连接
3、把构造函数的this绑定在新的空对象身上
4、根据构造函数返回的类型判断,如果是值类型,则返回对象,如果是引用类型,就要返回这个引用类型
JS是如何实现继承的
原型链继承
让一个构造函数的原型是另一个类型的实例,那么这个构造函数new出来的实例就具有该实例的属性
优点:写法方便简洁,容易理解
缺点:对象实例共享所有继承的属性和方法,无法向父类构造函数传参
借用构造函数继承
在子类构造函数的内部调用父类型构造函数:使用apply()或call()方法将父对象的构造函数绑定在子对象上
优点:解决了原型链实现继承的不能传参的问题和父类的原型共享的问题
缺点:借用构造函数的缺点是方法都在构造函数中定义,因此无法实现函数复用。在父类的原型中定义的方法,对子类型而言也是不可见的,结果所有类型都只能使用构造函数模式
组合继承
原型链继承和借用构造函数继承的结合,使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。既通过在原型上定义方法实现了函数复用,又能够保证每个实例都有自己的属性
优点:解决了原型链和借用构造函数继承造成的影响
缺点:无论什么时候,都会调用两次父类构造函数,一次是在创建子类原型的时候,另一次是在子类构造函数内部
ES6、class实现继承
Class通过关键字extends实现继承,其实质是先创造出父类的this对象,然后用子类的构造函数修改this
子类的构造函数必须使用super()方法,且只要在调用了super()之后才能使用this,因为子类的this对象是继承父类的this对象,然后对其加工,而super方法表示的是父类的构造函数,用来新建父类的this对象
优点:语法简单易懂,操作更方便
缺点:并不是所有的浏览器都支持clss关键字
JS的设计原理是什么
JS引擎 => 运行上下文 => 调用栈 => 事件循环 => 回调
Js引擎:将js代码进行语法解析,编译成可执行的机器码,让电脑去执行,目前流行的是V8引擎
执行上下文:浏览器里面可以调用的一些api,比如说dom,window提供的api,事件循环和任务队列也可归为执行上下文
调用栈:是单线程去运行的,多线程会出现很多同步问题,数据不同步问题,主线程是用来做渲染,如果出现阻塞,导致浏览器卡死
事件循环:当调用栈空了以后,事件循环就会将循环放入调用栈中实现一个循环
回调:加入到事件队列里面等待调用栈调用,当事件循环监听到调用栈空了,就把回调函数拿出来放到调用栈里去执行
JS中关于this指向的问题
1、全局对象中的指向:指向的是window
2、全局作用域或者普通函数中的this:指向全局的window
3、this永远指向最后调用它的那个对象,不是在箭头函数的情况下
4、new关键词改变了this的指向
5、apply、call、bind:改变this的指向,不是箭头函数
6、箭头函数中的this:箭头函数本身没有this,看外层是否有函数,有就是函数的this,没有就是window
7、匿名函数中的this:永远指向window,匿名函数的执行环境具有全局性,因此this指向window
script标签里的async和defer有什么区别
当没有async和defer这两个属性时:浏览器会立刻加载并执行指定的脚本
有async:加载和渲染后面元素的过程将和script的加载和执行并行进行(异步)
有defer:加载和渲染后面元素的过程将和script的加载并行执行,运行事件要等所有元素解析完成后才会执行
不同点就是:async和元素渲染加载是并行的,H5新出的属性,defer是将脚本放在最后执行,是最早出现的属性
相同点就是异步进行加载
setTimeout最小执行时间
HTML5规定的内容,不同浏览器的时间也可能会不同;
setTimeout最小执行时间是4ms,setInterval最小执行时间是10ms;
ES5和ES6的区别
JS的组成部分:ECMAScript,DOM,BOM
ES5:ECMAScript5,2009年ECMAScript的第五次修订,ECMAScript2009
ES6:ECMAScript6,2015年ECMAScript的第五流4次修订,ECMAScript2015,是JS下一个版本标准
具体可以说一下ES6新特性
ES6的新特性有什么?
1、块级作用域(let,const)
特点:
不存在变量提升;存在暂时性死区;不能在同一个作用域内重复声明
2、定义类的语法糖(class)
3、基本数据类型啊(symbol)
4、解构赋值
从数组或者对象中取值,然后给变量赋值
5、给数组新增了API
6、新增了函数参数的默认值
7、给数组和对象新增了扩展运算符
8、新增了Promise
特点
解决了回调地狱的问题
自身有all,resolve,reject,race等方法
原型上有then,catch
把异步操作队列化
三种状态:pending(初始化状态)、fulfilled(操作成功),rejected(操作失败)
状态:pending->fulfilled;pending->rejected 一旦发生,状态就会凝固,不会再变
async、await
同步代码做异步的操作,两者必须搭配使用
Async表明函数内有异步操作,调用函数会返回promise
await是组成async的表达式,结果取决于他等待的内容,如果是promise那就是promise的结果,如果是普通函数就进行链式调用
await后的promise如果是reject状态,那么整个async就会中断,后面的代码就不执行了
9、新增了箭头函数
不能作为构造函数,不能使用new;
箭头函数没有原型
箭头函数没有arguments
箭头函数不能使用call、apply、bind改变this的指向
箭头函数的this指向的是外层第一个函数的this
10、新增了模块化(import、export)
11、新增了Map和Set数据结构
Set就是不重复、map的key的类型不受限制
12、新增了generator
call、apply、bind区别
共同点:改变this的指向
区别:call参数是列表,apply参数是数组,bind传参后不会立刻执行,会返回一个改变了this指向的函数,这个函数还可以传参,bind()()
用递归的时候有没有遇到什么问题?
递归就是函数内部调用自己。需要注意的是:写递归必须有退出条件return
如何实现一个深拷贝
深拷贝就是完全拷贝一份新的对象,在堆内存中开辟新的空间,拷贝的对象被修改后,原对象不会受影响。 主要针对的是引用数据类型
实现方法:
1、扩展运算符
缺点是只能深拷贝对象的第一层,有多层的时候,就是浅拷贝
2、JSON.parse(JSON.stringify())
不能拷贝到对象的内部函数
3、通过递归来实现
说一下事件循环
JS是一个单线程的脚本语言;
主线程、执行栈、任务队列、宏任务、微任务
主线程先执行同步任务,然后才去执行任务队列里的任务,如果在执行宏任务之前有微任务,就先执行微任务,全部执行完之后等待主线程的调用,调用完之后再去任务队列里面查看是否有异步任务,这样一个循环往复的过程就是事件循环
AJAX是什么?怎么实现的?
创建交互式网页应用的网页开发技术,在不重新加载整个网页的前提下,与服务器交换数据并更新部分内容
通过XMLHttpRequest对象向服务器发送异步请求,然后从服务器拿到数据,通过js操作DOM更新页面
创建一个XMLHttpRequest对象,简称:xmh
通过xmh对象里的open()方法和服务器建立连接
构建请求所需的数据,通过xmh里的send()方法发送给服务器
通过xmh对象的onreadystate change事件监听服务器和你的通信状态
接收并处理服务器响应的数据结果
把处理的数据更新到HTML页面上
get和post有什么区别
1、get是获取数据,post是提交数据
2、get传参是在url上,安全性比较差,post传参是放在body中
3、get请求刷新服务器或退回是没有影响的,post请求退回时会重新提交数据
4、get请求时会被缓存,post请求不会被缓存
5、get请求会保存在浏览器历史记录中,post不会
6、get请求只能进行url编码,post请求支持很多种
Promise的内部原理是什么,他的优缺点是什么
Promise对象,封装了一个异步操作,并且可以获取成功或者失败的结果
Promise主要是解决回调地域的问题,之前如果异步任务比较多,他们之间还存在相互依赖的关系,就只能使用回调函数处理,这样就容易形成回调地狱,可维护性差,代码的可读性也差
Promise三种状态:pending(初始化状态) fulfilled(成功状态) rejected(失败状态)
状态改变只有两种:状态:pending->fulfilled;pending->rejected 一旦发生,状态就会凝固,不会再变。首先我们无法取消promise,一旦创建,就会立即执行,无法终止,如果不设置回调,promise内部抛出的错误无法反馈到外面,若当前处于pending状态时,无法得知目前在哪个阶段
原理:构造一个promise实例,实例需要传递函数的参数,这个函数有两个形参,分别是函数类型,一个是resolve,一个是reject
Promise上还有then方法,这个方法是用来制动状态改变时的确定操作,resolve是执行第一个函数,reject是执行第二个函数
promise和async await的区别是什么?
相同点:
1、都是处理异步请求的方式
2、promise是ES6,async/await是ES7语法
3、async/await是基于promise实现的,他和promise都是非阻塞性的
不同点:
1、promise的返回对象用then、catch方法处理和捕获异常,并且书写方式是链式,容易造成代码重叠,不好维护。async/await是通过try catch来捕获异常的
2、async/await最大的优点就是让代码看起来和同步一样,只要遇到await就会立刻返回结果,然后再执行后面的操作,而promise.then()的方式返回,会出现请求还没有返回,就执行了后面的操作
浏览器的存储方式有哪些
1、cookies
H5标准前的本地存储方式
兼容性好,请求头自带cookie
存储量小,资源浪费,使用麻烦(封装)
2、localstorage
H5加入的以键值对标准的方式
操作方便,永久存储,兼容性好
保存的类型被限定,浏览器隐私模式下不可读取,不能被爬虫
3、sessionstorage
当前页面被关闭后就会立刻清理,会话级别的存储方式
4、indexedDB
H5标准的存储方式,他是以键值对进行存储,可以快速进行读取,适合WEB场景
token是存在sessionstorage里还是Localstorage里?
Token:验证身份的令牌,用户通过账号和密码登录以后,服务端把这些凭证通过加密等一系列操作后得到的字符串
1、存在Localstorage里,后期每次请求接口都需要把他当做一个字段传给后台
2、存在cookie里,会自动发送,缺点是不能跨域
存在Localstorage里,会被xss(跨脚本攻击)攻击,但是如果做好对应的措施,那么是利大于弊
存在cookie里,会被csrf攻击
token的登录流程
1、客户端用账号和密码登录
2、服务端收到账号和密码之后,需要去验证密码和账号
3、验证成功以后,就会签发一个token,给客户端发送过去
4、客户端拿到token以后存储到cookie或者localstorage里,
5、客户端每次向服务端发送请求都需要带上token
6、服务端收到请求,首先要先验证token,验证通过才会返回客户端请求的数据
精灵图和base64的区别是什么
精灵图:把多张小图整合到一张大图上面,利用定位的一些属性把小图显示在页面上,当访问页面时可以减少请求,提高加载速度
Base64:传输8Bit字节代码的编码方式,把原本的二进制形式转为64个字符的单位,最后组成字符串。 Base64是会和html css一起下载到浏览器中,减少请求,减少跨域问题,但是一些低版本不支持,若base64体积比原图片大,不利于css的加载
svg格式了解多少?
基于XML语法格式的图像格式,可缩放矢量图,其它图像是基于像素的,SVG是属于对图像形状的描述,本质是文本文件,体积小,并且不管放大多少倍都不会失真
1、SVG可直接插入页面中,成为DOM一部分,然后用JS或css进行操作
<SVG></SVG>
2、SVG可作为文件被引入
<img src=“pic.svg”>
3、SVG可以转为base64引入页面
说一下浏览器的缓存策略?
缓存策略:强缓存(本地缓存)、协商缓存(弱缓存)
强缓:不发起请求,直接使用缓存里的内容,浏览器把JS、CSS、Image等存到内存中,下次用户访问直接从内存中取,提高性能
协缓:需要像后台发送请求,通过判断来决定是否使用协商缓存,如果请求内容没有变化,则返回304,浏览器就用缓存里的内容
强缓存的触发
HTTP1.0:时间戳响应标头
HTTP1.1:Cache-control
协商缓存触发
HTTP1.0:请求头:if-modified-since 响应头:last-modifined
HTTP1.1:请求头:if-none-match 响应头:Etag
解释下什么是JSON
JSON是一种纯字符串形式的数据,它本身不提供任何方法,适合在网络中进行传输
JSON数据存储在.json中,也可以把json数据以字符串的形式保存在数据库、cookie中
什么时候使用呢?定义接口;序列化;生成token;配置文件pakage.json
防抖和节流
都是应对页面中频繁触发事件的优化方案
防抖:避免事件重复触发,不论频繁触发多少次,都以最后一次事件请求一次,再重新计算时间
使用场景:1、频繁和服务端交付2、输入框的自动保存事件
节流:把频繁触发的事件减少,每隔一段时间执行
使用场景:scroll
有没有做过无感登录
1、在响应中做拦截,判断token返回过期后,调用刷新token的接口
2、后端返回过期时间,前端判断token过期时间,调用刷新token的接口
3、写定时器,定时刷新token
最常用的第一个大致流程:登录成功后,保存token和refresh_token;在响应拦截中对401状态码引入刷新token的api,替换保存在本地的token,替换错误包里的token重新进行请求,如果refresh_token也过期了,就需要跳转到登录页重新登陆
大文件上传是怎么做的
分片上传、断点续传