1)、官方解释:
一个函数和对其周围状态(变量)(lexical environment,词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包(closure)。
闭包让你可以在一个内部函数中访问到其外部函数的作用域。
2)、通俗的来说:闭包是 函数的嵌套定义,当调用外部函数时,会产生一个闭包。这个闭包就是外部函数定义的局部变量和内部函数。
内部函数可以使用外部函数的局部变量
让外部函数的局部变量一直存在于内存中(局部变量的生命周期变长了)。
因为,闭包会让局部变量一直保持在内存中,所以,不要滥用闭包,以防止内存泄漏。
让数据私有化(同时使用setter和getter函数,可以保证数据的合法性)
防抖
节流
单例模式
柯里化(谨慎的说这一点)
…………………… 其实用的挺多。
扩展:通常,函数的作用域及其所有变量都会在函数执行结束后被销毁。但是,在创建了一个闭包以后,这个函数的作用域就会一直保存到闭包不存在为止。
javascript的事件循环(event loop)_javascript的事件循环(event loop)_jiang7701037的博客-csdn博客-CSDN博客
JS是单线程的,那么,它如何处理异步操作?
答:使用事件循环,执行过程如下:
所有同步任务都在主线程上执行,形成一个执行栈。
主线程之外,会存在一个任务队列,只要异步任务有了结果(如:setTimeout的等待时间到了),就在任务队列中放置一个事件(所以,也叫事件队列),进行排队(处于等待状态)。任务队列又分为宏任务队列和微任务队列。
先执行微任务队列里的所有任务,所有任务都执行完毕后,再执行宏任务队列里的任务
宏任务队里的任务执行完一个后,再清空微任务队列。再执行下一个宏任务队列的任务。
当执行栈中的所有同步任务执行完后,就会读取任务队列(事件队列)中的任务(事件)。即:任务队列中的任务就结束了等待状态,进入执行栈。
主线程不断重复第三步。直到任务队列和执行栈里的代码执行完毕,这就是事件循环。
补充:
宏任务一般包括: setTimeout,setInterval,I/O 操作(包括AJAX请求),即上面的示例中setTimeout是宏任务。
微任务一般包括:promise.then() 里的回调函数
let
/ const
箭头函数
函数参数默认值
模板字符串
解构赋值
对象解构
数组解构
...
运算符
对象简写形式
模块化语法 import
/ export
Set
/ Map
/ for ... of
定义类的class和类的继承:extends。
1、写法格式不同【可以不说这点,哈哈】
2、箭头函数不能作为构造函数使用
3、箭头函数不具有super
4、箭头函数中没有this和arguments
5、箭头函数不具有prototype原型对象
6、箭头函数的出现:一方面为了解决this指向问题,另一方面写法简单。
7、箭头函数使用的是词法分析,所以,this是词法作用域【这点看情况说】
相同点:都不会改变原数组,返回值都是数组,参数都是回调函数(数组的当前项,下标,数组本身)
不同点:
map返回值是一个新的数组,新数组中的元素为原始数组中的元素调用函数处理后的值,所以,新数组和原数组的元素个数一样。
filter 返回数组中满足提供的测试函数的所有元素的数组。
const arr = [5, 12, 8, 18, 35]; const result = arr.filter(item => item > 10); console.log(item);//[12,18,35]
相同点:
forEach和map都是循环遍历数组中的每一项。forEach() 和 map() 里面每一次执行匿名函数都支持3个参数:数组中的当前项item,当前项的索引index,原始数组input。匿名函数中的this都是指Window。只能遍历数组。
不同点:
forEach没有返回值,但map中要有返回值,返回处理后的所有新元素组成的数组。
1、readyState是什么意思:
readyState:是表示请求和响应过程中的状态(进行到了哪一步)。
0:未初始化,【XMLHttpRequest对象创建完毕】
1:初始化,【调用open完毕】
2:后端接收到请求,
3:后端正在处理
4:后端响应回来。
2、status是什么意思:
status:表示响应结果的状态描述,该状态一般都是三位的数字,常见的取值为:
200:表明该请求被成功地完成,所请求的资源发送到客户端。
301:本网页被永久性转移到另一个URL
404:可连接服务器,但服务器无法取得所请求的网页,请求资源不存在。
500:务器错误。
Promise是ES6提供的原生的类(构造函数), 用来传递异步操作的消息。它代表了某个未来才会知道结果的事件(通常是一个异步操作,如:ajax请求,定时器)
1)、对象的状态不受外界影响。
Promise 有三种状态:Pending(进行中)、Resolved(已完成,又称 Fulfilled)和 Rejected(已失败)。
2)、一旦状态改变,就不会再变
状态改变,只有两种可能:从 Pending 变为 Resolved 和从 Pending 变为 Rejected。
解决回调地狱的问题。
功能:把then方法的参数传给resolve和reject。 promise对象.then(resolve回调函数,reject回调函数);
当promise里的异步操作完毕后,会调用then方法的参数。
参数:
then方法的第一个参数是resolve
then方法的第二个参数是reject。
返回值:promise对象,所以,then调用完毕后,还可以继续调用then(即:链式调用)
扩展:
fn01().then(fn02).then(fn03): 1、看看第二个then。 • 如果fn02没有返回promise对象,那么第二个then就使用的是第一个then的promise。 • 如果fn02返回了promise对象,那么第二个then就使用的fn02返回的promise对象。
它和then的第二个参数一样,用来指定reject的回调,
功能: Promise.all() 可以并行执行多个异步操作(并发),并且在一个回调中处理所有的返回数据。返回的数据与传的参数数组的顺序是一样的。当所有的异步操作都成功才表示成功 。
参数:数组。数组里是若干个返回promise对象的函数(异步操作);
返回值:promise对象。promise对象的then方法的回调函数的参数是 所有promise对象的resolve的参数(数组形式)。
功能:也是并发,但是,与all不同之处时,当一个异步操作完成(resolve或reject)时,就调用方法了。即:多个异步操作,同时执行,谁快就用谁的结果,所以,结果不再是数组。
ES7新增的两个关键字(async和await),是彻底解决回调地狱。是promise的语法糖。把异步的回调变成了同步的写法。
async:异步
修饰函数后,函数的返回值会变成Promise对象。原函数的返回值会成为resolve的参数。async修饰函数后,表示函数里面有异步操作。
await:等待
1、await必须放在async修饰的函数里
2、await是修饰proimse对象的。await修饰后,会把promise对象的resolve的实参作为返回值。
3、await 修饰代码后,处于await所在行后面(而不是await右边)的代码会等到异步结束后执行。但不影响主线程的代码执行。
4、如果要拿到reject里参数,就使用try catch。
cookie,localStorage,sessionStorage都是在客户端保存数据的,存储数据的类型:都是字符串。
1、生命周期:
1)、cookie如果不设置有效期,那么就是临时存储(存储在内存中),是会话级别的,会话结束后,cookie也就失效了,如果设置了有效期,那么cookie存储在硬盘里,有效期到了,就自动消失了。
2)、localStorage的生命周期是永久的,关闭页面或浏览器之后localStorage中的数据也不会消失。localStorage除非主动删除数据,否则数据永远不会消失。
3)、sessionStorage仅在当前会话下有效。sessionStorage引入了一个“浏览器窗口”的概念,sessionStorage是在同源的窗口中始终存在的数据。只要这个浏览器窗口没有关闭,即使刷新页面或者进入同源另一个页面,数据依然存在。但是sessionStorage在关闭了浏览器窗口后就会被销毁。同时独立的打开同一个窗口同一个页面,sessionStorage也是不一样的。
可以简单的理解为:sessionStorage,没有设置有效期的cookie。
如果说把cookie的有效期设置为永远永远,永久,那么就是localStorage。 cookie没有设置有效期,那么就是sessionStorage
2、大小限制:cookie大小限制在4KB,非常小;localstorage和sessionStorage在5M
3、网络流量:cookie的数据每次都会发给服务器端,而localstorage和sessionStorage不会与服务器端通信,纯粹为了保存数据,所以,webstorage更加节约网络流量。
4、安全性:WebStorage不会随着HTTP header发送到服务器端,所以安全性相对于cookie来说比较高一些,不会担心截获。
5、使用方便性上:WebStorage提供了一些方法,数据操作比cookie方便;
setItem (key, value) —— 保存数据,以键值对的方式储存信息。 getItem (key) —— 获取数据,将键值传入,即可获取到对应的value值。 removeItem (key) —— 删除单个数据,根据键值移除对应的信息。 clear () —— 删除所有的数据 key (index) —— 获取某个索引的key
https的默认端口是443,而http的默认端口是80,且两者的连接方式不同;
http传输是明文的,而https是用ssl进行加密的,https的安全性更高;
https是需要申请证书的,而http不需要。
同源策略: 是浏览器的一种安全机制,限制JavaScript或Cookie只能访问同域名下的内容,否则,会出现跨域问题。
同源的定义: 同样的协议,同样的地址,同样的端口
解决跨域的办法:
1)、原生中有jsonp
2)、脚手架项目(webpack和vite)中有反向代理
3)、后端用cors方式,就没有前端啥事了。
1)、理解 定义:程序中已在堆中分配的内存,因为某种原因未释放或者无法释放的问题 简单理解: 无用的内存还在占用,得不到释放和归还,比较严重的时候,无用的内存还会增加,从而导致整个系统卡顿,甚至崩溃。
2)、内存的生命周期
1.分配期 分配所需要的内存,在js中,是自动分配的 2.使用期 使用分配的内存,就是读写变量或者对象的属性值 3.释放期 不需要时将该内存释放,js会自动释放(除了闭包和一些bug以外) 内存泄漏就是出现在这个时期,内存没有被释放导致的
3)、可能出现内存泄漏的原因
1.意外的全局变量 2.DOM元素清空时,还存在引用 3.闭包 4.遗忘的定时器
4)、如何优化内存泄漏?
全局变量先声明在使用 避免过多使用闭包。 注意清除定时器和事件监听器。
计算机内部存储数据使用2进制存储,两个数字进行的数学运算,首先是将这两个数字以2进制形式,存储在计算机内部,然后在计算机内部使用两个2进制数字进行计算,最后将计算结果的2进制数字转为10进制展示出来。
由于10进制的小数在转2进制的时候,规则是小数部分乘以2,判断是否得到一个整数,如果得到整数,转换完成;如果没有得到整数,则继续乘以2判断。所以,0.1和0.2在转换2进制的时候,其实是一个无限死循环,也就是一直乘以2没有得到整数的时候,但计算机内部对于无线死循环的数据,会根据一个标准保留52位。也就是说,计算机内部在存储0.1和0.2的时候,本来就不精准,两个不精准的小数在计算后,距离精准的结果是有一定误差的。
将小数乘以10的倍数,转为整数,然后计算,计算完成后,再缩小10的倍数,例如:
var result = ((0.1 * 10) + (0.2 * 10)) / 10 // result === 0.3
使用数字的toFixed方法,强制保留小数点后多少位,例:
var result = (0.1 + 0.2).toFixed(2) // result === 0.30
自定义数字运算方法,当需要进行数学运算的时候,不直接进行,调用自定义的方法进行,例:(加法封装)
function add(...args){ var num = args.find(item => { if(item != 0 && !item){ throw new Error("数学运算要使用数字") } }) var arr = args.map(item => { var index = (item+'').indexOf('.') if(index >= 0){ return (item+'').split('.')[1].length } }) arr = arr.filter(item => item) if(arr.length){ var max = Math.max(...arr) var data = args.map(item => item * Math.pow(10, max)) var data.reduce((a, b) => a + b) / Math.pow(10, max) }else{ var data = args return data.reduce((a, b) => a + b) } } // 调用使用: var num1 = add(0.1, 0.2) console.log(num1); // 0.3 var num2 = add(1, 2) console.log(num2); // 3 var num3 = add(1, 2.1) console.log(num3); // 3.1
我们都知道JS是一种单线程语言,即使是一些异步的事件也是在JS的主线程上运行的。如:setTimeout、ajax的异步请求,或者是dom元素的一些事件,都是在JS主线程执行的,这些操作并没有在浏览器中开辟新的线程去执行,而是当这些异步操作被操作时或者是被触发时才进入事件队列,然后在JS主线程中开始运行。
首先说一下浏览器的线程,浏览器中主要的线程包括,UI渲染线程,JS主线程,GUI事件触发线程,http请求线程。
JS作为脚本语言,它的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。(这里这些问题我们不做研究)
但是单线程的语言,有一个很致命的确定。如果说一个脚本语言在执行时,其中某一块的功能在执行时耗费了大量的时间,那么就会造成阻塞。这样的项目,用户体验是非常差的,所以这种现象在项目的开发过程中是不允许存在的。
其实JS为我们提供了一个Worker的类,它的作用就是为了解决这种阻塞的现象。当我们使用这个类的时候,它就会向浏览器申请一个新的线程。这个线程就用来单独执行一个js文件。
var worker = new Worker(js文件路径); 那么这个语句就会申请一个线程用来执行这个js文件。这样也就实现了js的多线程。
escape()函数,对字符串进行编码;
isNaN()函数,检查一个参数是否是非数字值;
Number()函数,把对象的值转换为数字;
String()函数,把对象的值转换为字符串;
encodeURI()函数,把字符串作为URI进行编码;
decodeURI()函数,解码某个编码的URL;
decodeURIComponent()函数,解码一个编码的URI组件;
encodeURIComponent()函数,把字符串编码为URI组件;
eval()函数,计算字符串,并执行其代码;
isFinite()函数,检查参数是否是无穷大;
parseFloat()函数,解析字符串,返回浮点数;
parseInt()函数,解析字符串,返回整数;
unescape()函数,对escape()编码的字符串进行解码
页面的重排和回流(提升移动端网页性能)_前端如何让主侧页面从移动端的重叠到网页版的并排-CSDN博客
一、重绘重排的概念: 重绘的意思是:重新绘制,如:颜色发生变化, 重排(回流)的意思是:重新排列,即布局会受影响,如:用js动态改变了元素的宽或高,就会影响其它元素的位置,这叫重新排列。
二、什么时候引起重绘,什么时候引起重排: 1、重排(回流):回流这一阶段主要是计算节点的位置和几何信息,那么当页面布局和几何信息发生变化的时候,就需要回流。比如以下情况:
页面一开始渲染的时候(这肯定避免不了) DOM树的结构变化:添加或删除可见的DOM元素 DOM元素的几何属性变化:如外边距、内边距、边框厚度、宽高、等几何属性) 内容发生变化,比如文本变化或图片被另一个不同尺寸的图片所替代。 浏览器的窗口尺寸变化(因为回流是根据视口的大小来计算元素的位置和大小的) 窗口属性的获取和尺寸改变:offsetTop、offsetLeft、 offsetWidth、offsetHeight、scrollTop、scrollLeft、scrollWidth、scrollHeight、 clientTop、clientLeft、clientWidth、clientHeight、getComputedStyle() (currentStyle in IE) Display:的变化。 2、重绘
·DOM元素的字体颜色、改变visibility、outline、背景色。重绘不会带来DOM元素的重新计算,所以重绘并不一定伴随重排(回流),但是重排一定会引起浏览器的重绘
三、问题: 重绘,重排太过频繁,就会影响网页的执行性能。亲,你想想:你的页面本来一次可以重排好,你得多重排一次,那肯定是影响性能的。重绘一次就可以,你非得多重绘继承,那肯定也是影响性能的。
跟生活中一样。
重绘:你不停地擦掉重画,擦掉重画,肯定不如一次画到位好
重排:你总是重复性的把某个物体不停地挪动。跟家里的家具要换位置的道理一样。你如果想不来,今晚回去思考一下:假定你要把家里的家具重新布局(从A布局变成B布局),你在家具搬动的过程中,可以出几套搬动方案。看看哪一种搬动方案是挪动家具次数最少的,那么这种方案就是重排的最优方案。
四、浏览器的性能优化方案 浏览器也是很聪明的,由于每次重排都会造成额外的计算消耗,因此大多数浏览器都会通过队列化修改并批量执行来优化重排过程。浏览器会将修改操作放入到队列里,直到过了一段时间或者操作达到了一个阈值,才清空队列。但是!当你获取布局信息的操作的时候,会强制队列刷新,比如当你访问以下属性或者使用以下方法:
offsetTop、offsetLeft、offsetWidth、offsetHeight
scrollTop、scrollLeft、scrollWidth、scrollHeight
clientTop、clientLeft、clientWidth、clientHeight
getComputedStyle()
getBoundingClientRect()
以上属性和方法都需要返回最新的布局信息,因此浏览器不得不清空队列,触发回流重绘来返回正确的值。这也是为什么在获取这些值时会引起重排(回流)、重绘的原因,因此,我们在修改样式的时候,最好避免使用上面列出的属性,他们都会刷新渲染队列。如果要使用它们,最好将值先保存起来。
五、如何解决:
1、分离读和写的操作(避免触发同步布局事件):
let ulDom = document.getElementById(“box”);
var curLeft=ulDom .offsetLeft;
var curTop=ulDom .offsetTop;
ulDom .style.left=curLeft+1+'px';
ulDom .style.top=curTop+1+'px';
而不要这样写:
let ulDom = document.getElementById(“box”);
var curLeft=ulDom .offsetLeft;
ulDom .style.left=curLeft+1+'px';
var curTop=ulDom .offsetTop;
ulDom .style.top=curTop+1+'px';
因为,获取offsetLeft和offsetTop会导致浏览器强制清空队列,进行强制同步布局。
2、样式集中改变,而不要一个一个的改变(减少重绘重排)
如:let ulDom = document.getElementById(“box”);
ulDom.style.left = “100px”; ulDom.style.top = “200px”;
最好改成如下(cssText):
let ulDom = document.getElementById(“box”); ulDom.style.cssText = ‘left :100px;top:200px;’ 或者使用class名也可以
ulDom.className = “boxcls”;
3、批量修改DOM
1)、如果可以的话,在重排时,可以使用absolute脱离文档流,这样,元素的尺寸改变时,就不会影响其它元素了。先让元素absolute。然后给元素中放入若干个dom,再把元素的absolute去掉;
如果可以的话,使用display:none(脱离文档流),等元素的样式属性改变完毕后,再让元素显示。
2)、使用createDocumentFragment或拼接html字符串的方式进行DOM的增加
http的状态码一般都是三位的数组。
1、1开头的,该类型状态码表示接收到请求并且继续处理
100:客户端必须继续发出请求。 101:客户端要求服务器根据请求转换HTTP协议版本。
2、2开头的,该类型状态码表示动作被成功接收、理解和接受。
200,表明该请求被成功地完成,所请求的资源发送到客户端。 201,提示知道新文件的URL。 202,接受并处理,但处理未完成。 203,返回信息不确定或不完整。 204,收到请求,但返回信息为空. 205,服务器完成了请求,用户必须复位当前已经浏览过的文件。 206,服务器已经完成了部分用户的GET请求。
3、3开头的,该类型状态码表示为了完成指定的动作,必须接受进一步处理。
300,请求的资源可在多处获得。 301,本网页被永久性转移到另一个URL。 302,请求的网页被重定向到新的地址。 303,建议用户访问其他URL或访问方式。 304,自从上次请求后,请求的网页未修改过。 305,请求的资源必须从服务器指定的地址获得。 306,前一版本HTTP中使用的代码,现已不再使用。 307,声明请求的资源临时性删除。
4、4开头的,该类型状态码表示请求包含错误语法或不能正确执行。
400,客户端请求有语法错误(如:请求方式不对,或者请求方式对应的参数不对) 401,请求未经授权。 402,保留有效ChargeTo头响应。 403,禁止访问,服务器收到请求,但拒绝提供服务。 404,可连接服务器,但服务器无法取得所请求的网页,请求资源不存在。 405,用户在Request-Line字段定义的方法不被允许。 406,根据用户发送的Accept,请求资源不可访问。 407,类似401,用户必须首先在代理服务器上取得授权。 408,客户端没有在用户指定的时间内完成请求。 409,对当前资源状态,请求不能完成。 410,服务器上不再有此资源。 411,服务器拒绝用户定义的Content-Length属性请求。 412,一个或多个请求头字段在当前请求中错误。 413,请求的资源大于服务器允许的大小。 414,请求的资源URL长于服务器允许的长度。 415,请求资源不支持请求项目格式。 416,请求中包含Range请求头字段,在当前请求资源范围内没有range指示值。 417,服务器不满足请求Expect头字段指定的期望值。
5、5开头的,该类型状态码表示服务器或网关错误。
500,服务器错误。 501,服务器不支持请求的功能。 502,网关错误。 503,无法获得服务。 504,网关超时。 505,不支持的http版本。