前端面试题汇总 ~ 持续更新中

225 阅读28分钟

js部分面试题

js数据类型

基本数据类型

es5的五种:null,undefined,Boolean,Number,String,

es6新增: Symbol(表示独一无二) Biglint (表示任意大的整数)

引用数据类型:Object 包含Object Array, function,Date,RegExp

null和undefined的区别:在if语句中null和undefined 都会转换为false 两者用相等运算符比价也是相等 首先null和undefined 都是基本数据类型,这两个基本数据类型分别只有一个值就是他们自身

不同:undefined代表了未定义,null代表的含义是空对象

数据类型存储已经堆栈内存是什么?

基本数据类型:直接存储在栈内存中,占据空间小,大小固定,属于被频繁使用的数据。指的是保存在栈内存中的简单数据段;number string 布尔

引用数据类型:同时存储在栈内存与堆内存中,占据空间大,大小不固定。

引用数据:类型将指针存在栈中,将值存在堆中。 当我们把对象值赋值给另外一个变量时,复制的是对象的指针,指向同一块内存地址,意思是,变量中保存的实际上只是一个指针,这个指针指向内存堆中实际的值,数组 对象

forEach for in for of****三者区别

forEach更多的用来遍历数组         

for in 一般常用来遍历对象或json

for of数组对象都可以遍历,遍历对象需要通过和Object.keys()

for in循环出的是key,for of循环出的是value

浅拷贝与深拷贝
  • 浅拷贝是创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址 ,所以如果其中一个对象改变了这个地址,就会影响到另一个对象

  • 深拷贝是将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,且修改新对象不会影响原对象

堆(heap)和栈(stack)有什么区别存储机制

栈: 是一种连续储存的数据结构,具有先进后出后进先出的性质。

通常的操作有入栈(压栈),出栈和栈顶元素。想要读取栈中的某个元素,就是将其之间的所有元素出栈才能完成。

堆: 是一种非连续的树形储存数据结构,具有队列优先,先进先出; 每个节点有一个值,整棵树是经过排序的。特点是根结点的值最小(或最大),且根结点的两个子树也是一个堆。常用来实现优先队列,存取随意。

数据类型相比较objected .is ==和===

=== 属于严格判断,直接判断两者类型是否相同,如果两边的类型不一致时,不会做强制类型准换,不同则返回false如果相同再比较大小,不会进行任何隐式转换对于引用类型来说,比较的都是引用内存地址,所以===这种方式的比较,除非两者存储的内存地址相同才相等,反之false

== 二等表示值相等。判断操作符两边对象或值是否相等类型可以不同,如果两边的类型不一致,则会进行强制类型转化后再进行比较,

typeof null 的结果是什么,为什么?

typeof null 的结果是Object。

在 JavaScript 第一个版本中,所有值都存储在 32 位的单元中,每个单元包含一个小的 类型标签(1-3 bits)  以及当前要存储值的真实数据。类型标签存储在每个单元的低位中,共有五种数据类型:object,int,double,string,boolean

什么是事件?

事件捕获就是:网景公司提出的事件流叫事件捕获流,由外往内,从事件发生的顶点开始,逐级往下查找,一直到目标元素。

事件冒泡:IE提出的事件流叫做事件冒泡就是由内往外,从具体的目标节点元素触发,逐级向上传递,直到根节点。

事件委托, 又名事件代理。事件委托就是利用事件冒泡,就是把子元素的事件都绑定到父元素上。如果子元素阻止了事件冒泡,那么委托也就没法实现了

阻止事件冒泡

Javascript 的作用域和作用域链

作用域:  作用域是定义变量的区域,它有一套访问变量的规则,这套规则来管理浏览器引擎如何在当前作用域以及嵌套的作用域中根据变量(标识符)进行变量查找。简单说:函数内部局部作用域,函数外面全局作用域。

作用域就是一个变量可以使用的范围,主要分为全局作用域和函数作用域

全局作用域就是Js中最外层的作用域,在哪里都可以访问

函数作用域是js通过函数创建的一个独立作用域,只能在函数内部访问,函数可以嵌套,所以作用域也可以嵌套

Es6中新增了块级作用域(由大括号包裹,比如:if(){},for(){}等)

防抖节流

防抖:所谓防抖,就是指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。

节流:所谓节流,就是指连续触发事件但是在 n 秒中只执行一次函数。两种方式可以实现,分别是时间戳版和定时器版。

什么是深拷贝,浅拷贝,浅拷贝 赋值的区别,如何实现

