JavaScript知识点集合

369 阅读1小时+

目录

  1. HTTP相关知识点
  2. 网站攻击
  3. 垃圾回收机制
  4. V8垃圾回收机制
  5. JavaScript继承的6种方式
  6. 防抖和节流
  7. 柯里化
  8. new运算符
  9. 输入URL到页面显示的过程
  10. cookie和session的区别
  11. 闭包
  12. 执行上下文
  13. Ajax
  14. Promise、Promise.all、promise A+的规范、手写Promise
  15. 数组方法的总结
  16. ES6、ESNext
  17. 拷贝
  18. 箭头函数
  19. 跨域
  20. 微前端
  21. webSocket、socket、HTTP的区别
  22. JavaScript的23种设计模式,5大设计原则
  23. 前端工程化
  24. Web Worker
  25. Babel原理与实现
  26. webSocket
  27. 时间复杂度、空间复杂度
  28. 深度优先遍历、广度优先遍历
  29. call/apply的区别
  30. BOM(浏览器对象模型)
  31. eval()
  32. 算法:排序
  33. 算法:去重
  34. 斐波那契数列(递归算法)爬楼梯
  35. 函数式编程
  36. 事件轮询Event Loop *
  37. Object方法总结
  38. 同源策略
  39. 回流和重绘 *
  40. 模块化开发,CommonJs/AMD/CMD *
  41. 缓存
  42. 优化:前端优化、首屏优化 *
  43. npm模块安装机制
  44. this指向
  45. 前端日志
  46. JavaScript二进制、八进制、十六进制
  47. toString()的用法

1、HTTP相关知识点。

定义:HTTP(超文本传输协议)是一个请求-响应协议。无状态,无连接,

http处理事物过程:建立连接-客户提出请求-服务器响应请求,返回资源-关闭连接。

请求方法:9种
    http1.0只有3种请求方法:GET、POST、HEAD(同GET,没有响应体)。
    http1.1增加6种请求方法:OPTIONS(测试服务器性能决定执行方法)、PUT(替换目标资源)、DELETE、TRACE(报文追踪,用于测试)、CONNECT(代理)、PATCH(PUT补充)。

HTTP报文:2种
    请求报文:
        1.请求行(request line):请求类型(GET/POST)、访问的资源(URL)、HTTP版本(HTTP1.1)
        2.请求头(header):
            Accept:浏览器可接收的数据格式,application/json
            Accept-Enconding:浏览器可接收的压缩算法,gzip
            Accept-Language:浏览器可接收的语言,zh-CN
            Accept-Token:唯一标识
            Cookie:唯一标识
            Connection:keep-live,HTTP1.1的一次TCP连接重复使用
            Host:请求的域名,虚拟机
            Content-Type:请求发送数据的格式
            User-Agent:浏览器信息
         3.空行:请求头和请求主体之间的空行是必须的。
         4.请求主体(request body)
    响应报文:
        1.响应行(Response line):HTTP版本(HTTP1.1)、状态码、状态码描述
        2.响应头(Response header):
            Accept-Control-Allow-Origin:*表示可以解决跨域
            Content-Type:返回数据的格式
            Set-Cookie:服务端修改的Cookie
            Cache-Control:
            Expires:
        3.空行
        4.响应体(Response body):返回的xml、json、Html
    
    
一个HTTP的请求过程:七步
    1.建立TCP连接,TCP的三次握手
    2.web浏览器向web服务器发送请求命令
    3.web浏览器发送请求头信息
    4.web服务器应答
    5.web服务器发送应答头信息
    6.web服务器向浏览器发送数据
    7.关闭TCP连接,TCP的四次挥手
    
  常用状态码:
    
  1xx(信息类):表示接收到请求并且继续处理
  2xx(响应成功):表示动作被成功接收、理解和接受
  3xx(重定向类):为了完成指定的动作,必须接受进一步处理
  4xx(客户端错误类):请求包含错误语法或不能正确执行
  5xx(服务端错误类):服务器不能正确执行一个正确的请求
  
  100  Continue   继续,一般在发送post请求时,已发送了http header之后服务端将返回此信息,表示确认,之后发送具体参数信息
  200  OK         正常返回信息
  201  Created    请求成功并且服务器创建了新的资源
  202  Accepted   服务器已接受请求,但尚未处理
  301  Moved Permanently  请求的网页已永久移动到新位置。
  302 Found       临时性重定向。
  303 See Other   临时性重定向,且总是使用 GET 请求新的 URI。
  304  Not Modified 自从上次请求后,请求的网页未修改过。

  400 Bad Request  服务器无法理解请求的格式,客户端不应当尝试再次使用相同的内容发起请求。
  401 Unauthorized 请求未授权。
  403 Forbidden   禁止访问。
  404 Not Found   找不到如何与 URI 相匹配的资源。

  500 Internal Server Error  最常见的服务器端错误。
  503 Service Unavailable 服务器端暂时无法处理请求(可能是过载或维护)。
  

全部HTTP状态码:常见的已加粗
    1xx:服务器接受,继续处理
    2xx:成功
    **200:成功,返回数据**
    201:已创建
    202:已接收
    203:成功,未授权
    204:成功,无内容,用于定期刷新
    205:成功,重置内容
    206:成功,带RangeGET请求,分批下载。发送HEAD请求获总文件大小,多线程下载
    3xx:重定向
    **301:永久移到新的url,重定向。=>308。(永久重定向,浏览器自动处理)**
    **302:临时移到新的url,可使用原url。=>307。(临时重定向,浏览器自动处理)**
    303:See Other 可在别url找到
    **304Not Modified 资源未修改,可利用缓存(使用浏览器缓存)**
    305User Proxy 通过Location头指定的代理服务器提取
    4xx:客户端错误
    400:Bad Request 请求参数报错
    401:Unauthorized 要求身份认证
    **403:Forbidden 服务器拒绝请求(没有权限)**
    **404Not Found 资源不存在(资源未找到)**
    405Method Not Allowed 请求行中的请求方法不能用于请求响应的资源
    406Not Acceptable 请求的内容不满足请求头中的条件,无法生成响应体
    5xx:服务器错误
    **500:Internal Server Error 请求未完成,服务器报错**
    **502:Bad Gateway 请求未完成,服务器收到一个无效响应**
    **503:Service Unavailable 请求未完成,服务器维护或者重载**
    **504:Gateway Timeout 网关超时**
    505:HTTP Version Not Supported 服务器不支持请求中指定的HTTP版本

HTTPS = HTTP + SSL 
https是在明文传输的http协议的基础上设置了SSl协议对http协议传输的数据进行加密处理
HTTPS的工作原理:
    1.服务器接到客户端的请求,服务器和SSL建立连接,将网站的证书(包含公钥)返回给客户端
    2.客户端和服务器端协商SSL连接的安全等级,即加密等级
    3.协商一致后,建立会话秘钥,网站通过公钥加密会话,传输给网站
    4.服务器通过公钥解密会话
    5.服务器通过会话秘钥加密与客户端之间的通信
    
HTTP和HTTPS的区别:
    1、HTTP是明文传输,HTTPS是加密传输
    2、HTTPS协议需要CA证书,费用较高
    3、HTTP默认端口80,HTTPS默认端口443

HTTP1.0、HTTP1.1、HTTP2.0的优缺点:
HTTP1.0: 正式作为标准,内容传输格式不限制,TCP三次握手,TCP慢启动(起初限制最大速度,随着时间速度越快),线头阻塞(大文件导致后续请求阻塞)
HTTP1.11. 持久链接:Connection:keep-alive
    2. 缓存策略:增加了更多的缓存控制策略 Cache-Control/Etag/If-none-Match                    
    3. host域(同一台服务器下不同的网站,虚拟主机的基础)
    4. 管道机制(pipelining,同一个TCP连接中,客户端可发送多个请求)
    5. 状态管理:增加了24个错误状态响应码,如409(conflict)/410(Gone)
    6. 断点续传:引入Range头域,返回206,只请求资源的某个部分。实例运用:分批下载

HTTP2.01.多路复用(单一的连接,多重的请求-响应消息)允许通过单一的HTTP/2连接发送多重的请求-响应响应,改善了HTTP1.1中同一时间、统一域名的请求有数量限制,PC端是6-8,移动端是4-6个,超过限制会被阻塞。
    2.服务器推送、
    3.头信息压缩(hpack算法),减少了传输体积
    4.二进制协议(分割更小的帧,二进制编码,封装到对应的frame, 应用层和传输层)http1.1是字符串传输

HTTP通信传输原理:
    客户端输入URL回车,DNS解析域名得到服务器的IP地址,服务器在80端口监听客户端的请求,端口通过TCP/IP协议建立连接。所以HTTP属于TCP/IP模型中的运用层协议。

传输层通过TCP的三次握手建立连接,四次挥手释放连接。

TCP的三次握手:
    1.Client发送SYN(seq=j)包到服务器,Client处于SYN_SENT状态,等待服务器响应。SYN:同步序列编号
    2.服务器发送ACK(j+1)以确认收到Client的SYN,同时发送自己的SYN(seq=k),即发送SYN+ACK,服务器进入SYN——RECV状态
    3.Client发送确认包ACK(seq=k+1)以确认收到服务器的SYN和ACK包,发送完毕后,Client和服务器进入Established(TCP连接成功状态)。

TCP三次握手,是为了避免无效连接造成的资源浪费,服务器处于等待状态。

TCP基于全双工机制:可发送,可接受。所以Client、Server都必须进行单独关闭。
TCP四次挥手:
    1.Client发送FIN到服务器,客户端进入FIN_WAIT状态(Client说:我要断开了哈)
    2.服务器发送ACK(FIN+1)确认包到Client,服务器进入Close_Wait状态(Server说,收到,你断吧)
    3.服务器断开连接,并发送自己的FIN包到Client,服务器进入LAST_ACK状态(Server说,我也要断开了)
    4.客户端发送ACK(FIN+1)确认包到服务器,服务器进入CLOSED状态,完成四次挥手
    
 TCP的流量控制:滑动窗口
 TCP的拥塞控制:慢开始、拥塞避免、快重传、快恢复
    
 Get、Post的区别:
 Get:能被缓存、请求长度受浏览器URL的限制、会被历史保存记录,安全性差
 post:无缓存、安全、编码类型多(二进制/ASCII)、大数据量
 
 
 HTTP缓存策略:强缓存和协商缓存
 强缓存:Cache-Control/Expires,Cache-Control是HTTP1.1,Expires是HTTP1.0时代的产物。
 浏览器判断缓存是否过期,未过期,直接使用缓存。
 Cache-Control的max-age优先级高于Expries。
 Cache-Control是一个通用消息头字段被用于HTTP的请求和响应中,这个缓存指令是单向的,即在请求中设置的指令不一定包含在响应中。常见的取值有
    1.private(默认值)只能在浏览器中缓存,只有第一次访问时才访问服务器。若有max-age,缓存期间不访问服务器。
    2.public 可以被浏览器、服务器、代理服务器等缓存区缓存。
    3.max-age 相对于请求时间的最大缓存时间,秒为单位
    4.s-maxage 共享缓存,秒为单位
    5.no-cache 不能缓存,每次请求都重新访问服务器,若有max-age,缓存期间不访问服务器。
    6.must-revalidate 同no-cache,更严格,但实际中访问频率快就失效了。
 
    1. 打开新窗口:private、no-cache、must-revalidate都会重新访问服务器,但若是设有max-age,在值内时间则不访问服务器。
    2. 地址栏回车和后退:正数的max-age,private、must-revalidate不会访问,但no-cache访问
    3. 刷新:都会重新访问
 
 例如:Cache-Control:max-age=<seconds>
 
 Expries不支持HTTP1.1的浏览器,来控制过期时间,值为-1是表示立即过期或者永远过期。值为0表示资源已过期。
 语法是Expries:<http-date> Example:Expires: Wed, 21 Oct 2015 07:28:00 GMT
 
 协商缓存:当缓存已经过期。Etag的优先级高于Last-Modified
 1.唯一标识方案:Etag(response携带)&If-None_match(Request携带上一次返回的Etag):服务器判断资源是否被修改。
 
 Etag是一个唯一校验码,例Etag :"2e681a-6-5d044840"
 Etag是请求返回的Response携带的一个标识符,If-None-Match是当前请求的Request中携带的标识符,值就是上次请求返回的Etag的值,服务器收到后会进行校验决定返回200还是304.
 
 
 2.最后一次修改时间:Last——Modified(Response携带)&If-Modified-Since(Request,上一次返回的Last-Modified):如果一致,则直接返回304,通知浏览器取缓存。如果不一致,则服务器返回新的资源。
 
 Last——Modified意思是资源最后的修改时间,在每次请求后都会返回一个Last-Modified
 If-Modified-Since在请求中的值是 上次Response里返回的Last-Modified的值,服务器会根据这个值判断请求的资源有没有进行过修改。没有修改就返回304,如果有修改,则返回200并返回最新的资源。
 
 缺点:
 周期性修改,内容未变,只改变的是修改时间,会重新请求;修改频繁,检测不到秒以内的修改。
 

