自己整理的八股文--- JS篇

550 阅读17分钟

自己整理的八股文,不足之处还请指教

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也过期了,就需要跳转到登录页重新登陆

大文件上传是怎么做的

分片上传、断点续传