深拷贝和浅拷贝是针对复杂数据类型来说的,浅拷贝只拷贝一层,而深拷贝是层层拷贝。

1.浅拷贝:

将原对象或原数组的引用直接赋给新对象,新数组,新对象只是对原对象的一个引用,而不复制对象本身,新旧对象还是共享同一块内存

如果属性是一个基本数据类型,拷贝就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址,

2.深拷贝:

创建一个新的对象和数组,将原对象的各项属性的“值”(数组的所有元素)拷贝过来,是“值”而不是“引用”

深拷贝就是把一个对象,从内存中完整的拷贝出来,从堆内存中开辟了新区域,用来存新对象,并且修改新对象不会影响原对象

3、赋值:

当我们把一个对象赋值给一个新的变量时,赋的是该对象在栈中的内存地址,而不是堆中的数据。也就是两个对象

数组的方法

sort( ),splice( ),pop( ),push( ),unshift( ),shift( ),reverse( ),concat( ),slice( ),join( ),toString( ),toLocaleString( ),forEach( ),map( ),filter( ),every( ),some( ),reduce( ),isArray(),indexOf,lastIndexOf,Array.of(),Array.from(),

字符串的方法

chartAt( ),concat( ),indexOf( ),lastIndexOf,split( ),substr( ),substring( ):,toLowerCase( ),toUpperCase( ),valueOf( ),includes(),slice( ),search(),toString(), replace(),

  • 函数声明与函数表达式的区别 函数声明会将那个函数提升到最前面(即使你写代码的时候在代码块最后才写这个函数),成为全局函数。

函数声明要指定函数名,而函数表达式不用,可以用作匿名函数。

  • 函数调用的几种方式 1.直接调用 函数名加上括号 ()

2.函数表达式 变量名()

闭包

1、闭包的概念就是:只有权利访问另一个函数作用域中的变量,一般就是函数包裹着函数。

3、闭包可以重用一个变量,且保证这个变量不会被污染的一种机制。这些变量的值始终保持在内存中,不会被垃圾回收机制处理

4、闭包的缺点:由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。

5、为什么要用闭包:使用场景 : 防抖、节流、函数套函数避免全局污染 闭包原理 函数执行分成两个阶段(预编译阶段和执行阶段)。 ​ 1.在预编译阶段,如果发现内部函数使用了外部函数的变量,则会在内存中创建一个“闭包”对象并保存对应变量值, 如果已存在“闭包”,则只需要增加对应属性值即可。 2.执行完后,函数执行上下文会被销毁,函数对“闭包”对象的引用也会被销毁,但其内部函数还持用该“闭包”的引用, 所以内部函数可以继续使用“外部函数”中的变量 ​ 利用了函数作用域链的特性,一个函数内部定义的函数会将包含外部函数的活动对象添加到它的作用域链中,函数执行完毕,其执行作用域链销毁, 但因内部函数的作用域链仍然在引用这个活动对象,所以其活动对象不会被销毁,直到内部函数被烧毁后才被销毁。

函数柯里化

把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术

我的理解就是将一个接受多个参数的函数,转化为接收一个参数,并且不改变输出结果的一种办法。我觉得这就是js的柯里化函数

垃圾回收机制和内存机制

垃圾回收

浏览器的js具有自动垃圾回收机制,垃圾回收机制也就是自动内存管理机制,垃圾收集器会定期的找出那些不在继续使用的变量,然后释放内存。但是这个过程不是实时的,因为GC开销比较大并且时停止响应其他操作,所以垃圾回收器会按照固定的时间间隔周期性的执行。

内存泄露

如果 那些不再使用的变量,它们所占用的内存 不去清除的话就会造成内存泄漏

内存泄露其实就是我们的程序中已经动态分配的堆内存,由于某些原因没有得到释放,造成系统内存的浪费导致程序运行速度减慢甚至系统崩溃等严重后果。

比如说:

1、闭包:在闭包中引入闭包外部的变量时,当闭包结束时此对象无法被垃圾回收(GC)。

2、DOM:当原有的DOM被移除时,子结点引用没有被移除则无法回收

3、Times计时器泄露

作用域

1、作用域

作用域就是一个变量可以使用的范围,主要分为全局作用域和函数作用域

全局作用域就是Js中最外层的作用域

函数作用域是js通过函数创建的一个独立作用域,函数可以嵌套,所以作用域也可以嵌套

Es6中新增了块级作用域(由大括号包裹,比如:if(){},for(){}等)