其他相关知识点:
HTTP headers:
    1.Request Headers
        Accept:浏览器可接收的数据格式,application/json
        Accept-Enconding:浏览器可接收的压缩算法,gzip
        Accept-Language:浏览器可接收的语言,zh-CN
        Accept-Token:唯一标识
        Cookie:唯一标识
        Connection:keep-live,HTTP1.1的一次TCP连接重复使用
        Host:请求的域名,虚拟机
        Content-Type:请求发送数据的格式
        User-Agent:浏览器信息
    2.Response Headers
        Accept-Control-Allow-Origin:*表示可以解决跨域
        Content-Type:返回数据的格式
        Set-Cookie:服务端修改的Cookie
        Cache-Control:
        Expires:
    3.自定义Headers
        Authorization 权限校验的header
    4.缓存相关的headers
        Cache-Control/Expries
        Last-Modified/If-Modified-Since
        Etag/If-None-Match
        

RESTful:
    1.一句话概括RESTful(表现层状态转化原则):用URL定位资源,用HTTP描述操作。
    2.一种新的API设计方法,无法批量查询,每个URL都是唯一资源
    
TCP和UDP的区别:
    1.连接方面:TCP是面向连接的,UDP是无连接的,知道IP和端口号就可以直接传输
    2.安全方面:TCP提供可靠服务,传送的数据无差错、不丢失、不重复,且按序到达。UDP尽最大努力交付,即不保证可靠交付。TCP适合大数据量的交换。
    3.传输效率:TCP面向字节流,传输效率低。UDP面向报文,传输效率高,即使网络拥塞也不会降低传输效率,因此会出现丢包,实际应用:IP电话,视频会议
    4.连接对象数量:TCP只支持一对一,UDP支持一对一,一对多,多对一,多对多。
    5.首部字节:TCP首部字节较大为20字节,而UDP为8字节。
    6.信道:TCP是全双工的可靠信道,UDP是不可靠信道
    
 WebSocket:是一个HTML5基于http的持久性连接的协议。
     1.HTTP1.0和HTTP1.1都不支持持久性连接,HTTP1.1的keep-alive支持将多个http请求合并为一个。
     2.HTTP1.0的生命周期:Request一个Response
     3.HTTP1.1的生命周期多个一个Connection:keep-alive:多个Request多个Response。但都是被动的,不能主动发起,只能客户端Client发起。
     4.WebSocket是基于HTTP协议,握手阶段采用HTTP协议通过各种代理服务器,握手协议增加了
     Upgrade:Websocket
     Connection:Upgrade
     Sec-WebSocket-Key:x3JJHMbDL1EzLkh9GBhXDw==(校验服务器是否支持WebScoket)
     Sec-WebSocket-Protocol:chat, superchat(需要的协议)
     
 
 具有的特点:
 推送功能:减少通信量,减少资源消耗
 没有同源策略限制,客户端可以和任何服务器通信
 格式:轻量,可文本,可二进制,高效,性能开销小
 协议标识符是ws,加密是wss,服务器网址就是url。Example:ws://example.com:80/some/path

2、网站安全:XSS、

   XSS(Cross Site Scripting)跨站脚本攻击,为了区分和层叠样式表CSS做出区分,故而叫做XSS。
   XSS攻击是指攻击者在网站上注入恶意代码,利用恶意脚本篡改网页从而控制用户浏览器或者获取用户隐私数据如Cookie、Session的一种攻击方式。

   XSS攻击方式:

  1.存储型XSS:恶意代码被保存到目标网站的服务器中。时间上是先攻击服务器,后用户。
    攻击流程:
    1.攻击者将恶意代码提交到网站的数据库中
    2.用户打开目标网站时,网站将恶意代码从数据库中取出,拼接到HTML中返回给浏览器并解析
    3.可执行浏览器权限下的命令,比如获取用户数据,冒充用户行为等。
    常见场景:博客、论坛、社交网站

  2.反射型XSS:恶意代码并没有保存到目标网站,而是引诱用户点击链接到目标网站。
    攻击流程:
    1.用户点击攻击者恶意构造的URL,网站服务端将恶意代码从URL中取出,拼接在HTML里返回给浏览器
    2.浏览器接受后解析执行HTML以及恶意代码
    3.恶意代码执行后窃取用户数据并发到攻击者的网站,或者冒充用户
    常见场景:

  3. DOM型XSS:通过恶意脚本修改页面的DOM结构,纯粹是发生在客户端的攻击。
     攻击流程:
     1.攻击者构造一个含有恶意代码的URL
     2.用户点击URL,浏览器解析执行,JavaScript取出URL的恶意代码(通过location.href)并执行
     3.恶意代码执行后窃取用户数据并发到攻击者的网站,或者冒充用户
     
   防范手段:

   1.输入检查:是在客服端、服务端过滤不合法的编码
   2.输出检查:利用各种转义库对HTML模板各处节点进行充分转义
   3.使用HttpOnly,通过设置HttpOnly,浏览器可以禁止页面的JavaScript访问带有HttpOnly的cookie,Cookie使用过程:
       a.浏览器向服务器发起请求,此时没有Cookie
       b.服务器返回Set-Cookie头,向浏览器写入Cookie
       c.在Cookie到期之前,浏览器访问该域下的所有页面,都将发送该Cookie
     HttpOnly使用规则:Set-Cookie: Name=Value; expires=Wednesday, 01-May-2014 12:45:10 GMT; HttpOnly
   4.增加攻击难度:输入内容长度限制、接口安全措施
   5.避免拼接HTML:innerHTML,OuterHtml,通过使用CreateElement、setAttribute之类的方法实现
   6.避免内联事件,内联事件(onclick、onerror、onload、location、eval、setTimeout),尽量使用addEventListener绑定事件
   7.白名单制度-CSP(Content Security Policy)网页安全策略,有两种方式,一是网页中的meta标签`<meta http-equiv="Content-Security-Policy" content="script-src 'self'; object-src 'none'; style-src cdn.example.org third-party.org; child-src https:">`,另一种是通过HTTP头信息头的Content-Security-Policy
   8.验证码:防止脚本冒充用户
   
   
   CSRF(Cross Site Request Forgery)跨站请求伪造,攻击者盗用了用户的身份,以用户的名义发送了恶意请求,并且服务器校验合法。

   常见场景:以用户的名义发送邮件、发消息、盗取账号、添加系统管理员、购买商品、虚拟货品转账等。
   【利用了web中用户身份验证的漏洞,对用户曾经认证过的网站进行一些操作,简单的身份验证只能保证请求发自验证的浏览器,不能保证是用户本身的自愿行为。防御方法:1、检查referer字段,HTTP头信息。2、同步表单token校验。3、双重cookie认证。token放到cookie里。AXIOS是利用双重cookie的方式去防御CSRF,即利用定义的csrfCookieName和csrfHeaderNam校验】

   攻击流程:
   1.用户登录网站A,保留登录凭证Cookie
   2.攻击者诱使用户登录网站B
   3.网站B向网站A发起请求,浏览器会默认携带A站的Cookie
   4.A战接到请求后进行验证,会误认为是用户的请求
   
   攻击方式:
   1.GET类型:一般是利用img标签的src,用户点击图片时发生
   2.POST类型:构造一个自动提交的表单
   3.链接类型:诱骗用户点击触发
   
   防范手段:
   1.验证码,增加图形验证码,短信验证码
   **2.验证Referer**,根据HTTP协议,在HTTP头中有一个字段Referer,它记录该HTTP请求的来源地址。通过校验Referer来检查请求是否是同一个源(用户)。缺点是:IE6和FF2可通过一些方法篡改Referer值。Referer值会泄漏用户的信息,侵犯隐私,手动设置了不发Referer。Referer值中有Token值,不安全。
   3.**验证Token**,客户端发生请求时会将token带到HTTP请求头或参数中,服务端接到请求后,验证保存中服务端session中的Token和HTTP请求中的Token是否一致。
   4.验证origin属性,先判断Origin,再判断Referer,post请求、Fetch、XmlHttpRequest
   5.使用HttpOnly
   
   点击劫持:在web页面隐藏了一个透明的iframe(opacity:0或z-index:9999),用外出层假页面诱导用户点击
   防范手段:服务端结合HTTPS和设置HTTP头X-Frame-Options:DENV,让浏览器主动禁止iFrame内嵌
   
   