2、自由变量

当前作用域外的变量都是自由变量,一个变量在当前作用域没有定义,但是被使用了,就会向上级作用域,一层一层依次查找,直至找到为止,如果全局作用域都没有找到这个变量就会报错。这个自由变量查找的过程就是作用域链。

3、变量提升

每个var声明的变量,function声明的函数存在变量提升。let const不存在变量提升

在js中声明之前未定义,会在js的最上方会形成一个预解析池,用来存储声明了但没有先定义的变量名

4、作用域链:

作用域链的作用是保证对执行环境有权访问的所有变量和函数的有序访问,通过作用域链,我们可以访问到外层环境的变量和 函数 , 简单来说:内部函数访问外部函数的变量这种链式查找的机制被称为作用域链

js事件循环

js代码执行过程中会有很多任务,这些任务总的分成两类:

  • 同步任务
  • 异步任务

需要注意的是除了同步任务和异步任务,任务还可以更加细分为宏任务和微任务,js引擎会优先执行微任务

微任务包括了 promise 的回调、node 中的 process.nextTick 、对 Dom 变化监听的 MutationObserver。 ​ 宏任务包括了 script 脚本的执行、setTimeout ,setInterval ,setImmediate 一类的定时事件,还有如 I/O 操作、UI 渲 染等。

服务端渲染

解释:服务端渲染的模式下,当用户第一次请求页面时,由服务器把需要的组件或页面渲染成 HTML 字符串,然后把它返回给客户端。客户端拿到手的,是可以直接渲染然后呈现给用户的 HTML 内容,不需要为了生成 DOM 内容自己再去跑一遍 JS 代码。使用服务端渲染的网站,可以说是“所见即所得”,页面上呈现的内容,我们在 html 源文件里也能找到。有了服务端渲染,当请求用户页面时,返回的body里已经有了首屏的html结构,之后结合css显示出来。

优点: ①首屏渲染快(关键性问题):相比于加载单页应用,我只需要加载当前页面的内容,而不需要像 React 或者 Vue 一样加载全部的 js 文件; ②SEO(搜索引擎)优化:不同爬虫工作原理类似,只会爬取源码,不会执行网站的任何脚本 ③可以生成缓存片段、节能; ​ 缺点:用户体验较差,不容易维护、通常前端改了部分html或者css,后端也需要改; ​ 使用场景:vue全家桶或者react全家桶,都是推荐通过服务端渲染来实现路由的。

同步和异步的区别?各举一个Js中同步和异步的案例?

同步:上一件事情没有完成,继续处理上一件事情,只有上一件事情完成了,才会做下一件事情

异步: 规划要做一件事情,如果是异步事情,不是当前立马去执行这件事情,需要等一定的时间,这样的话,我们不会等着他执行,而是继续执行下面的操作

对于写程序,同步往往会阻塞,没有数据过来,我就等着,异步则不会阻塞,没数据来我干别的事,有数据来去处理这些数据。

同步案例:for循环语句,alert(),console.log()等 js大部分都是同步编程

异步案例:所有定时器,ajax异步请求,所有的事件绑定都是异步;

cookies,sessionStorage 和 localStorage 的区别?

cookie:一个大小不超过4K的小型文本数据,一般由服务器生成,可以设置失效时间;若没有设置时间,关闭浏览器cookie失效,若设置了 时间,cookie就会存放在硬盘里,过期才失效,每次http请求,header都携带cookie

localStorage:5M或者更大,永久有效,窗口或者浏览器关闭也会一直保存,除非手动永久清除或者js代码清除,因此用作持久数据,不参与和服务器的通信

sessionStorage关闭页面或浏览器后被清除。存 放数据大小为一般为 5MB,而且它仅在客户端(即浏览器)中保存,不参与和服务器的通信。

js面试题的扩展

什么是函数式编程? 命令式编程?声明式编程?

声明式编程:专注于”做什么”而不是”如何去做”。在更高层面写代码,更关心的是目标,而不是底层算法实现的过程。 如:css, 正则表达式,sql 语句,html, xml…

命令式编程(过程式编程) : 专注于”如何去做”,这样不管”做什么”,都会按照你的命令去做。解决某一问题的具体算法实现。

如: for()

函数式编程:把运算过程尽量写成一系列嵌套的函数调用。

如 : forEach()

javascript原型与原型链

  • 原型:每一个 JavaScript 对象(null 除外)在创建的时候就会与之关联另一个对象,这个对象就是我们所说的原型,每一个对象都会从原型"继承"属性,其实就是 prototype 对象。
  • 原型链:由相互关联的原型组成的链状结构就是原型链。

每个函数都有一个prototype属性,被称为显示原型

每个实例对象都会有_ proto _属性,其被称为隐式原型

每一个实例对象的隐式原型_ proto _属性指向自身构造函数的显式原型prototype

每个prototype原型都有一个constructor属性,指向它关联的构造函数。

原型链

获取对象属性时,如果对象本身没有这个属性,那就会去他的原型__proto__上去找,如果还查不到,就去找原型的原型,一直找到最 顶层(Object.prototype)为止。Object.prototype对象也有proto属性值为null。链式查找机制叫原型链。

javascript 创建对象的几种方式

1、我们一般使用字面量的形式直接创建对象

(1)第一种是工厂模式,工厂模式的主要工作原理是用函数来封装创建对象的细节,从而通过调用函数来达到复用的目的。

(2)第二种是构造函数模式。js 中每一个函数都可以作为构造函数,只要一个函数是通过 new 来调用的,那么我们就可以把它称为构造函数。

(3)第三种模式是原型模式,因为每一个函数都有一个 prototype 属性,这个属性是一个对象,它包含了通过构造函数创建的所有实例都能共享的属性和方法。

(4)第四种模式是组合使用构造函数模式和原型模式,这是创建自定义类型的最常见方式。

(5)第五种模式是动态原型模式,这一种模式将原型方法赋值的创建过程移动到了构造函数的内部,通过对属性是否存在的判断,可以实现仅在第一次调用函数时对原型对象赋值一次的效果。

(6)第六种模式是寄生构造函数模式,这一种模式和工厂模式的实现基本相同,

es6部i分面试题

1,新增了块级作用域(let,const)

let 和 const

两个新的关键字用来声明变量

let用来声明一个块级变量,作用域只在块级内部,

const 用于声明常量,其值一旦被设定不能再被修改,否则会报错。

有几个不同于var的特性:

块级作用域

不能重复声明

不存在变量提升

但是存在变量暂时性锁死

2,提供了定义类的语法糖(class)

3,新增了一种基本数据类型(Symbol)

4,新增了变量的解构赋值

5,函数参数允许设置默认值,引入了 rest 参数,新增了箭头函数

6,数组新增了一些 API,如 isArray / from / of 方法;数组实例新增了entries(),keys() 和 values() 等方法

7,对象和数组新增了扩展运算符

8,ES6 新增了模块化(import/export)

9,ES6 新增了 Set 和 Map 数据结构

10,ES6 原生提供 Proxy 构造函数,用来生成 Proxy 实例

11,ES6 新增了生成器(Generator)和遍历器(Iterator)

3、箭头函数

js中我们在调⽤函数的时候经常会遇到this作⽤域的问题,这个时候ES6给我们提箭头函数。

1、 箭头函数是匿名函数不能作为构造函数,不能使用new

2、 箭头函数不绑定arguments,取而代之用rest参数…解决,

3、 this指向不同,箭头函数的this在定义的时候继承自外层第一个普通函数的this

4、 箭头函数通过call()或apply()调用一个函数,只传入了一个参数,对this并没有影响.

5、 箭头函数没有prototype(原型),所以箭头函数本身没有this

6、 箭头函数不能当做Generator函数,不能使用yield关键字、

7、 写法不同,箭头函数把function省略掉了 ()=> 也可以吧return 省略调 写法更简洁

8、箭头函数不能通过call()、apply()、bind()方法直接修改它的this指向

4、简述 let const var 的区别 以及使用场景

  • var let 是用来声明变量的,而const是声明常量的

var

1.var声明的变量存在变量提升,即变量可以在声明之前调用,值为undefined ​   
2、一个变量可多次声明,后面的声明会覆盖前面的声明 ​   
3、在函数中使用var声明变量的时候,该变量是局部的作用域只在函数内部,而如果在函数外部使用 var,该变量是全局的
  • let

1、不存在变量提升,let声明变量前,该变量不能使用。就是 let 声明存在暂时性死区 ​
2、let命令所在的代码块内有效,在块级作用域内有效,作用域只是在花括号里面 ​
3、let不允许在相同作用域中重复声明,注意是相同作用域,不同作用域有重复声明不会报错

  • const