3、垃圾回收机制

   变量会消耗系统中的内存,消耗完系统的内存会造成系统奔溃,为了防止内存泄露,所以需要垃圾回收机制。
   
   JavaScript内存的分配机制:
   
   JavaScript内存空间分为栈、堆、池,栈中存放变量,堆存放对象,池存放常量
   
   栈(stack):系统自动分配内存空间,大小固定,可直接访问栈内存中的值,存放基础数据类型(NumberStringBooleanUndefinedNullSymbol),遵循先进后出原则。木桶原型。
   堆(heap):系统动态分配内存空间,大小不固定,不可直接访问堆内存中的位置,只可通过操作对象的引用来访问,即先从栈中获得该对象的地址指针,再从堆内取得对应的数据,存放引用类型(ObjectArrayFunction)。书架原型。堆 是无序的key-value键值对。
   
   JavaScript内存的生命周期:内存分配、内存使用、内存回收
   JavaScript变量的生命周期:局部变量(函数执行完即释放)、全局变量(浏览器关闭才释放)
   
   JavaScript引擎:
   
   是一个专门处理JavaScript脚本的程序虚拟机,一般会附带在网页浏览器中,之后和渲染引擎分开,例如:Google ChromeJavaScript的解析引擎是V8IEInternet Exporer)和微软(Microsoft Edge)是Chakra,火狐(Mozilla Firfox)是SpiderMonkeyJavaScript引擎包括:编辑器(源代码编辑成AST)、解析器(解析并输出结果)、JIT工具(将字节码、AST转换成本地代码)、垃圾回收器和分析工具(Profiler)。
   
   JavaScript引擎是程序脚本,我们写的js代码也是程序脚本,通过ECMAScript定义的规则,可以让程序识别程序并进行交流,所以JavaScript262ECMAScript标准的一种实现。
   
   浏览器中有JavaScript引擎和渲染引擎
   渲染引擎:对HTML文档进行解析并将其显示在页面上的工具,渲染过程:解析HTML构建DOM树(同时构建CSSOM树)-> 构建Render TreeDOM Tree + CSSOM Tree)-> 布局render Tree -> 绘制 Render Tree
   JavaScript引擎:提供调用接口被渲染引擎使用
   
   JavaScript垃圾回收方式:标记清除(mark and sweep)、引用计数(reference counting)
   标记清除:变量进入环境就标记“进入环境”,离开环境就标记“离开环境”,有标记“离开环境”并且没有被引用的变量就被销毁回收。
   引用计数:被引用次数为0时就被回收,例外:对象的相互引用形成一个环
   
   内存垃圾:没有被引用的对象和被互相引用形成一个环的对象
   栈内存中的对象,方法函数执行结束就会被回收
   堆内存中的对象,没有任何变量引用它时才会回收
   
   引起变量的操作:全局变量、闭包、定时器setTimeout、子元素存在、循环引用
   
   解决方案:减少全局变量、高效重复利用引用数据类型(ObjectArrayFunction

4、V8垃圾回收机制

  垃圾回收:内存将不再使用的数据进行清理回收,释放内存空间。V8将内存分为新生代空间和老生代空间。
  新生代空间:用于存活较短的对象
             新生代空间分为from空间和to空间
             Scavenge GC算法:当from空间被占满时,启动GC算法。GC算法如下:
                 1.存活的对象从from space 转移到 to space
                 2.清空from space
                 3.from space 与to space 互换
                 4.完成一次新生代GC
  老生代空间:用于存活时间较长的对象
             从新生代转移到老生代空间的条件:
                 1.经历过一次以上的Scavenge GC的对象
                 2.to space的体积超过25%
             清理回收方法:标记清除算法、压缩算法
             标记清除算法:标记存活的对象,未被标记的就被释放。并发标记、增量标记。
             压缩算法:解决内存的碎片化。将内存中清除后导致的碎片化的对象往堆的一端移动。
   
   

5、JavaScript继承的6种方式

   OO语言(Object Oriented)即面向对象语言支持两种继承方式:接口继承、实现继承。由于JavaScript是松散型语言,所以JavaScript没有函数签名,故而不支持接口继承,只支持实现继承。
   JavaScript是面向对象的编程,面向对象的是三个特点就是继承、封装、多态。
   继承:A对象通过继承对象B,就能拥有B对象的所有属性和方法。
   function Person(){
       this.name = name
       this.sayName = function(){alert(this.name)}
   }
   
   构造函数始终以大写字母开头,以区别其他函数,用来创建对象。构造函数的三个特点:
       1.没有显式的创建对象
       2.直接将属性和方法赋值给this
       3.没有retrun语句
       
   var person1 = new Person('tongdada')
   person1是Person构造函数的实例,要创建实例必须使用new操作符。person1对象拥有constructor属性,该属性指向Person
   以上person1调用构造函数的过程,分为4步:
       1.创建一个新对象
       2.将构造函数的作用域赋给新对象(this指向person1)
       3.执行构造函数中的代码
       4.返回新对象
   构造函数用于定义实例属性,原型模式用于定义方法和共享属性
   
   注意点:在创建实例的情况下重写原型,会切断现有实例和新原型之间的联系,实例的仍然指向的是旧原型。


   1.原型链继承:函数对象
       两个类,子类的继承父类,实现方式是:子类型Student的原型是父类型Person的一个实例对象
       Student prototype = new Person()  s1 = new Student()
       子类的实例s1通过proto访问Student.prototype,即父类Person的实例,访问到父类的私有方法。s1通过Student.prototype.prototype就可访问到父类Person原型链上的公有属性和方法。
       优点:父类Person新增的原型方法、原型属性,子类都能访问到
       缺点:
           1、原型属性实例共享:来自原型对象的所有属性被所有实例共享
           2、创建子类实例时,无法向父类构造函数传参
           3、在子类中新增方法、属性或者是重写父类的方法、属性,必须要放在Student prototype = new Person()之后,不然,子类新增会改变原型的指向,不再指向父类,父类重写会仍调用旧方法,没有屏蔽。
           4、无法实现多继承
       
       
   2.借用构造函数(constructor stealing):可以**传递参数**
       在子类型构造函数中通过call()调用父类型构造函数,解决原型链的不可多继承和实例共享
       function Person(name,age){
           this.name = name
           this.age = age
           this.setName = function(){alert(this.name)}
       }
       function Student(name,age,price){
           Person.call(this,name,age) // 相当于: this.Person(name, age)
           this.price = price
       }
       var s1 = new Student('tongdada',30,10)
       优点:
           1、通过call的this指向改变,解决了实例共享,即子类实例共享父类属性的问题
           2、创建子类实例s1时,可以向父类Person传参
           3、可以实现多继承(call多个父类对象)比如:name,age
       缺点:
           1、实例s1不是父类的实例,只是子类Student的实例
           2、只能继承父类的实例属性和方法,不能继承父类原型上的属性和方法
           3、无法实现函数复用,每个子类Student都有父类Person的实例函数的副本,影响性能
           
           function Person(name,age){
               this.name = name
               this.age = age
               this.setName = function(){alert(this.name)}
           }
           function Student(name,age,price){
               Person.call(this,name,age) // 相当于: this.Person(name, age)
               this.price = price
           }
           var s1 = new Student('tongdada',30,10)
   3.组合继承(combination inheritance)
       原型链+借用构造函数:使用原型链实现对原型属性和方法的继承,通过借用构造函数实现对实例属性的继承。调用父类构造函数,继承父类的属性并保留传参的优点,然后通过父类的实例作为子类原型,实现函数复用。
       
       Student.prototype = new Person()  //原型链:可继承父类原型上的属性和方法
       Student.prototype.constructor = Student //借用构造函数:第二次调用父类构造函数,实例共享是通过Person.call(this,name,age)和传参实现的
       
       优点:
           1、可继承实例的属性和方法,也可继承原型的属性和方法
           2、不存在实例属性共享问题
           3、可传参
           4、函数可复用
       缺点:调用了两次父类构造函数,生成了两份实例
       
       
   4.原型式继承
       借助原型可以基于已有的对象创建新对象,同时还不必因此创建自定义类型,ES6引入Object.create(arg1,arg2)方法规范了原型式继承。说人话就是新创建的对象不必定义,直接引用已经定义好的对象就行了。相当于是一个对象不是函数,也不涉及类
       function object(o){
           function F(){}
           F.prototype = o
           return new F()
       }
       var person = {
           name:'tongdada',
           friends:['a','b','c']
       }
       var anotherPerson = Object(person})
       var yetPerson = Object.create(person,{name:{value:'d'}})
       缺点:引用类型值会被共享,相当于对象的浅拷贝
   
   5.寄生式继承(parasitic)
       原型式继承的基础上增加了方法,即工厂模式的对象复制和添加方法。也相当于是一个对象的继承
       function createAnother(original){
           var clone = object(original)
           clone.sayHi = function(){alert('hi')}
           return clone
       }
       var anotherPerson = createAnother(person) //4中定义好的person对象
       anotherPerson.sayHi() => 'hi'
       
   6.寄生组合式继承
       借用构造函数继承属性,原型链的混成形式继承方法。
       复制了一个父类原型的副本,也就是原型链继承,调用了构造函数
       function inheritPrototype(Student,Person){
           var clone = Object.ceate(Person.prototype) //原型链:复制父类原型
           clone.constructor = Student //为副本添加constructor属性,补上重写原型的缺失
           上面两部实现了副本的完全复制,clone === Person
           Student.prototype = clone //子类的原型继承父类(超类)
           
           或者这样写
           Student.prototype = Object.ceate(Person.prototype) 
           Student.prototype.constructor = Student
       }
       
       经过inheritPrototype之后,Student既有父类又有自己本身的子类对象的属性和方法
       
       
       扩展:
           1ES6class语法糖,extends关键字实现继承,super调用父类的构造函数
           class Student extends Person {
               constructor(name,age,price){
                    super(name,age)
                    this.price = price
               }
               sayHi(){}
           }
           let s1 = new Student('tongdada',25,1000)
           缺点:IE不支持
           
           2、原型链:
               1.属性查找机制: 当访问一个对象的某个属性时,先在对象本身上查找,没有的话就会去它的隐私原型__proto__上查找,即它的构造函数的prototype,如果还没有,再去构造函数的protoype的__proto__上查找,直到最顶级的原型对象Object.prototype,一层一层向上查找形成的一个链式结构。没找到输出undefined
               2.属性修改机制: 只会修改实例对象本身的属性。修改原型需要o.prototype.x = '2'通过prototype来修改,由于实例共享,所有实例都会被改变。
               3.从而继承其他对象属性和方法。
               4.__proto__是不同对象之间的桥梁。
           
           3、最优化方案:圣杯模式
           
           4、typeScript的高级特性
               1.class:关键字extendssuper
               2.泛型(generic):let n2: Array<Person> = [] 规定该数组n2只能放Person3.接口(interface):JavaScript没有接口概念,typeScript通过关键字inerface + 接口名 => 声明一个接口
               4.模块(Module):代码分割为可复用的单元
               5.注解(annotion):为工具或框架提供的说明
               6.类型定义文件(*.d.ts5、获取原型的方法:
              1.o.__propo__
              2.o.constructor.prototype
              3.Object.getPrototypeOf(o)
           6、prototype的原生方法有七个:
              1.constructor() 所有对象都有这个属性,只可读。o.constructor === Object => true 
              2.hasOwnProperty() 判断对象自身属性中是否有指定的属性,即key,键。返回Boolean3.prototypeIsEnumerable(prop) 指定的属性是否可枚举:let o ={a:1};o.prototypeIsEnumerable('a') => true
              4.toLocaleString() 返回一个字符串
              5.isPrototypeOf() 测试一个方法是否在另一个对象的原型链上;function Bar(){};function Foo(){}; Bar.prototype = Object.create(Foo.prototype); var bar = new Bar(); Foo.prototype.isPrototypeOf(bar) => true
              6.toString() 返回该对象字符串;o.toString() => '[object Object]'
              7.valueOf() 返回该对象的原始值; o.valueOf() => {a:1}
              
              
   

6、防抖与节流

      本质上都是高频触发优化方式,如持续触发事件resize、scroll、mouseover等。
      防抖(debounce):指触发事件后在n秒内函数只能执行一次,如果在n秒内又触发了事件,则会重新计算函数执行时间。即符合条件后才执行,且只执行最后一次。
    /**
    * @desc 函数防抖
    * @param func 函数
    * @param wait 延迟执行毫秒数
    * @param immediate, ture表示立即执行,false表示不立即执行
    */
    function debounce(func,wait,immediate) {
        let timout;
        return function () {
            let context = this
            let arg = arguments
            if(timeout) clearTimeout(timout)
            if(immediate) {
                var callNow = !timeout
                timeout = setTimeout(() => {
                    timeout = null
                },wait)
                if(callNow) func.apply(context,args)
            }else{
                timeout = setTimeout(function () {
                    func.apply(context,args)
                },wait)
            }
        }
    }
    
    节流(throttle):连续触发事件,但是在n秒内只执行一次。
    /**
    * @desc 函数节流
    * @param func 函数
    * @param wait 延迟执行毫秒数
    * @param type 1 表时间戳版,2 表定时器版
    */
    function throttle(func, wait ,type) {
        if(type===1){
            let previous = 0;
        }else if(type===2){
            let timeout;
        }
        return function() {
            let context = this;
            let args = arguments;
            if(type===1){
                let now = Date.now();

                if (now - previous > wait) {
                    func.apply(context, args);
                    previous = now;
                }
            }else if(type===2){
                if (!timeout) {
                    timeout = setTimeout(() => {
                        timeout = null;
                        func.apply(context, args)
                    }, wait)
                }
            }
        }
        
        

6、柯里化

   接受多个参数的函数变换成接受一个单一参数的函数,并且返回接受余下的参数而且返回结果的新函数。
   通俗的说:在一个函数中,首先填充几个函数,然后再返回一个新的函数的技术,称为函数的柯里化。通常在不侵入函数的前提下,为函数预置通用参数,供多次重复调用。
   
    const add = function add(x){
        return function(y){
            return x+y
        }
    }
    const add1 = add(10)   //预置的通用参数
    add1 = function(y){ return 10 + y }  //返回的新的函数,基于通用参数,可多次重复调用
    add1(1) => 11
    add1(2) => 12
    

8、new运算符执行过程

    新建一个空对象,这个对象原型指向构造函数的prototype,指向构造函数后返回这个对象
    new Person('tongdada') = {
      var obj = {};
      obj.__proto__ = Person.prototype;
      var result = Person.call(obj, 'tongdada');
      return typeof result === 'object' ? result : obj;
    }
    1.新生成一个对象
    2.链接到原型,__proto__
    3.绑定this,通过call、apply、bind,this指向新生成的空对象,即构造函数,将其改造成需要的样子,
    4.返回新对象(如果构造函数有return,则返回该值),返回值要看result是否返回对象值
    
    在JavaScript中,万物皆对象,为什么要new创建对象?
    通过new创建的对象和构造函数直接建立一条原型链,让对象有了依赖关系和继承能力。让JavaScript对象能更好的映射真实世界里的对象,这是面向对象的本质。
   
   

9、输入URL到页面显示的过程

   涉及知识点:URL规范、HTTP协议、DNS、CDN、网络协议、浏览器解析规则、JS执行。
   
   (1) DNS服务器是将具体域名转换成IP地址的作用。
       互联网通讯基于TCP/IP,而TCP/IP是基于IP地址,由于IP地址不好记,给IP地址起一个名字,这个域名就可以通过DNS服务器来转换成IP地址。这个过程被称为地址请求解析。
   (2) 同源策略:两种。
       1、DOM同源策略,指不同域名的iframe限制互相访问。
       2、xmlHttpRequest同源策略:禁止使用XHR对象向不同源的服务器请求。
   
  1、浏览器会开启一个线程来处理这个请求,对 URL 分析判断如果是 http 协议就按照 Web 方式来处理;
  
  2、调用浏览器内核中的对应方法,比如 WebView 中的 loadUrl 方法;
  
  3、通过DNS解析获取网址的IP地址(会检查缓存,查找缓存中是否有记录,浏览器缓存->系统缓存hosts文件->路由器缓存。都没有,则查找系统的hosts文件中是否有记录。都没有,则查询DNS服务器,得到服务器的IP地址。),判断当前URL是否跨域(同源策略),设置 UA 等信息发出第二个GET请求;
  
  4、进行HTTP协议会话(根据这个IP和对应的端口号,构造一个HTTP请求),客户端发送报头(请求报头);这个请求封装在一个TCP包中,这个TCP包依次经过传输层、网络层、数据链路层、物理层到达服务器。
  
  5、进入到web服务器上的 Web Server,通过TCP协议的三次握手建立连接
  
  6、服务器解析这个请求作出响应,返回相应的HTML给浏览器,HTTP响应报文包括:响应头、响应行,相应主体。并返回对应的http状态码。1xx信息、2xx成功、3xx重定向、4xx客户端错误、5xx服务器端错误。响应涉及缓存,先看Cache-Control、Expries->Etag和If-None-Match-> Last-Modified和If-Modified-Since。返回响应HTML后,断开TCP连接,即TCP的四次挥手。
  
  7、处理结束回馈报头,此处如果浏览器访问过,缓存上有对应资源,会与服务器最后修改时间对比,一致则返回304;
  
  8、浏览器开始下载html文档(响应报头,状态码200),同时使用缓存;浏览器开始解析:构建DOM Tree -> 构建CSSOM Tree -> 构建Render Tree -> 布局(确定各个元素的位置和尺寸) ->绘制(会发生重绘、回流或重排)
  
  9、文档树建立,根据标记请求所需指定MIME类型的文件(比如css、js),同时设置了cookie;
  
  10、页面开始渲染DOM,JS根据DOM API操作DOM,执行事件绑定等,页面显示完成。
   
   
   1.检查缓存
   2.DNS解析
   3.TCP连接
   4.发送HTTP请求
   5.服务器返回请求的文件
   6.浏览器解析渲染页面
   
   输入URl后,浏览器要找到URL域名服务器的IP。
   首先会检查缓存,查找缓存中是否有记录,浏览器缓存->系统缓存->路由器缓存。都没有,则查找系统的hosts文件中是否有记录。
   都没有,则查询DNS服务器,得到服务器的IP地址。
   浏览器根据这个IP和对应的端口号,构造一个HTTP请求。请求的报文包括这次请求的信息,请求方法、请求说明、请求附带的数据。并将这个请求封装在一个TCP包中,这个TCP包依次经过传输层、网络层、数据链路层、物理层到达服务器。
   到达服务器后,通过TCP协议建立连接,即TCP的三次握手。
   服务器解析这个请求作出响应,返回相应的HTML给浏览器,HTTP响应报文包括:响应头、响应行,相应主体。并返回对应的http状态码。1xx信息、2xx成功、3xx重定向、4xx客户端错误、5xx服务器端错误。这里的响应涉及缓存,先看Cache-Control、Expries->Etag和If-None-Match-> Last-Modified和If-Modified-Since
   返回响应HTML后,断开TCP连接,即TCP的四次挥手。
   浏览器得到HTML后,开始解析:构建DOM Tree -> 构建CSSOM Tree -> 构建Render Tree -> 布局 ->绘制
   
   根据HTML树形结构来构建DOM树,采用标记化算法,进行元素状态的标记,即HTML parse -> DOM Tree
   遇到js脚本和外部js连接,就停下来执行下载响应的代码,就会造成js阻塞,可利用refer async,最好是refer,并且把js脚本放在最后
   根据外部样式、内部样式、内联样式构建CSS对象模型树,即CSSOM Tree,构建完成之后,CSSOM和DOM合并为渲染树,即Render Tree。
   布局是确定各个元素的位置和尺寸
   GPU painting像素绘制页面
   
  

10、Cookie和session的区别

  Cookie实际上是一小段文本信息,Cookie的内容包括:name(名字)、value(值)、maxAge(失效时间)、path(路径)、domain(域)、secure(安全)。
  name:创建之后不可改
  value:格式是字符串,两种编码,Unicode和二进制数据
  maxAge:单位秒,默认-1。正数是maxAge秒后失效,负数是关闭浏览器即失效,0是删除该Cookie
  path:只有“/”的话,本域名下都可访问,“/pathName”,只有该路径下才可访问,同源策略
  domain:域,第一个字符必须为“.”,如果.后没有值则为所有域
  secure:是否使用安全协议传输
  
  Session机制是服务端的一种机制。包括一个sessionID作为唯一标识符
  
  当浏览器发送一个请求后,服务器Response给浏览器一个Cookie并保存,大小4k,每次传输**必须**要携带,一个站点最后保存20个Cookie
  
  区别如下:
      1.Cookie在浏览器,Session数据存放在服务器
      2.Cookie欺骗,CSRF攻击
      3.Session访问增加,影响服务器性能
      4.单个Cookie不超过4k,一个站点最后20个,不同浏览器不同
      5.Cookie保存的是字符串,Session保存的是对象,有个属性是sessionID,校验其值
      6.Cookie的path设置有同源策略的路径限制,Session没有
      7.Cookie不安全,存放不重要信息,Session放重要信息
      8.Cookie的maxAge若为-1,浏览器关闭即失效,若为正值,关闭也不失效
      

11、闭包

1.定义:能够读取其他函数内部变量的函数,子函数所在的父函数的作用域不会被释放。
  定义:即使在词法范围之外调用,仍可以记住它的词法范围。
  定义:有权访问另一个函数作用域中的变量的函数。本质上是函数局部变量的集合。函数执行上下文结束后,这些变量并不释放,而是分配在堆中。
  如何产生闭包:当一个函数内定义另一个函数,就会产生闭包。
 2.标准的闭包:function a(){
           let i = 0;
           return function b(){
               return i++;
           }
       }
       
 3.闭包的作用:
  (1)柯里化:只需要执行一次的函数,内部变量不需要维护,可以使用闭包,比如柯里化。模仿块级作用域。
  (2)结果缓存:一个需要多次调用的函数,而且调用很耗时,闭包可以将值缓存起来,需要时就从缓存中去取,找不到就需要更新缓存,并返回值。保存外部函数的变量。
  (3)封装:实现类和继承。封装私有变量
  函数具有一个隐藏属性[[scope]]。
  立即执行函数(IIFE):直接调用,直接执行。 (function(){})()
     4.斐波那契序列:
     const factorialMemo = (function(){
         const cache = {}
         return function factorial(n){
             if(n === 1 || n === 0){
                 return 1
             }else if(cache[n]){
                 return cache[n]
             }else {
                 cache[n] = n * factorial(n-1)
                 return  cache[n]
             }
         }
     })()

12、执行上下文

  1.执行上下文(Execution Context)即执行环境(EC):只要有JavaScript代码运行,它就一定是运行在执行上下文中。当程序的执行流进入到可一个可执行的代码时,就进入了EC2.执行上下文分为三种类型:
      1.全局执行上下文:只有一个,程序载入的默认环境,浏览器的全局对象就是windowthis指向window2.函数执行上下文:存在无数个,函数被调用时才会被创建,每次调用都会创建一个新的执行上下文。
      3.Eval函数执行上下文:指运行在eval()函数中的代码
  
  执行上下文的三个生命周期:
      1.创建阶段:当函数被调用,但未执行任何内部代码之前。
          创建阶段做了三件事:
          a.确定this的值,也被称为This Bindingthis的值执行时才能确认,定义时不能。
          b.词法环境组件被创建:词法环境包括全局环境、函数环境。
          全局环境:是一个没有外部环境的词法环境,外部环境引用为null,有一个全局对象,this指向这个全局对象。
          函数环境:用户在函数中定义的变量存储在环境记录中,包含了arguments对象,外部环境可以是全局环境也可以是包含内部函数的外部函数。
          c.变量环境组件被创建:变量环境也是一个词法环境,在ES6中,词法环境和变量环境的区别在于:词法环境用于存储函数声明和变量(letconst绑定),变量环境仅用于存储变量(var绑定)。
          通俗的理解是:变量提升的本质原因
          
    let a = 20;
    const b = 30;
    var c;
    var d = 5;
    在创建阶段,letconst定义的变量a和b没有被赋值。但var变量在创建阶段被赋值为undefined。
    原因:创建阶段,会在代码中扫描变量和函数声明,然后将函数声明存储在环境中,但变量会被初始化为undefinedvar声明时)和保持uninitialized(未初始化状态)即let、cosnt声明。
    从另一个角度理解:
    ES5规定的全局对象和顶层对象的属性是等价的,var命令和funcion 命令的全局对象自然也在顶层中,所以window.c = undefined;window.d = 5;
    ES6规定的letconst、cals声明的全局对象不属于顶层对象的属性。所以window.a =
    **底层原理是:JavaScript代码是先经过编译器编译成可执行代码,再交给JavaScript引擎执行。用var关键字声明的变量在ES5规定里是在编译阶段声明的,ES6规定的letconst则不是。**
      2.执行阶段:执行变量赋值,代码运行。如果JavaScript引擎在源代码声明的实际位置找不到变量的值,name将其分配为undefined3.回收阶段:执行上下文出栈,等待虚拟机回收执行上下文。window.a = undefined
      
      
  3.执行栈,即调用栈,具有LIFO(后进先出)结构,用于存储在代码执行期间创建的所有执行上下文。执行时将函数上下文并压入栈,执行完毕,推出执行栈。
  
  4.作用域:Scope
      三种,全局作用域,函数作用域,eval作用域。
      ES6多了一个块级作用域。
      代码执行前的编译阶段,有三个步骤:分词/词法分析; 解析/语法分析; 代码生成。
  
  5.作用域链:Scope chain
      一系列的嵌套作用域就形成了作用域链。
      根据内部函数可以访问外部函数的变量这种机制,这些变量就像一条变量列表,通过链式查找的方式决定哪些变量能被函数访问。
      由当前的活动对象AO和当前函数的[[scope]]属性拼接而成。
  
  6.letconstvar的区别:
      (1)letvar用来声明变量,const用以声明只读的常量。
      (2)var存在变量提升,是在编译阶段声明的。letconst则是在执行阶段声明,不存在变量提升。
      (3)let声明的变量是块级作用域,存在暂时性死区,不受外部影响,且不允许重复声明同一个变量。
      (4)const在声明时必须初始化赋值,声明之后,值不允许改变。如果定义的是引用类型,如对象,改变对象属性的值但不改变对象的指针就可以,如:const o = {a:2}; o.a = 3;=>o = {a:3},因为栈内是不可变的。
     
   7.基本数据类型和引用数据类型
   (1)赋值,新值和旧值在栈内存空间的位置是不一样的,即给基本类型的值赋一个新值,是在内存空间上的新开辟一块内存空间,并将新的内存地址和变量进行绑定。JS引擎会在合适的时候进行GC旧的内存空间。
   (2)比较,基本数据类型是值的比较,引用类型是引用的比较。比较的是内存地址是否一样,无关值。
   (3)基本数据类型在栈,引用类型在栈和堆。
   (4)NaNJS中的特殊值,非数字,但数据类型是数字,不等于任何值,包括自身,Boolean(NaN)=>false,数学运算中,无法运算或计算失败都会返回NaN。
   (5)改变函数作用域的方法:evalwith。都会导致数据泄露,性能降低。
   (6)判断数据类型的方法,typeofArray.isArrayinstanceofisNaN。
   (7)JavaScript采用的是词法作用域,即静态作用域。函数的作用域在函数定义的时候就决定了。
   
   8.正则表达式
   (1)语法:/正则表达式主体/修饰符(可选)     修饰符i/g/m
   (2)test() 方法,返回Blooean.
   (3)语法:
   (4)语法:
   (5)语法:
    
   9.变量对象(VO)Variable object:存储了再在上下文中定义的变量、函数声明和形式参数,不可访问。是在执行阶段前的创建阶段,到执行阶段就变为活动对象(AO)activation object,包含VO以及参数arguments和params
   
   10.LHS(Left Hand Side)左手边查询,对变量进行赋值。如:let a = 2;  对a进行赋值。
   11.RHS(Right Hand Side)右手边查询,获取变量的值。 LHSRHS都是在编译的第二步执行的。
   
   12.PWA渐进式WEB框架。web技术开发APP

13、Ajax

   1.原生AJAX(Asynchronous JavaScript and XML)
       原理:通过XmlHttpRequest对象来向服务器发送异步请求,从服务器获得数据,然后用JavaScript操作DOM从而更新页面。
       
       实现过程:
       var xhr = new XmlHttpRequest()  //创建XmlHttpRequest对象
       xhr.open('GET',a.php,false)      //用XmlHttpRequest对象的open和send方法发送请求
       xhr.send()
       xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded') //post添加http信息头,发送信息致服务器的内容编码类型
       xhr.onreadystatechange=function(){  
           if(xhr.readyState === 4){                          //监听状态
               if(xhr.status === 200 || xhr.status === 304){
                   // 做一些事情 xhr.responseText                //执行回调函数
               {  
           }
       }
    代码详解:
        1.open(method,url,async)
            method指请求方法,get、post
            get/post请求的区别:post无法使用缓存,更新数据、post发送大量数据、含未知字符的请求用post,更安全。
            url:规定服务器端脚本的url,文件类型
            async:true是异步,false是同步
        2.send()方法可将请求发送服务器
        3.onreadystatechange(),存有处理服务器响应的函数,readyState改变函数就会执行
        4.readyState:存有服务器响应的状态信息
            0 => 未初始化,open还未调用
            1 => 载入,正在发送请求,服务器连接已建立,open已调用,send方法未调用
            2 => 载入完成,请求已接收,已接收到头信息,send方法已执行完成
            3 => 交互,请求处理中,已接收到响应主体,交互,正在解析响应内容
            4 => 完成,请求已完成,响应内容解析完成,可在客户端调用
        5.responseText:获得字符串形式的响应信息
        6.setRequestHeader():post传数据时添加HTTP头,GET直接在url后
   
   2.AJAX解决浏览器缓存问题
       AJAX在发送请求前加上anyAjaxObj.setRequestHeader('If-Modified-Since',0)
       AJAX在发送请求前加上anyAjaxObj.setRequestHeader('Cache-Control','no-cache')
       在URl后面加上一个随机数:"fresh"=Math.random()  
       在URl后面加上一个时间戳"nowtime"=+new Date().getTime() 
       应用:下载附件的时候,可解决下载最新附件,不取缓存中的附件
    
   3.AXIOS的优势:
       AXIOS是一个基于Promise的HTTP库,支持Promise的所有API
       AXIOS有两个拦截器,请求拦截器Resquest,响应拦截器Response,拦截请求和响应
       AXIOS可以转换请求数据和响应数据,响应数据自动转换成JSON类型的数据
       AXIOS可以实现并发请求,axios.all()、axios.spread(),解决调用方式混乱
       AXIOS客户端支持防止CSRF(通过请求中携带Cookie中的key)
       AXIOS支持5种请求方式GET、POST、PATCH(更改的数据推到后端)、PUT(所有数据推到后端)、DELETE
       AXIOS通过在请求头中添加Access-Control-Allow-Origin解决跨域问题
       
       

14、Babel和polyfill

    1. Babel是一个工具集,用于将ES6的代码转为ES5等向后兼容的js代码。**转换语法规则。**
    Babel官方的三个包:Babel/cli、Babel/CoreBabel/preset-env
    Babel/cli是Babel的命令行转码工具包,使用时需要安装Babel/Core核心npm包
    Babel/CoreBabel的核心npm包
    babel/preset-env这个npm提供了ES6转换ES5的语法转换规则,例如将箭头函数转换成ES5定义的函数语法
    Babel默认只转换新的语法,不转换新的API,比如PromiseAPIBabel是不能转换的
    
    新的API分为两类:
    1、新的全局对象及对象自身的方法,如PromiseMapSymbolProxy以及Object.assignPromise.resolve2、新的实例方法,如find。[1,2,3,5].find((x)=>{x > 2})
    
    3. Polyfill是**补齐API**,通过polyfill在目标环境中添加缺失的特性。
        Polyfill相当于一个垫片,垫平不同浏览器之间的差异。
        Polyfill提供了全局的ES6对象以及通过Array.prototype原型链等实现对实例的实现。
        Polyfill广义上讲是为环境提供不支持特性的一类文件或库,狭义上讲是polyfill.js文件以及@Babel/polyfill这个npm包
     
    4. babel的配置,主要是两个配置数组,plugins插件数组和presets预设数组。
         presets预设数组,例如babel-presets-se2015就是用来处理ES2015的二十多个babel插件的集合。
         Babel7版本有短名称,省去Babel-plugin和Babel-preset
     
    5. babel里的plugin和preset的执行规则:
        plugin插件比preset预设先执行
        Plugins插件数组执行顺序是从前往后执行
        Presets预设数组执行顺序是从后往前执行
     
     6.Babel里常用的plugin和preset
         由于@Bable/preset-env已经将大部分预设和插件整合了,所以常用的预设一个preset-env就够了,还有三个preset-flow、preset-react、preset-typescript
         常用的插件只有@Babel/plugin-transform-runtime,这个包的作用是,将ES6代码转换为ES5代码的时候会增加一些函数声明,也就是注入的函数,又叫辅助函数,@Babel/plugin-transform-runtime这个npm包是用来将这些语法转换后会用到的辅助函数集成到了一起,这样在webpack构建工具的时候把用到npm包里的辅助函数引入一次,这样复用可以减少体积。
         每个转换后的文件都会注入相同的辅助函数,为什么webpack不用打包工具去掉重复的函数声明,而是通过@Babel/plugin-transform-runtime这个plugin插件去存放这些辅助函数的包?
         原因是:webpack是基于模块去做去重工作的,每一个函数声明都是引用类型,在堆内存中不同的空间存放,缺少唯一的地址来做去重,所以webpack是做不到把不同文件的相同函数声明去重,当我们放在一个npm包里时,基于模块工作的webpack就可以进行去重工作了。
         
      7. Babel-polyfill引入
         在webpack的entry入口文件里引入:entry:{app:'babel-polyfill','./src/main.js'}
         在main.js里引入:import 'babel-polyfill' 或者第三方插件polyfill.js
         
      8.Babel-loader是对js代码进行自动转移的一个loader
       
  
    

15、Promise

   callback -> Promise -> generator -> async/await
   
 1.生成器函数:function* 这种声明方式(function关键字后跟一个星号)会定义一个生成器函数。一个函数最多有255个参数。生成器函数在执行时能暂停,后面又能从暂停处继续执行。
   调用一个生成器函数,并不会马上执行里面的语句,而是返回这个生成器的迭代器对象,调用这个迭代器对象的next()方法才会执行,执行到第一个yield为止,yield后是迭代器要返回的值value,若用yield*就会将生成器执行权交给另一个生成器函数。
   next()方法返回一个对象,value和done,value是yield返回值,done是Boolean值表示是否执行完成。
   next(arg1)方法传入参数会传给上一条执行yield语句左边的变量。
   return会导致生成器立即变为完成状态。
   
   generator函数的thorw()向生成器抛出一个错误
   for...of...方法都可以自动遍历generator函数内部的yield
   普通函数不允许使用yield
   
    function *generator(){
        yield 1;
        yield* anotherGenerator()         // 移交执行权
        let first = yield 2;              // 传入参数会传给上一条执行yield语句左边的变量
        let second = yield first + 10
        retrun 'over'
        yield '1111'
    }
    
    function* anotherGenerator(){
        yield 10;
    }
    
    let gen = generator()    //调用生成器函数,并不会马上执行里面的语句,返回这个生成器的迭代器对象
        gen.next()           //执行yield 1  返回1 done为false
        gen.netx()           //执行anotherGenerator函数的 yield 10  返回10 done为false
        gen.next()           //传入参数 执行yield 2, done为false
        gen.next(4)          //first =4 是next(4)将参数赋给上一条的 返回14 done为false
        gen.next()           // 执行结束 返回over done值为true
2.回调地狱:回调函数嵌套异步回调函数。解决回调地狱可以用ES6里的Promise、generator和ES7里的async await
     doSomething(function(result) {
      doSomethingElse(result, function(newResult) {
        doThirdThing(newResult, function(finalResult) {
          console.log('Got the final result: ' + finalResult);
        }, failureCallback);
      }, failureCallback);
    }, failureCallback);
3.Promise

(1) 本质上Promise是一个函数返回的对象。保存着未来将要结束的事件。
    两个特征:
    1.对象的状态不受外部影响,异步操作的三个状态,只有异步操作的结果可以决定状态
    2.一旦状态改变就不会再变
    
(2) promise解决的问题:
    1. 回调地狱
    2. 解决异步
    3. 支持多个并发的请求,promise.all
    
(3) Promise支持then的链式调用:Promise.then(f1).then(f2).then(f3)
    实现原理就是创建一个数组,执行回调时改成遍历回调数组执行回调函数。
    
(4) 底层实现:
                new Promise((resolve,reject)=>{
                    setTimeout(()=>{
                        resolve
                    },1000)
                })

 (5) Promise有三种状态:pending(待定):初始状态,既没有被兑现也没有被拒绝、fulfilled(已兑现):操作成功完成、rejected(已拒绝):操作失败
    Promise在相应的处理程序被绑定时就已经被兑现或被拒绝。
    Promise.prototype.then()返回的是promise
    Promise.prototype.catch()返回的是promise
    resolved(已决议):表示promise已处于已敲定状态(settled)
    惰性求值:无参数的箭头函数,如f =() => 表达式
    
 (6) Promise的静态方法:
        1.Promise.all(interable):返回一个Promise对象,将多个没有关系的Promise封装成一个Promise对象,有一个失败了就返回失败的结果,都成功了返回一个数组数据。解决网络拥塞现象。适用场景:比如游戏类素材比较多的应用,预先加载图片资源,flash,文件等,当所有都加载完成后再进行页面的初始化。
        let p = Promise.all([Promise1, Promise2, Promise3]) p.then().catch()
        
        2.Promise.resolve(value):返回状态由指定的value决定的Promise对象
        3.Promise.reject(reason):返回一个状态为失败的Promise对象
        4.Promise.any() 接受一个promise对象集合,当其中的一个promise成功,就返回那个成功的promise值。都失败的话就返回一个失败的Promise值
        5.Promise.race() 返回最快的Promise对象,不管是成功还是失败, 适用场景:给异步请求设置超时时间。Promise.race([Promise1(),PromiseTimeout()]).then((data)=>{}).catch((err)=>{})
        
  (7) Promise A+ 的实现:
      Promise A+ = 构造函数 + 回调参数Resolve和reject
        
  (8) Promise原型:
        Promise.prototype.constructor = Promise
        Promise.prototype.then() 返回一个新的Promise
        Promise.prototype.catch()
        Promise.prototype.finally()
        
   (9) 创建Promise
         Promise是用关键字new及Promise构造函数来创建的。该构造函数会把一个处理器函数作为它的参数。这个处理器函数接受两个参数resolve、reject。异步完成返回值时调用resolve,异步失败调用reject。
         const myFirstPromise = new Promise((resolve,reject)=>{})
         一个函数想要拥有Promise功能,让其返回promise即可。
         function myAsyncFunction(){
             return new Promise((reslove,reject)=>{
                 const xhr = new XmlHttpRequest()
                 xhr.open(post,url.true)
                 xhr.onload = () =>resolve(xhr.responseText)
                 xhr.onerror = () => reject(xhr.status)
                 xhr.send()
                 xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded')
                 xhr.onreadystatechange = function(){
                     if(xhr.readyState === 4){
                         if(status === 200 || status === 304){
                             let data = xhr.responseText
                             resolve(data)
                         }else{
                             reject(error)
                         }
                     }
                 }
             })
         }
        
 (10) Promise的特点是链式调用
     async await 语法: async function name1(arg1,...argn){ const func2 = await name2()}
   () => x 是 () => { return x; } 的简写
   
   
   Promise的执行顺序为:同步执行的代码-> promise.then -> settimeout
   
 (11) 手写Promise.all
   
    Promise.myAll = function(promises){
        if(!Array.isArray(promises)){ return new Error('argument is no Array') }
        let arr = new Array(),count = 0 
        return new Promise((resolve,reject)=>{
            promises.map((item,index)=>{
                Promise.resolve(item).then(result=>{
                   arr[index] = result
                   count ++
                   if(count === promise.length){
                       resolve(arr)
                   }
                })
                .catch(e=>{
                    new Error 
                })
            })
        })
    }
    const a = new Promise((resolve,reject)=>{resolve('a')})
    const b = new Promise((resolve,reject)=>{resolve('b')})
    const c = new Promise((resolve,reject)=>{resolve('c')})
    
    Promise.myAll([a,b,c]).then(res=>{console.log(res,'success')}).catch(e=>{console.log(err, 'iiii')})
    
 (12) 实现Promise.race()
     myPromise.race = function(promises){
        return new Promise(function(resolve,reject){
            for(let i=0;i<=promises.length;i++){
                promises[i].then(function(data){
                    resolve(data)
                }).catch(function(err){
                    reject(err)
                })
            }
        })
     }
     
   (13) promise注意点:
        promise.then()是异步,放入微任务队列执行。
        promise有三种状态pending待兑现状态,fulfilled已成功状态,rejected已失败状态。状态改变只能是一次,由pending到fulfilled或rejected。状态一旦改变,不能再变。
        promise.then().then()链式调用,是每次调用都会返回一个新的promise
        Promise的.then()和.catch()返回值不能是promise本身,不然会陷入死循环。
        promise的.then()和.catch()的参数期望是函数,传入非函数会发生值穿透。Promise.resolve(1).then(2).then(Promise.resolve(3)).then(console.log) ==> 1

.

16、数组方法的总结

   基本归纳为增、删、改、查
   
   (1)增:
    1. push()  数组末尾推入,改变原数组,返回数组长度
    2. unshift() 数组头部推入,改变原数组,返回数组长度
    3. splice(start,number,value...) 改变原数组,返回新数组,可删除,插入
    4. concat() 数组合并,原数组不影响,浅拷贝
    
   (2)删:
    1. pop() 数组末尾弹出删除,改变原数组,返回原数组最后一项即删除项
    2. shift() 数组头部弹出删除,改变原数组,返回原数组第一项即删除项
    3. splice(start,number,value...) 改变原数组,返回新数组,可删除,插入
    4. slice(start,end) 不改变原数组,返回截断后的新数组 
    
   (3)改:
    1. splice(start,number,value...) 改变原数组,返回新数组,可删除,插入
    
   (4)查:查找元素,返回元素坐标或元素值
    1. indexOf('x') 查找数组对应下标,从前往后查
    2. includes() 判断是否包含指定值,返回 Boolean值;a1.includes(1) => true
    3. find() 查找出第一个符合条件的数组成员,并返回该成员,没有则返回undefined
    4. findIndex() 查找出第一个符合条件的数组成员位置,并返回该位置下标,没有则返回-1
    5. lastIndexOf('x') 查找数组对应下标,从后往前查
    6. contains() 用于DOM元素的查找包含关系,返回值为 Boolean值;div1.contains(div2) => true
    
   (5)排序方法
    1. reverse() 反转,改变原数组
    2. sort() 排序,改变原数组
    
   (6)转换方法
    1. join() 将数组转成指定格式的字符串
    2. toString() 将数组转成字符串;a1.toString(); =>'1,2,3'
    3. Array.from() 类数组转成数组,以及Set和Map
    4. Array.of() 转成数组 const arr1 = Array.of(4,5,6); arr1=>[4,5,6]
    
   (7)迭代方法
    1. for(let i=0;i<arr.length;i++){} 
    2. for(let i in obj){} 主要用来遍历对象,可遍历对象原型链上的可枚举的所有属性,索引为String,且遍历的顺序是随机的
    3. forEach((value,index,self)=>{}) 对于已删除(delete)和未赋值(undefined和null)的元素跳过,而且不能break、return。可以用try/catch中的throw new Error来停止
    4. for(let i of arr){} ES6引入,不支持对象,可正常break、continue、return。支持类数组如DOM Nodes对象,支持Map和Set对象,支持字符串遍历.
    5. some() 遍历数组,有一项返回true,则返回true。循环在第一次 return true后返回
    6. every() 遍历数组,有一项返回false,则返回false。循环在第一次 return false后返回
    7. filter() 遍历数组过滤。返回一个新的数组,该数组内的元素满足回调函数
    8. map()遍历数组,返回 回调返回值组成的新数组
    9. reduce(function(pre,crrunt,index,arr){},defaultPrev)/reduceRight() 数组求和
   
   (8)其他方法
    
    1. 扩展云算符... 
       替代apply方法:ES5:Math.max.apply(null,a1);ES6:Math.max([...a1])
       复制数组:let a1 = [1,2,3];let a2 = [...a1]; a2=>[1,2,3]   替代concat
       合并数组:let a3 = [...a1,...a2]; a3=>[1,2,3,1,2,3]        替代concat
       解构赋值:const [a4,...a5] = [7,8,9]; a4=>7; a5=>[8,9]     
       字符串转成数组:let arr = [...'hello']; arr=['h','e','l','l','0'] 替代join
     2.flat(Infinity) 数组拆解,多维数组=> 一维数组,数组维度降
     3.copyWithin(target,start,end) 改变原数组,将指定位置的元素复制到其他位置
     4.fill(x,first,last) 给数组的元素赋值;['a','b','c'].fill(7,2,3); =>['a','b',7] 
     

17、字符串方法总结:

     (1)增
      1. concat() 将一个或多个字符串合并成一个新字符串。 string.concat(str2)
      
     (2)删(截取字符串)
      1. substring(start,stop) 提取字符串中介于两个指定下标之间的字符。start,stop为非负整数
      2. substr(start,length) 提取从start下标开始指定数目的字符 start可正可负,负数代表从右截取
      3. slice(start,stop) 提取字符串中介于两个指定下标之间的字符,start,stop都可正可负,负数代表从右截取。
      4. replace(reg/string,replacement) 字符串中用一些字符替换另一些字符。
      
     (3)改
      1. trim() 从字符串的两端删除空白符。 string.trim()
      2. trimLeft()、trimStart() 从字符串的开头删除空格。string.trimStart()
      3. trimRight()、trimEnd() 从字符串的末尾删除空格。 string.trimEnd()
      4. repeat(count) 返回字符串指定赋值次数的字符。 string.repeat(2) 
      5. padStart(length,s) 用一个字符串填充当前字符串,生成的字符串达到指定的长度。从字符串的左侧开始填充。 str.padStart(6,'.') 
      6. padEnd() 用一个字符串填充当前字符串,生成的字符串达到指定的长度。从字符串的右侧开始填充。
      7. toLowerCase() 将字符串的值转为小写形式并返回。 string.toLowerCase()
      8. toUpperCase() 将字符串的值转为大写形式并返回。 string.toUpperCase()
      
     (4)查
      1. charAt() 从字符串里返回指定的字符。str.charAt(index)。index的范围是0~length-1
      2. charCodeAt() 返回0~65535整数,即指定位置的UTF-16的编码。str.charCodeAt(index),index范围是0~length-1。默认为0
      3. indexOf(searchString,startIndex) 返回字符串第一次出现的位置,找不到返回-1。 str.indexOf('code'),默认startIndex为0
      4. lastIndexOf(searchString,startIndex) 从后开始查指定字符第一次出现的位置,找不到返回-1
      5. match(reg) 在字符串内检索指定的值,并返回。
      6. includes(searchString,start) 判断字符串是否包含指定的字符串,返回Boolean
      7. startWith(v,start) 检查字符串是否以指定的字符串开头并返回Boolean值。start是查找的开始下标位置。 string.startWith('a')
      
      
     (5)字符串转换数组
      1. split(place,howmany)  从指定的位置把字符串分割成数组,不超过howmany的长度
      
     (6)数字转换成字符串
      1. toString(radix) 把不同进制的数转换成字符串
     
     (7)模板匹配方法
      1.match() 在字符串内检索指定的值,并返回数组。 string.match(patter) 
      2.search() 检索字符串中指定的字符串,并返回字符串的起始位置或-1。 str.search(reg) 
      3.replace() 将字符串的一些字符替换成另一些字符并返回。 str.replace('a','b')
      

17、类型转换机制:

    (1)显示转换
        常见的方法有Number()、parseInt()、String()、Boolean()
        Number() ==> Number(undefined/{}/'2a')=NaN; Number([]/null/''/false)=0
        parseInt(num,radix) ==> parseInt() 将字符串换成数字,radix值为2~26进制
        String() 将任意类型的值转为字符串
        Boolean() ===> Boolean(undefined/null/false/NaN/0)=false;Boolean([]/{})=true
        
    (2)隐示转换
        两种情况下发生隐式转换,比较运算和算术运算
        1. 隐式转换成Boolean值:比较运算( == 、 != 、>、<) 、if、while。
        == 规则:
               a. 两个简单类型,字符串和布尔值都转换成数值,再比较
               b. 简单类型和引用类型,对象用valueOf转换成原始类型的值,再比较
               c. 两个都是引用类型,比较是否指向同一个对象,再比较
               d. null和undefined相等 
               e. 存在NaN则返回false
        if规则:
               a. if(obj == null) 等同于 if(obj === null || obj === undefined)
               
        2. 算术运算(+、 -、 *、 /、 %) 预期的值为字符串时,就会自动转成字符串,常发生在 + 运算符里。其他运算符里都会自动转换成数值。
        
        

17、ES6、ESNext小结:

 1ES6:
   (1)类(class):如下代码块
   (2)模块化(ES Module):模块A.jsexport const sub = (a,b) => a+b;import {sub} from './A'
   (3)箭头函数(Arrow):如上的sub箭头函数:const sub = (a,b) => a+b;
   (4)函数参数默认值:function(age =25){//...}
   (5)模板字符串 const str = `my name is ${name}`
   (6)解构赋值: let a = 1,b=2; [a,b] = [b,a] ;a=> 2,b=> 1
   (7)扩展操作符:let a = [...'hello'] ;a=> ['h','e','l','l','0']
   (8)对象属性简写:let name = 'dada';let obj ={name}
   (9)Promise:Promise.resolve().then(()=>{}).catch()
   (10)letconst
class
    class Man(){
        constructor(name){
            this.name = 'tongdada'
        }
        
        say = name = > console.log(name)
    }
    const man = new Man('tongdada')
    man.say() => tongdada
2、ES7
    (1)inludes(): Array.prototype.includes()
    (2)指数操作符; 2**10 => 1024 类似的有2e2=> 200
    
3、ES8
    (1)async/await:异步解决终极方案
        async getData(){
            const res = await api.getTableData()
            ...
        }
    (2)Object.values()
    (3)Object.entries()
    (4)str.padStart(targetLength,str1) 用另一个字符串填充当前字符串,直到结果字符串达到指定的长度。let hh = 'abc'.padStart(10,'foo') => hh='foofoofabc'
    (5)函数参数列表结尾运行逗号,
    (6)Object.getOwnprototypeDescriptors() 获取对象属性的描述符,没有则返回空对象
    (7)ShareArrayBuffer对象 :原始二进制数据缓存区
    (8)Atomics对象:拥有一组静态方法来对ShareArrayBuffer对象进行原子操作
    
4、ES9
    (1)异步迭代: await和for...in 循环使用, async function pro(arr){for await(let i in arr){}}
    (2)**Promise.finally()**:Promise.resolve().then(()=>{}).catch(e=>e).finally()
    (3)Rest/Spread属性  即参数...
    (4)正则表达式命名捕获组groups、反向断言、dotAll模式
    
5、ES10
    (1)flat():数组扁平化,flatMap()
    (2)String.trimStart()和String.trimEnd() 去除字符串首位空白符
    (3)String.prototype.matchAll() 为所有匹配的匹配对象返回一个迭代器
    (4)Symbol.prototype.description 只读属性,返回Symbol对象的可选描述符的字符串。Symbol('a').description => 'a'
    (5)Object.fromEntries() 返回对象自身可枚举属性的键值对数组
    (6)Catch
    
6、ES11
    (1)?? 表达式在??的左侧求值为null或undefined,返回右侧。let uu ={u2:null,u3:'dada'}
    let u2 = uu.u2 ?? '用户2' => '用户2'; let u3 = uu.u3 ?? '用户2' => 'dada'
    (2)?. 可选链 ,用户检测不确定的中间节点
    (3)Promise.allSettled
    (4)import() 按需导入
    (5)BigInt 新基本数据类型  任意精度的整数
    (6)globalThis:浏览器是window,worker是self,node是global

7、ES12
    (1)replaceAll() 返回一个新的字符串,所有符合匹配规则的字符都将被替换掉 'hello'.replaceAll('l','k') => 'hekko'
    (2)Promise.any() 返回最快响应的数据
    (3)WeakRefs
    (4)逻辑运算符和赋值表达式 a ??= b <==> a=a ?? (a=b)
    (5)数字分隔符 _来分割数字 const money= 1_000_000_000 等价于 const money= 1000000000

18、拷贝

   浅拷贝:
       1.对象:Object.assign(target, ...sources) 
       2.数组:array.slice(0) eg=> let newArr = [1,2,3].slice(0) =>newArr = [1, 2, 3]
       3.数组:concat() => newArr = oldArr.concat(value1,...valuen)
       4.数组:扩展运算符...  newArr = [...oldArr]
   
   深拷贝:
       1._cloneDeep() 在loadsh包里的
       2.jQuery.extend() 
       3.JSON.stringify()  const newObj = JSON,parse(JSON.stringify(oldObj)) 性能最快
       4.循环递归

19、箭头函数

   1、箭头函数表达式没有自己的thisargumentssupernew.target,适用于匿名函数,不能用作构造函数。
   2、语法:(parm1,parm2,...parmN)=>{}
   3、函数的this指向:
       (1)构造函数内,this指向新对象  function Person(){this.age //this指向实例}
       (2)严格模式下,this指向undefined
       (3)如果该函数是一个对象的方法,this指向这个对象,可通过let that = this解决,将this值分配给封闭的变量。
   4、箭头函数不会创建this,只会从自己的作用域链的上一层继承this
   5、call、apply的第一个参数会被忽略,只能传递参数,不能改变this指向,因为没有this6、箭头函数不绑定arguments对象
   7、使用箭头函数可作为方法,如:let obj ={ foo :(a=0)=>a}
   8、箭头函数不能用作构造器,与new同时使用会报错:var F = ()=>{}; var f = new F() 报错!
   9、箭头函数没有prototype属性: F.prototype => undefined
   10、yied关键字不能在箭头函数内使用
   11、返回对象字面量,需要用()括起来 var foo = () =>({foo:1})
   12、可用作闭包
       标准的闭包:function a(){
           let i = 0;
           return function b(){
               return i++;
           }
       }
   13、箭头函数递归:var fact = (x) => (x==0 ? 1 : fact(x-1))
   14function add(a,b){
                return a + b
        }
        等价于箭头函数 const add = (a,b) => a + b

   

20、跨域

   基于同源策略的限制,即同一协议,同一域名,同一端口号,当有一个不满足就会发生跨域,浏览器就会拦截响应的数据。

   (1)jsonp,利用script标签的src属性不受跨域限制的特点,缺点是只支持get请求,有安全问题,返回HTTP状态码,不能解决不同域两个页面的跨域。核心:<script src='url'></script>
        function jsonp(url,jsonpCallback,success){
             const script = document.createElement('script')
             script.src = url
             //script.setAttribute('src', url);
             script.async = true
             script.type = 'text/application'
             window[jsonpCallback] = function(data){
                 success && success.data
             }
             document.body.appendChild(script)
        }
   (2)设置 CORS: Access-Control-Allow-Origin:* 后端
   (3)postMessage:能解决不同域两个页面的跨域。window.postMessage
       otherWindow.postMessage(message,targetOrigin) 发送消息
       window.addEventListener('message',callback,false) 监听消息
   (4)proxyTable: 
      主要原理是利用服务器到服务器没有同源策略的限制,用vue-cli的http-proxy-middleware中间件,这中间件的本质上是在本地开了一个服务器。把浏览器发送的请求转发到代理服务器上,由代理服务器发送请求给目标服务器。
      proxyTable:{
          target:'xxx',     //目标接口域名
          changeOrigin:true, //是否跨域
          pathRewrite:{
              '`api':'api'
          }
      }
   

21、微前端

   价值:解决历史系统难以维护的问题。
   涉及到的方面:
   JS沙箱、CSS隔离、父子应用通信、子应用并行、子应用嵌套、预加载、公共依赖加载、按需加载、HTML Entry、Config Entry。
   框架:qiankun
   
       

22、webSocket、socket、HTTP的区别

  1.socket是对TCP/IP协议的封装,socket本身并不是协议,而是一组调用接口(API),是应用层和传输层之前的一个抽象层。在设计模式中是门面设计,把TCP/IP协议封装在socket接口API里,实现网络的通信。
  2.webSocket是基于HTTP实现的长连接。
  3.socket和webSocket本身是没有关系的。关系点在于:socket是TCP/IP协议的封装,HTTP是基于TCP连接的,所以TCP是核心点和关联点。
   

23、JavaScript的23种设计模式,5大设计原则

  1.创建型:工厂模式、单例模式、原型模式
  2.结构型:适配器模式、代理模式
  3.行为型:策略模式、迭代器模式、观察者模式、命令模式、状态模式
  

24、前端工程化

  目的:为了提高效率和降低开发成本,减少不必要的重复工作时间,而让前端开发能够“自成体系”。
  主要分为四个方面:模块化、组件化、规范化、自动化
      1.模块化:
          JS模块化:CommonJS、AMD、CMD、ES6
              
              模块是能实现特定功能的文件,有了模块方便复用,需要什么模块就加载什么模块。
              
              模块加载加载规范如下:
              CommonJS:主要应用于服务端,node.js,同步加载,由于node.js主要用于服务器编程,模块文件一般都存在于本地硬盘。加载快,不用考虑异步。对象。运行时加载。浏览器端会加载阻塞。
                  基本语法:暴露模块module.export = value;引入模块:require(xxx)
                  加载机制:输入的是被输出的值是拷贝
              AMD:应用于浏览器端,异步加载,requireJS实现AMD规范,主要解决了两个问题
                  1.多个文件有依赖关系,被依赖的文件早于依赖它的文件加载到浏览器
                  2.加载的时候浏览器会停止页面渲染,加载的越多,页面失去响应的事件越长
                  异步加载,不会失去响应,异步依赖。
                  基本语法:暴露模块 define(function(){return 模块});引入模块:require(function(){使用 xxx})
                  缺点:会发送多个请求,引入的js文件顺序不能错
              CMD:专门用于浏览器端,模块的加载是异步的,模块使用时才会加载执行。依赖就近,延迟执行。依赖SPM打包。
              ES6:编译时就确定模块的依赖关系。ES6-Babel-Browserify。输出的是值的引用。
              
          CSS模块化:解决样式私有化、选择器的全局污染、可复用
              1.弱约束:根节点类名,引入LESS、SASS预处理器处理嵌套的样式
              2.私有化:Vue中的Scoped style,仍有被污染的可能
              3.CSS Modules:通过配置webpack里的css-loader和main.js
          资源的模块化:
              万能模块加载理念,资源模块化后的优点:
              1.依赖关系单一化:CSS、图片等资源统一走JS路线,无需处理图片合并、路径问题
              2.资源处理集成化:通过vue-loader
              3.项目结构清晰化:项目结构的函数 dest = webpack(src,config)
              
      2.组件化:页面是个大型组件,拆分成若干个小组件,将HTML、CSS、JS
      
      3.规范化:
          目录结构规范:提高项目的逻辑结构合理性、方便扩展和合作、方便资源的统一定位
          编码规范:HTML规范、CSS规范、JS规范、图片规范、命名规范
          前后端接口规范:
          文档规范:
          组件管理:对应公司业务逻辑存放组件
          git分支管理:封板、打Tag、新建分支、合并生产分支
          Commit描述规范
          视觉图标规范
          
      4.自动化:
          简单机械的重复劳动都让自动化工具去完成。
          图标合并、持续集成、自动化构建、自动化部署
         

25、Web Worker

  现代浏览器为JavaScript创建的多线程环境。可以新建并将部分任务分配到到worker线程并运行,两个线程可独立运行,互不干扰,通过自带的通信机制相互通信。
    const worker = new Worker('work.js')  //创建worder
    worker.postMessage('hello worker')    //主线程向worker线程推送消息
    worker.onmessage = function(event){   //监听worker线程发送过来的消息
        event.data
    }
缺点:无法加载本地资源、同源策略、无法使用document/window/confirm/alert


  

26、babel原理

   babel是一个转译器,转译过程分为三个阶段:parsing(词法分析)、transforming(转译)、generating(生成)
   babel的核心包:
       1.babel-core:转译器本身,提供babel的转译API。webpack的babel-loader就是调用这些API进行转译的。
       2.babylon:js的词法解析器
       3.babel-traverse:用于对AST的遍历,供plugin用
       4.babel-generator:根据AST生成代码
       
   ES6代码转译ES5代码的过程如下:
       1.ES6代码输入 => babylon进行解析js代码词法解析 => 得到AST => 
       2.plugin用babel-traverse对AST树进行遍历转译 => 得到新的AST树 => 
       3.用babel-generator通过AST树生成ES5代码

27、webSocket

   webSocket是一个持久化协议,基于HTTP,解决服务端主动push消息
    var ws = new WebSocket('wss://echo.websocket.org')
    ws.onopen = function(){          //连接成功后的回调函数
        ws.send('hello webSocket')   //向服务器发送数据
    }
    ws.onerror = function(){
                                     //报错时的回调函数
    }
    ws.onmessage = function(){       //收到服务器数据的回调函数
        ws.close()                   //关闭连接
    }

28、时间复杂度、空间复杂度

29、深度优先遍历、广度优先遍历

  树形结构数据,遍历取出需要的值。本质上是时间和空间的相互转换,看时间复杂度和空间复杂度哪个更合适。
  深度优先遍历(depthFirstSearch):自上而下的遍历,采用栈的形式,先进后出。有回溯的操作,相对时间比较长一点。但占用空间少。
  广度优先遍历(breadthFirstSearch):逐层遍历,采用队列的形式,先进先出,时间短,占用空间大。
  引发问题:递归版本的BFS由于层级太深,会导致堆栈溢出:Maximum call stack size exceeded,这是由于空间内存占用问题,改为DFS即可。
  

30、call/apply的区别

   call和apply都属于Function.prototype的一个方法,它是JavaScript引擎内实现的,每个函数方法都有这个call和apply属性,所以一定是调用的函数方法。
   作用:改变this指向。
   区别:参数不同,call的参数需要逐个列举,apply是一个参数数组
   数组的合并:Array.prototype.push.apply(arr1,arr2)
   取数组中的最大值:Math.max.apply(null,arr1)

31、BOM(浏览器对象模型)

window、navigator、screen、history、location

window的方法总结:
navigator的方法总结:
screen的方法总结:

32、eval()

   1.将传入的字符串当做JavaScript代码执行,eval(string)
   2.由于参数string的形式有多种情况,字符串、数字、函数表达式,json
   3.如果是表达式,会对表达式求值。
   4.不使用eval()函数的理由:
       (1)安全问题:eval()运行的代码被恶意修改,并通过作用域形成不同的攻击
       (2)执行速度:eval()必须调用JS解析器转成机器代码,强制浏览器进行冗长的变量名称查找,以确定其位置并设置其值,然后强制浏览器重新已经生成的机器代码以进行补偿。
       (3)会报错:产生混乱的逻辑代码
       (4)不利于SEO
                    

33、 算法:排序

34、 算法:去重

35、 斐波那契数列(递归算法)爬楼梯

36. 函数式编程

37. Even Loop(JS运行机制)

    1.进程和线程
        CPU是计算机的核心,承担所有的计算任务
    进程:CPU资源分配的最小单位
    线程:CPU调度的最小单位
    
    进程是操作系统分配资源的最小单位,线程是程序执行的最小单位
    一个进程由一个线程或多个线程组成,线程可理解为是一个进程中代码的不同执行路线
    
    进程之间相互独立,但同一个进程下的线程间共享程序的内存空间(代码段、数据集、堆)及一些进程级的资源(如打开文件和信号)
    
    调度和切换:线程上下文切换比进程上下文切换要快得多
    
    JS是单线程,JavaScript的主要用途是与用户互动以及操作DOM
    
    浏览器是多进程
    浏览器包含4个进程:
    1.Browser进程
    2.第三方插件进程
    3.GPU进程
    4.渲染进程
    
    渲染进程Renderer:页面渲染、JS执行、事件循环
    渲染进程Renderer的主要线程:
    1.GUI渲染线程
    2.JS引擎线程
    3.事件触发线程
    4.定时器触发线程
    5.异步HTTP请求线程
    
    自己的理解:
    JS引擎是单线程的,但是浏览器是多线程的
    JS引擎按照执行上下文自上而下执行主线程调用栈里任务,当执行上下文清空时,就会不断轮询访问微任务队列,进行一个microtask checkPoint,而微任务队列里的比如promise的异步任务是放在异步http请求线程里,当返回回调函数,就把这个微任务放进微任务队列里,这个时间可早于checkpoint也可能晚于checkpoint。然后直到清空所有的微任务队列,此时保存在队列中被挂起的GUI渲染线程,看到JS引擎线程空闲,就立即开始执行 UI Rendering。用户就可以看到DOM的更新渲染。
    

    浏览器单线程
    等待的任务挂起,
    同步任务、异步任务
    同步任务:排队执行,主线程执行,形成执行栈
    异步任务:不进入主线程,进入任务队列的热任务,回调函数,
    宏任务:script、setTimeout、setInterval、setImmediate、I/O、UI Rendering、postMessage、RequestAnimationFrame
    微任务:promise、process.nextTick(node环境的方法)、object.observe、MutationObserver
    
    知识点:
    1. 在一轮Event Loop中多次修改同一DOM,只有最后一次会进行绘制
    2. 更新渲染(update the rendering)会在宏任务task和微任务microtasks完成后进行。浏览器会根据是否修改DOM或者有无必要更新状态去进行渲染。顺序是**task**->**microtasks**->**rendering**
    3. 微任务存在的原因:反复修改DOM或者进行大量计算,同步就会有大量的任务一一执行,异步放入微任务里可以缓存和优化性能,过滤了多余的计算并只执行最后一次的修改。所以dom变动放在微任务里比放在宏任务里更快的变化呈现给用户。
    4. 执行上下文为空时,进行微任务检查点(a microtasks checkpoint)
    5. 更新渲染是发生在GUI渲染线程,它与JS引擎线程是互斥的,GUI渲染线程会被保存在一个队列中,当JS引擎线程空闲时,即宏任务-微任务之后,立即执行GUI渲染线程。
    6. vue的nextTick的回调函数可以获得最新的DOM,但是基于 Task - microtasks - UI Render,UI渲染是在微任务之后执行,nextTick的本质是microtasks,只是它会在执行时立即追加到执行队列里,此时DOM更新,但是UI未渲染。
    7. 一个Event Loop有一个或多个task队列。本质是浏览器和nodejs的区别,在浏览器里一个Loop只有一个宏任务队列,但是在nodejs里有不同的macrotask:
    (1)timers queue:setTimeout和setInterval的回调。
    (2)IO queue:用户输入的回调,如键盘、鼠标。
    (3)check queue:setImmediate的回调。
    (4)close callback queue:关闭回调的函数,如socket.on('close')
    nodejs里的宏任务运行规则:检查当前宏任务队列是否还有任务,有则取出放入主线程执行栈中执行,没有就取下一个宏任务队列里的任务。
    nodejs里的微任务运行规则:由于nodejs里有两个微任务队列(1.nextTick queue:是放置process.nextTick的回调任务的。2.other queue:放置其他微任务,如promise),两个微任务队列也是按队列顺序依次执行。
    nodejs的Event Loop执行顺序:
    1. 先执行全局script代码。
    2. 执行完同步代码调用栈清空后,先从微任务队列nextTick queue依次取出所有微任务放入调用栈执行,然后再依次取出other Microtask的所有微任务放入调用栈执行。
    3. 然后开始宏任务,将当前宏任务队列里的所有宏任务都取出来执行。(浏览区只执行一个宏任务)
    4. 然后再执行微任务。
    
    8.整个script是一个主任务, setTimeout 是一个macroTask, promise的回调是microtask, 顺序是:
     主script(第一个主任务) —> microTask (全部执行完)—> UI渲染 —> 下一个macroTask
     
    9. JavaScript有一个主线程main thread和调用栈call-stack,称之为执行栈。所有的任务都是通过放入调用栈等待主线程执行。

    
    事件轮询Event Loop
    1.整体代码是第一个宏任务,代码分为两部分:同步任务、异步任务
    2.同步任务在主线程执行,形成一个执行栈
    3.异步任务分为宏任务(代码script/setTimeout/setInterval)、微任务(promise.then/ promise.nextTick),任务队列
    4.宏任务在事件注册表中注册回调函数,事件完成,移到事件队列
    5.微任务在事件注册表中注册回调函数,事件完成,移到事件队列
    6.主线程任务执行完毕,主线程为空,检查微任务,如果有,清空。没有就执行下一个宏任务
    7.循环

38. Object方法总结

39. 同源策略

40. 回流和重绘

41. 模块化开发,CommonJs/AMD/CMD

42. 缓存

43. 优化:前端优化、首屏优化

    1.路由懒加载   vue-router:require.ensure 按需加载,创建chunk
    2.webpack图片压缩  webpack.base.conf.js => module/rules/limit:10000
    3.若静态资源放在CDN上,用gzip压缩  Nginx的配置
    4. 雪碧图、图片预加载
    5. destroy组件销毁,定时器销毁,解除绑定
    6. v-if、v-show
    7. 分页、懒加载
    8、defer、async1) 减少http请求次数:CSS Sprites, JSCSS源码压缩、图片大小控制合适;网页GzipCDN托管,data缓存 ,图片服务器。

(2) 前端模板 JS+数据,减少由于HTML标签导致的带宽浪费,前端用变量保存AJAX请求结果,每次操作本地变量,不用请求,减少请求次数

(3) 用innerHTML代替DOM操作,减少DOM操作次数,优化javascript性能。

(4) 当需要设置的样式很多时设置className而不是直接操作style。

(5) 少用全局变量、缓存DOM节点查找的结果。减少IO读取操作。

(6) 避免使用CSS Expression(css表达式)又称Dynamic properties(动态属性)。

(7) 图片预加载,将样式表放在顶部,将脚本放在底部  加上时间戳
        
        
        
        
        
### 44. npm模块安装机制
### 45. this指向
### 46. 前端日志

### 47、JavaScript二进制、八进制、十六进制 

     二进制:以0B、0b开头
     八进制:以0、0O、0o开头
     十六进制:以0X、0x开头
     
### 48、toString()的用法
  
      1.Number转进制,格式:number.toString(radix) ,radix值范围是2-36之间的整数,默认值10,除10以外的其他值可返回任意值。返回值都是字符串!!
      2.判断类型,格式:Object.prototype.toString.call(x),判断x类型,"[object String]"
      3.数组返回字符串,格式:Array.toString(),一维或多维没有键值对的数组会返回数组元素的字符串
      4.null /undefined 报错
      5.1..toString()可返回字符串或者(1).toString(),原因是JavaScript解析器把1.解析为一个数字类型。

### 49、vue项目打包后的dist目录详解
   
       一共两个文件夹
       1.css文件夹:
         app.xxx.css文件:css样式文件
         app.xxx.css.map文件:是一个存储css代码位置信息的文件
       2.js文件夹
         app.xxx.js:项目中各个页面的逻辑代码
         app.xxx.js.map
         manifest.xxx.js:webpack打包生成的配置文件=>views
         manifest.xxx.js.map
         vendor.xxx.js:页面各个组件公用的代码=>components
         vendor.xxx.js.map:
       3.index.html
         前端代码入口的html文件
         
### 50、函数式编程 :原理、应用场景、常见库、实战
       
### 51、CDN

     CDN的全称是Content Delivery Network,即内容分发网络