1、const声明一个只读的常量,声明后,值就不能改变 ​
2、let和const在同一作用域不允许重复声明变量const声明一个只读的常量。一旦声明,常量的值就不能改变,但对于对象和数据这种 引用类型,内存地址不能修改,可以修改里面的值。 ​
3、let和const不存在变量提升,即它们所声明的变量一定要在声明后使用,否则报错 4、能用const的情况下尽量使用const,大多数情况使用let,避免使用var。 const > let > var const声明的好处,一让阅读代码的人知道该变量不可修改,二是防止在修改代码的过程中无意中修改了该变量导致报错,减少bug的产生

5、map和forEach的区别

相同点

都是循环遍历数组中的每一项 forEach和map方法里每次执行匿名函数都支持3个参数,参数分别是item(当前每一项)、index(索引值)、arr(原数组),需要用哪个的时候就写哪个 匿名函数中的this都是指向window 只能遍历数组

注意:forEach对于空数组是不会调用回调函数的

不同点

map方法返回一个新的数组,数组中的元素为原始数组调用函数处理后的值。(原数组进行处理之后对应的一个新的数组。) map()方法不会改变原始数组 map()方法不会对空数组进行检测 forEach()方法用于调用数组的每个元素,将元素传给回调函数.(没有return,返回值是undefined)

6、promise的解释

Promise是ES6引入的一个新的对象,他的主要作用是用来解决JS异步机制里

,回调机制产生的“回调地狱”。它并不是什么突破性的API,只是封装了异步回调形式,使得异步回调可以写的更加优雅,可读性更高,而且可以链式调用。

1、Promise 是异步编程的一种解决方案,主要用于异步计算,支持链式调用,可以解决回调地狱 的问题,自己身上有all、reject、resolve、race 等方法,原型上有then、catch等方法。

2、可以将异步操作队列化,按照期望的顺序执行,返回符合预期的结果,可以在对象之间传递和操作 promise,帮助我们处理队列

3、promise 有三个状态:pending[待定]初始状态,fulfilled[实现]操作成功,rejected[被否决]操作失败

4、Promise 对象状态改变:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了

5、如果不设置回调函数,Promise内部抛出的错误,不会反应到外部,但是写了then 和 catch ,会被then的第二个参数 或 catch所捕获

  • promise 的 then 为什么可以支持链式调用

promise 的then会返回一个新的 promise 对象,能保证 then 方 可以进行链式调用

6、async、await的原理

Async 和 await 是一种同步的写法,但还是异步的操作,两个必须配合一起使用

函数前面的async关键字,表明该函数内部有异步操作。调用该函数时,会立即返回一个Promise对象。

await 是个运算符,用于组成表达式,await 表达式的运算结果取决于它等的东西,如果是promise则会等待promaise 返回结果,接普通函数直接进行链式调用.

await 能够获取promise执行的结果 await必须和async一起使用才行,async配合await使用是一个阻塞的异步方法

如果await后面不是Promise对象, 就直接返回对应的值,只能在async函数中出现, 普通函数直接使用会报错

await语句后的Promise对象变成reject状态时,那么整个async函数会中断,后面的程序不会继续执行

7、解构赋值

ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构赋值

常见的几种方式有

1.默认值

2.交换变量

3.将剩余数组赋给一个变量

结构数组和对象字符串区别

对象的解构与数组类似,但有所不同。数组的元素是按次序排列的,变量的取值由它的位置决定;

而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。字符串也是可以解构赋值的。字符串被转换成了一个类似数组的对象.

我在项目中:就是从目标对象或数组中提取自己想要的变量。最常用的场景是:element-ui,vant-ui按需引入,请求接口返回数据,提取想要数据。

8、 for...in 迭代和 for...of 有什么区别

1、 推荐在循环对象属性的时候,使用 for...in,在遍历数组的时候的时候使用for...of。

2、 for in遍历的是数组的索引,而for of遍历的是数组元素值

3、for...of 不能循环普通的对象,需要通过和 Object.keys()搭配使用

4、for...in 遍历顺序以数字为先 无法遍历 symbol 属性 可以遍历到公有中可枚举的

5、从遍历对象的角度来说,for···in会遍历出来的为对象的key,但for···of会直接报错。

set和map数据结构有哪些常用的属性和方法?

set数据的特点是数据是唯一的

Set的不重复性

、谈谈你对模块化开发的理解?

我对模块的理解是,一个模块是实现一个特定功能的一组方法。在最开始的时候,js 只实现一些简单的功能,所以并没有模块的概念 ,但随着程序越来越复杂,代码的模块化开发变得越来越重要。

由于函数具有独立作用域的特点,最原始的写法是使用函数来作为模块,几个函数作为一个模块,但是这种方式容易造成全局变量的污 染,并且模块间没有联系。

后面提出了对象写法,通过将函数作为一个对象的方法来实现,这样解决了直接使用函数作为模块的一些缺点,但是这种办法会暴露所 有的所有的模块成员,外部代码可以修改内部属性的值。

现在最常用的是立即执行函数的写法,通过利用闭包来实现模块私有作用域的建立,同时不会对全局作用域造成污染。

2、 请描述一下你对webpack的理解?

Webpack Webpack 是一个项目打包工具

可以压缩代码和图片,把浏览器识别不了的代码转化为能识别的,可以启动一个热加载服务器

配置跨域、路径别名、打包分析、cdn映入、去掉console.log、单独打包第三方模块、ie兼容、eslint规范、图片压缩

5、前端有哪些页面优化方法?

  • 减少 HTTP请求数
  • 从设计实现层面简化页面
  • 合理设置 HTTP缓存
  • 资源合并与压缩
  • 合并 CSS图片,减少请求数的又一个好办法。
  • 将外部脚本置底(将脚本内容在页面信息内容加载后再加载)
  • 多图片网页使用图片懒加载。
  • 在js中尽量减少闭包的使用
  • 尽量合并css和js文件
  • 尽量使用字体图标或者SVG图标,来代替传统的PNG等格式的图片
  • 减少对DOM的操作
  • 在JS中避免“嵌套循环”和 “死循环”
  • 尽可能使用事件委托(事件代理)来处理事件绑定的操作
  • 浏览器缓存
  • 防抖、节流
  • 资源懒加载、预加载
  • 开启Nginx gzip压缩 三个方面来说明前端性能优化 一: webapck优化与开启gzip压缩 1.babel-loader用 include 或 exclude 来帮我们避免不必要的转译,不转译node_moudules中的js文件 其次在缓存当前转译的js文件,设置loader: 'babel-loader?cacheDirectory=true' 2.文件采用按需加载等等 3.具体的做法非常简单,只需要你在你的 request headers 中加上这么一句: accept-encoding:gzip 4.图片优化,采用svg图片或者字体图标 5.浏览器缓存机制,它又分为强缓存和协商缓存 二:本地存储——从 Cookie 到 Web Storage、IndexedDB 说明一下SessionStorage和localStorage还有cookie的区别和优缺点 三:代码优化 1.事件代理 2.事件的节流和防抖 3.页面的回流和重绘 4.EventLoop事件循环机制 5.代码优化等等

三次握手和四次挥手

三次握手:

第一次:建立连接时,客户端发送syn包到服务器,等待服务端确认

第二次:服务器收到syn包,必须确认客户的syn,同时也发送一个syn包,即syn+ACK包

第三次:客户端收到服务器的syn和ack包,向服务器发送确认包ack,发送完毕,客户端和服务端连接成功,完成三次握手

四次挥手:

第一次:浏览器发送完数据后,发送fin请求断开连接

第二次:服务器发送ack到客户端,确认客户端的断开请求

第三次:服务器请求断开fin的请求

第四次:客户端确认服务器的断开ack

能不能说一说浏览器的本地存储?各自优劣如何?

浏览器的本地存储主要分为Cookie、WebStorage和IndexDB, 其中WebStorage又可以分为localStorage和sessionStorage。

共同点: 都是保存在浏览器端、且同源的

不同点:

cookie数据始终在同源的http请求中携带(即使不需要),即cookie在浏览器和服务器间来回传递。cookie数据还有路径(path)的概念,可以限制cookie只属于某个路径下sessionStorage和localStorage不会自动把数据发送给服务器,仅在本地保存。

存储大小限制也不同,

cookie数据不能超过4K,sessionStorage和localStorage可以达到5M

sessionStorage:仅在当前浏览器窗口关闭之前有效;

localStorage:始终有效,窗口或浏览器关闭也一直保存,本地存储,因此用作持久数据;

cookie:只在设置的cookie过期时间之前有效,即使窗口关闭或浏览器关闭

作用域不同

sessionStorage:不在不同的浏览器窗口中共享,即使是同一个页面;

localstorage:在所有同源窗口中都是共享的;也就是说只要浏览器不关闭,数据仍然存在

cookie: 也是在所有同源窗口中都是共享的.也就是说只要浏览器不关闭,数据仍然存在