Fetch API / AJAX
ES6
迭代器模式
只要部署了Symbol.iterator接口的则都可以为迭代器使用迭代器优势:可以使用break/continue/return配合使用可以使用迭代器模式的7大数据结构:Array、Map、Set、String、TypedArray、函数的 arguments 对象、NodeList 对象let it = arr[Symbol.iterator]();console.log(it.next()); // {value: 1, done: false}console.log(it.next()); // {value: 2, done: false}console.log(it.next()); // {value: undefined, done: true}
模块化
循环
效果一致for (let strong of strongElements) {strong.className = "important";}for (let i = 0; i < strongElements.length; ++i) {strongElements.item(i).className = "important";}for (let i = 0; i < strongElements.length; ++i){strongElements [i].className = "important";}matches方法返回元素是否可以被querySelector或querySelectorAll返回if (document.body.matches ("body.page1")){// true}
Prototype-原型链
- JavaScript中每个构建函数都有一个prototype属性,它指向原型对象,原型对象中有一个constructor属性指回构造函数,当使用构造函数创建实例时,实例proto属性指向该构造函数的prototype原型对象

- 原型链:当试图去访问一个实例的属性/方法时,会优先在该实例对象本身进行查找,实例本身没有则往实例的原型上进行查找,如果实例原型也没去,则再到实例原型的原型上查找,这个查找过程形成的链路称为原型链
Shadow DOM-沙箱DOM
- webcomponent,提供沙箱环境
- 组件间的通信
- customEvent自定义事件
设计模式
开放封闭原则:开放(对拓展开放)、封闭(对修改封闭)
设计模式的核心在于找到逻辑里的变与不变,将这两者抽象分离出来
创建型
工厂模式-简单工厂
- 以工厂模式创建用户为例,可变的是用户的姓名、身高、体重这些值,不变的是这些属性他们都有
工厂模式就是将创建对象的过程进行封装
let User = function(options){this.name = options.namethis.age = options.agethis.role = options.rolethis.work = options.work}let Factory(name, age, role) {let workswitch(role) {case: 'manage'work = '管理工作,分发需求'case: 'developer'work = 'coding'case: 'product'work = '原型工作'}return new User(naem, age, work, role)}
b. 单例模式
保证一个类只有一个实例,并提供一个它的全局访问实例
- Vuex使用单例模式为全局提供一个Store状态对象,避免install安装插件时覆盖Store ```javascript // 实现单例模式 class SingleUser { static getInstance(){ if (!SingleUser.instance) { SingleUser.instance = new SingleUser() } return SingleUser.instance } } let s1 = SingleUser.getInstance() let s2 = SingleUser.getInstance() s1 === s1 // true
// 通过闭包实现 SingleUser.getInstance = (function(){ let instance return function(){ if (!instance) { instance = new SingleUser() } retrun instance } }())
// 使用单例创建一个模态框 let Modal = (function(){ let modal return function(){ if (!modal) { modal = document.createElement(‘div’) modal.innerHTML = ‘全局唯一模态框’ modal.id = ‘#modal’ modal.style.display = ‘none’ document.body.appendChild(modal) } return modal } }()) // 显示 button.onclick = () => { const modal = new Modal() modal.style.display = ‘block’ } // 隐藏 button.onclick = () => { const modal = new Modal() modal.style.display = ‘none’ }
1. 策略模式<br />结构if else使用,算法分发逻辑strict-严格模式1. 使用上:在JS文件的最顶层,或者在函数体的首行,否则无效1. 常用的特点:1. 不允许使用隐式声明变量,报错1. 不允许函数有相同的参数,对象有相同的属性1. 不允许对只读属性赋值操作1. 禁止this指向window,this为undefined1. 增加了限制,使得静态绑定,助于提高编译效率1. 对一些保留字不允许声明、inteface、let、package等浏览器如何工作DNS- DNS:提供域名到IP的解析服务- DNS的查找过程:本地host、本地DNS服务器、再往上层DNS服务器查找、直到DNS根服务器返回域名,浏览器再向服务器进行TCP连接再进行请求<a name="5JO4M"></a>## HTTP基本概况1. 1990年提出HTTP协议-万维网之父Tim Berners-Lee1. 1991年HTTP0.9诞生1. 1996年HTTP1.0发布1. 1997年HTTP1.1发布1. 2015年HTTP2.0提出1. HTTP3.0QUIC协议TCP/IP协议族1. TCP/IP协议族是由一个四层协议组成的系统,这四层分另为:应用层、传输层、网络层和数据链路层HTTP的数据传输过程<br /> 1. 发送端发送数据时,数据会从上层传输到下层,且每经过一层都会被打上该层的头部信息。而接收端接收数据时,数据会从下层传输到上层,传输前会把下层的头部信息删除2. TCP是如何建立连接的1. 使用TCP协议进行通信的双方必须先建立连接,然后才能开始传输数据。为了确保连接双方可靠性,在双方建立连接时,TCP协议采用了三次握手策略1. 第一次握手:客户端发送带有SYN标志的连接请求报文段,然后进行SYN_SEND状态,等待服务端确认1. 第二次握手:服务端接收到客户端的SYN报文段后,需要发送ACK信息对这个SYN报文段进行确认。同时,还要发送自己的SYN请求信息。服务端会将上述信息放到一个报文段中(SYN+ACK),一并发送给客户端,此时服务端进入SYS_RECV状态1. 第三次握手:客户端接收到服务端的SYN+ACK报文段后,会向服务端发送ACK确认报文,这个报文段发送完成后,客户和服务端都进入Established状态,完成TCP三次握手1. 为什么要使用三次握手:客户端第一次发送,服务端知道客户端的发送能力,服务端第二次发送是告诉客户端自己的接收能力和发送能力,发出第二次后依然不知道客户端的接收能力,所以需要客户端进行第三次发送,类似于两个人之间寄信,往返三次才知道相互都能接收和发送3. HTTP协议的特点1. 无状态1. 没有记忆能力,缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大,优点是:无状态,解放了服务器,缺点是每次请求都会传输大量重复的信息2. 长连接2. 短连接4. URL与URI的区别与联系1. URN作用就好像一个人的名字1. URL就像一个人的地址1. URI5. HTTP报文结构1. 请求头1. 请求体1. 响应报文6. HTTP/1.1 常用方法:8种1. GET1. 请求url的长度注意有限制1. IE:2083、firfox:65536、chrome:8182、safair:800002. POST1. 主要的目的不是获取响应主体的内容1. 相对GET更安全一点,在公共场所历史记录可以看到GET上请求的数据,POST看不到1. 提交数据放到body里面,get放到url上面1. POST请求没有大小限制1. 无论GET、POST都可以通过抓包看到数据3. PUT1. 更新资源,有漏洞4. HEAD1. <br />5. DELETE1. 删除资源,有漏洞6. OPTIONS1. 查询请求URI指定的资源支持的方法1. Allow:是显示支持的方法7. TRACE1. 回显服务器收到的请求,主要用于测试或诊断8. CONNECT1. 开启客户端与所请求资源之间的双向沟通通道7. HTTP状态码1. 2xx1. 200:成功1. 206:返回部分内容1. 除此之外的2xx:基本都是接收成功,但服务器未处理2. 3xx:重定向1. 301:永久移动,请求的资源已被永久的移动到新的URI,返回信息包括新的URI,浏览器会自动定向到新URI,今后任何新的请求都应使用新的URI代替1. 302:临时移动,与301类似,但资源只是临时被移动,客户端应继续使用原有URI1. 307:临时重定向,与302的区别是,使用同样的请求方法去请求资源,一般用于网站支持http、https两种协议下,用户使用了http去访问,需要重定向到https的情况下会返回3. 4xx:客户端请求导致的错误1. 400:客户端请求的语法错误,服务器无法理解1. 401:请求要求用户的身份认证1. 403:服务器理解请求,但拒绝处理1. 404:服务器找不到客户端请求的资源4. 500:服务器引起的处理1. 500:Internal Server Error:服务器内部错误,无法完成请求1. 502:Bad Gateway:充当网关或代理的服务器,从远端服务器接收到了一个无效的请求9. HTTP如何做状态管理:Cookie与Session1. Cookie1. cookie实际上是一小段的文本信息,客户端请求服务器,如果服务器需要记录该用户状态,就向客户端游览器颁发一个Cookie1. 客户端再次请求时把cookie一同提交给服务器,服务器以此来辨认用户状态1. cookie保存在客户端2. Session1. 通过Cookie保存session id1. URL重写:http:xxx?sessionid:xxxabcd1234(防止客户端禁用cookie)1. session id保存在服务端,保存在一张表里,对服务器的压力大一些10. HTTP中的编码与解码1. 编码规范:包括字库表、字符集、编码方式1. 字库表:比如GBK存储了所有中文,但是没有法语、俄语等,UTF8存储了非常多语言1. 字符集:与字库表一一对应2. 乱码的由来1. 编码和解码所使用的编码方式不一致11. HTTP协议基本认证1. BASIC认证:基本认证1. DIGEST认证:比基本认证加强一些1. SSL客户端认证是基于HTTPS认证证书:成本较高1. 基于表单的认证:更多使用的是这种方式12. HTTP的长连接与短连接1. HTTP协议是基于请求/响应模式的,服务端给了响应,HTTP请求就结束了1. HTTP的长连接和短连接本质上是TCP长连接和短连接1. HTTP1.0都是短连接1. HTTP1.1默认开启长连接:connection: keep-alive,长连接可以节约TCP建立连接和关闭的时间,对于频繁请求有一定优势,但也存在一个问题,过多的长连接导致服务端连接占用,服务端可以采取一些策略,将长时间无请求状态的连接进行关闭,在不同场景下有不同的策略13. HTTP代理1. 代理对于web客户端来说,代理是服务器的角色,接收请求,响应请求1. 对了web服务器来说,代理是客户端的角色,发送请求,响应请求<br />c. 作用:匿名访问、抓包、外网、过滤内容14. HTTP缓存1. 为什么要有HTTP缓存:缓存可以节约用户与服务器流量、减少服务器HTTP请求,提高页面渲染性能1. 缓存的内容:主要是CSS、JS、图片等静态资源1. HTTP协议主要通过请求头和响应头来控制15. 缓存场景1. 场景一:服务器与浏览器约定一个文件过期时间-Expires1. 通过响应头Expires设置文件响应过期时间,有个问题:服务器会接收到这个请求吗?不发起请求2. 场景二:过期时间到了,该怎么办1. 服务器给浏览器文件时,除了给个过期时间Expires(1.0的字段),再给了一个Last-Modified,如果过期时间到期了,浏览器加上一个请求头:if-Modified-Since(GMT)取Last-Modified时间发送给服务器,服务器进行文件时间对比,如果时间不相等,则重新返回新的文件,及Expires和Last-Modified,如果对得上则服务器返回3041. 场景二使用的缓存策略是存在问题:Expires是客户端与服务端返回的时间做对比,如果客户端的时间被更改,则缓存策略基本无效,第二、Last-Modified只能感知文件变更时间为秒,如果文件在1秒内发生变更,则新文件无法被重新请求3. 场景三:针对Expires有漏洞,所以推出了文件内容唯一对比标记:Etag与if-None-Match以及max-age1. Cache-Control: max-age=2592000,当服务器返回max-age时,则浏览器在设定时间内(秒)不再发起请求,当max-age存在时,expires则被忽略了,因为max-age优先级高1. 当max-age的时间到达后,浏览器请将if-None-Match与服务端的Etag进行对比,Last-Modified不再进行对比,因为Etag优化级高于Last-Modified,Etag就是为了解决文件1秒内变动的问题,如果Etag不相等,则服务器返回新的文件以及新的max-age缓存,也会顺便把Etag和Last-Modified给客户端,虽然没什么用,如果Etag没有变,则返回304,继续使用浏览器的缓存4. 以上三种场景都存在一个问题,如果文件有变更,缓存时间未过期,则浏览器不会向服务器请求新的文件,所以通过为静态文件添加MD5或者Hash标识,解决浏览器无法跳过缓存过期时间主动感知文件变化的问题4. 继续通过CDN来解决缓存问题1. CDN有效的分发了源服务器的请求压力1. CDN同时也为用户分配了就近的服务器,使用户访问更快1. CDN不同于服务器是可以手动进行缓存清除,如果请求资源缓存时间没有过期,则浏览器还是使用缓存的文件,CDN不会返回最新的变更文件6. Ctrl+F5:浏览器所有的缓存策略失效,强制向服务器请求最新文件16. HTTP内容协商1. 通过请求头和响应头Accept、Accept-Encoding、Accept-Language、Accept-Type与响应头Content、Content-Encoding、Content-Language、Content-Type一一对应来进行协商1. Content-Language通过权重来使用多种语言:en;q=0.5, fr;q=0.0, nl;q=1.0,语言协商用得比较多17. HTTP断点续传与多线程下载HTTPS1. HTTP1. 缺点:明文传输,相当于在互联网裸奔1. 数据有可能被篡改2. HTTPS:使用密钥进行加密传输,可以认为是HTTP+TLS,TLS是传输层加密协议,前端是SSL协议2. HTTPS使用成本1. 证书费用以及更新维护1. HTTPS降低用户访问速度,也可以通过优化来解决,提高了优化成本1. 消耗CPU资源,需要增加大量机器<a name="wmDc5"></a>## 安全模块1. 日常的安全问题1. 为什么我们登录的时候经常要求我们输入一个验证码1. 验证码技术1. 常规的数字字母验证码,第三方可通过OCR进行识别破解,提高识别难度为汉字或谷歌那样的,太难破解1. 通过cookies设置failLogin=0,依次递增,当达到5次时服务器拒绝当前登录,然而没有用,客户端可以更改cookies值1. 双因子认证:what you know你知道什么,what you have你有什么,你知道账号密码,你有验证码来达到双重认证1. 忘记密码先验证是否是用户本人;通常网站设计有三种方式来认证用户1. 用户设定的安全问题1. 用户注册时留下的安全邮箱1. 给预留手机号发送验证码短信3. 在一个网站上长时间没有操作,为什么session会失效1. 常时间没有操作,服务器会认为用户本人已经离开,避免他人使用你的令牌,session,所以需要重新登录4. 假如地铁拥堵现象严重,有什么办法可以解决1. 扩容:增加地铁线1. 地铁时间运行缩短,由两分钟缩短到一分钟1. 限流:和汽车一样对人口进行限流1. 分流:提升准入标准、票价提高5. 典型的身份验证模式讨论6. web应用程序没有或很少对用户密码强度进行控制1. 非常短或空白密码1. 以常用字典词汇为密码(password、123456)1. 密码与用户名完全相同1. 长时间使用默认密码7. XSS:跨站脚本攻击,分为三大类1. 反射式XSS1. 存储式XSS1. 基于DOM的XSS<a name="LmSDs"></a>## JS基础1. 0.1 + 0.2 = 0.300000000000000041. 原因:计算机在进行计算时需要将十进制转换为二进制1. 0.1转换为二进制时,无法完整表示,进入了无限循环,而计算机存储是有限的,所以截取了一部分值1. 0.2转换为二进制,也无法完整表示,也同样进入无限循环,所有支持浮点数运算的语言都无法精确表示0.1+.02```javascript0.8125转换为二进制0.8125 * 2 = 1.625 取整:10.625 * 2 = 1.25 取整:10.25 * 2 = 0.5 取整:00.5 * 2 = 1 取整:1从上向下读数:0.8125转换为二进制结果为:0.1101
typeof 与 instanceof的区别
- typeof对所有对象类型都返回object
- Object.prototype.toString.call(a)也有一个缺点,不能校验自定义类
- instanceof只能校验是否是属于某个实例的,原型类型校验不出来
- ‘abc’ instanceof String : false 等价写法:StringSymbol.hasInstance
- 2 instanceof Number : false
JS的基本类型
- 原始类型:number string boolean null undefined symbol
- 原始类型本身不可更改:let str = ‘abc’ str[0] = ‘d’ // 不可改变
- 对象类型:object
- 原始类型:number string boolean null undefined symbol
- 号的两大作用:运算、字符串拼接
- 如果有一方为字符串,则认为是字符串拼接
- 数字和null相加:1 + null = 1
- 数字和字符串相加:1+ ‘a’ = NaN
- 数字和undefined相加:1 + undefined = NaN
- 数字和字符相加:1 + {} = 1’[object Object]’
- 数字和函数相加 1+ function(){} = 1’function(){}’
- 数字和数组相加 1 + [] = ‘1’
- 1 + +’123’ = 124,后面的加把字符串进行了转换
- typeof 1 + +’a’ = ‘number’
let obj = {[Symbol.toPrimitive](){retrun ...}valueOf() {return {}},toString() {return ...}}与对象类型相加时,会优先调用对象的valueOf方法,如果valueOf方法返回的还是对象,则再调用对象的toString方法,当然也可以声明Symbol.toPrimitive方法,优先级最高
比较运算:< = >
- 数字与另一方比较,如果另一方能转换成数字成正常比较,如果不能转换成数字,则直接返回false
- 1 < ‘12’ = true;
- 字符串与字符串进行比较,则取其Ascll码进行比较;
- ‘a’.charCodeAt(0) // 97; ‘b’.charCodeAt(0) // 98; 只比较第一位,’aa’ < ‘b’ = true
- 其它比较
- null == undefined = true
- null、undefined和其它进行比较的时候都为 false
- {} == {} = false
- {} 和基本数据类型比较的时候,会把对象转换为原始数据类型 toString 方法后再进行比较
- [] == [] = false; [] = ![] = true;!先进行了数字转换
模拟new实现
function MockNew(){let Constructor = [].shift.call(arguments)let obj = {}obj.__proto__ = Constructor.prototype // 继承原型上的方法let r = Constructor.apply(obj, arguments); // 需要让构造函数执行,// 因为构造函数中如果返回对象类型,则不再返回thisreturn r instanceOf Object ? r : obj}let animal = mockNew(Animal, '哺乳类')
事件循环
- Event Loop:就是执行任务和等待休眠状态的无限循环,有任务时,从最先进入的任务开始执行,引擎执行任务时,永远不会渲染DOM,执行完成后才会进行对DOM的更改
拆分CPU过载任务
- 避免任务执行时间过长,页面无响应,可以使用setTimeout将任务进行拆分,虽然时间设置为0,但浏览器最小的延时时间依然为4ms
- 拆分同时可以获取并显示进度
let i = 0;function count() {do {i++;dom.innerHTML = i;} while (i % 1e3 != 0);if (i < 1e5) {setTimeout(count);}}count();
-
节流防抖
节流:多少时间内触发一次
防抖:不停的触发,只触发最后一次
// 节流:使用requestAminationFrame实现节流,50ms执行一次function expensiveOperations() {console.log('scroll change: ')}let enable = truewindow.addEventListener('scroll', () => {if (enable) {enable = falsesetTimeout(() => (enable = true), 200)window.requestAnimationFrame(expensiveOperations)}})
尾调用、尾递归
某个函数的最后一步是调用另一个函数
- 递归非常耗费内存,因为需要同时保存成千上百个调用帧,很容易发生“ 栈溢出 ”错误(stack overflow )。但对于尾递归来说,由于只存在一个调用帧,所以永远不会发生“ 栈溢出 ”错误 ```javascript // 尾调用优化过后的尾递归 function Fibonacci2 (n , ac1 = 1 , ac2 = 1) { if( n <= 1 ) {return ac2}; return Fibonacci2 (n - 1, ac2, ac1 + ac2); } Fibonacci2(100)
// 尾调用,最后一行执行代码不能有运行,只能返回一个纯函数调用 function f(x){ return g(x); }
<a name="MULqP"></a>## 页面生命周期(DOMContentLoaded)1. DOMContentLoaded:浏览器已完全加载HTML,并构建了DOM 树,但像img和样式表之类的外部资源可能尚未加载完成,只能使用document.addEventListener进行监听1. 具有async以及document.createElement('script')动态创建的脚本不会阻塞DOMConentLoaded1. 特例:如果link外链表下面存在脚本,脚本也会等待样式表加载完成,所以也会阻塞DOMConentLoaded1. 浏览器自动填充账号密码也是在这个事件之后执行的2. load事件:浏览器完成了DOM渲染,所有资源图片、样式等加载完成2. 页面离开时触发的重要事件(主要使用这两个事件,pagehide\unload不使用)1. visibilitychange:页面不可见时触发,兼容PC移动两端1. 清除轮询、停止动画、操作音视频等1. document.visibilityState === 'hidden' 页面离开1. document.visibilityState === 'visible' 页面可见2. beforeunload:页面即将要离开时触发1. 一般对于页面编辑过后未保存,表单未保存时做的提示1. 可以系统弹出pop阻止关闭<a name="8gTs9"></a>## 重绘回流1. 重绘:渲染树中的元素更改属性,但不影响布局,比如background color等称为重绘1. 回流:任何会改变元素几何信息(元素的位置和尺寸大小) 的操作, 都会触发回流。(1) 添加或者删除可见的 DOM 元素;<br />(2) 元素尺寸改变——边距、 填充、 边框、 宽度和高度<br />(3) 内容变化, 比如用户在 input 框中输入文字<br />(4) 浏览器窗口尺寸改变——resize 事件发生时<br />(5) 计算 offsetWidth 和 offsetHeight 属性<br />(6) 设置 style 属性的值<br />(7) 当你修改网页的默认字体时3. 回流必定会发生重绘, 重绘不一定会引发回流3. 避免回流重绘的一些优化点a. 避免频繁操作样式,最好一次性重写`style`属性,或者将样式列表定义为`class`并一次性更改`class`属性<br />b. 对具有复杂动画的元素使用绝对定位,使它脱离文档流,否则会引起父元素及后续元素频繁回流<br />c. 避免使用table布局,因为改动一个元素可能导致整个table回流<a name="coac8"></a>## 前端需要注意哪些 SEO1. 合理的 title、 description、 keywords: 搜索对着三项的权重逐个减小, title 值强调重点即可, 重要关键词出现不要超过 2 次, 而且要靠前, 不同页面 title 要有所不同; description把页面内容高度概括, 长度合适, 不可过分堆砌关键词, 不同页面 description 有所不同;keywords 列举出重要关键词即可。1. 语义化的 HTML 代码, 符合 W3C 规范: 语义化代码让搜索引擎容易理解网页。1. 重要内容 HTML 代码放在最前: 搜索引擎抓取 HTML 顺序是从上到下, 有的搜索引擎对抓取长度有限制, 保证重要内容肯定被抓取。1. 重要内容不要用 js 输出: 爬虫不会执行 js 获取内容1. 少用 iframe: 搜索引擎不会抓取 iframe 中的内容1. 非装饰性图片必须加 alt1. 提高网站速度: 网站速度是搜索引擎排序的一个重要指标<a name="TPFBW"></a>## 前端存储1. cookie1. session storage1. local storage1. 大规模存储1. indexDB1. web SQL(废弃)5. 缓存1. cache storage1. application cache6. SessionStorage, LocalStorage, Cookie 区别1. 这三者都可以被用来在浏览器端存储数据, 而且都是字符串类型的键值对。 区别在于前两者属于 H5 WebStorage, 创建它们的目的便于客户端存储数据。 而 cookie 是网站为了标示用户身份而储存在用户本地终端上的数据( 通常经过加密)。 cookie 数据始终在同源( 协议、 主机、 端口相同) 的 http 请求中携带( 即使不需要), 会在浏览器和服务器间来回传递。1. 大小1. cookies:4K1. SessionStorage, LocalStorage:一般为5M3. 有效时间:1. localStorage 存储持久数据, 浏览器关闭后数据不丢失除非主动删除数据。1. sessionStorage 数据在页面会话结束时会被清除。 页面会话在浏览器打开期间一直保持,并且重新加载或恢复页面仍会保持原来的页面会话。 在新标签或窗口打开一个页面时会在顶级浏览上下文中初始化一个新的会话。1. cookie 设置的 cookie 过期时间之前一直有效, 即使窗口或浏览器关闭。由expires属性设置<a name="RAWC4"></a>## 正则表达式1. 正则方法1. reg.test1. reg.exec2. 字符串支持的正则方法1. str.match(reg)1. str.replace(reg, replacement)1. str.search(reg)1. str.split(reg)3. 分组:将()内的看成一块整体1. 非捕获括号:如果不想使用全局API引用括号内的分组,可以使用?:(?:ab)```javascriptconst reg = /(ab)+/gconst str = 'abab aba abababa'console.log(str.match(reg)) // ["abab", "ab", "ababab"]
- 分支结构:(|) ```javascript const reg = /^I love (JavaScript|Node.js )$/ console.log(reg.test(‘I love JavaScript’)) // true console.log(reg.test(‘I love Node.js’)) // true
// 提取年月日数据 const reg = /(\d{4})-(\d{2})-(\d{2})/ const str = ‘2021-01-02’ str.match(reg) 或者 reg.exec(str) 或者 RegExp.$1, RegExp.$2, RegExp.$3 [“2021-01-02”, “2021”, “01”, “02”, index: 0, input: “2021-01-02”, groups: undefined]
// 全局属性$1-$9需要使用正则调用一遍 regex.test(string); //regex.exec(string); //string.match(regex);
4.1 - replace使用```javascript// 年月日格式替换const date = '2021-02-12' => '02/12/2021'const reg = /(\d{4})-(\d{2})-(\d{2})/date.replace(reg, '$2/$3/$1')data.replace(reg, function(){return RegExp.$2 + '/' + RegExp.$3 + '/' + RegExp.$1})data.replace(reg, function(match, year, month, day){return month + '/' + day + '/' + year})
反向引用:\1\2…引用之前已经出现的分组
const date1 = '2021/01/12'const date2 = '2020.01.12'const date3 = '2020.01/12'const reg = /^\d{4}(\/|\.)\d{2}(\/|\.)\d{2}/reg.test(date3) => true\1 代表第一个分组,两个匹配结果完全一致const reg = /^\d{4}(\/|\.)\d{2}\1\d{2}/reg.test(date3) => false
History
go、back、forward、state、length
- pushState、replaceState
- window.addEventlistener(‘popState’)
安全-XSS
- 反映型XSS,用户输入什么,页面就返回什么,不经过处理,输入的有可能是脚本
- 问题主要在于服务端未进行字符串编码 ```javascript
- 通过获取url的参数,未经处理直接返回给前端页面 http://localhost:3000/index.html?type=
- 获取到用户的cookie http://localhost:3000/index.html?type=
encodeURIComponent编码字符串中的特殊字符,decodeURIComponent解码已经编码过的特殊字符 encodeURIComponent(‘http://www.cc/my test.asp?name=ståle&car=
‘) ``` DOM-Based型
- 问题主要在前端,改变原有DOM结构,会造成攻击
$(box).innerHTML(`<img src=${encodeURI(${input}.val())}>`)<img src=""><srcipt>alert(1)</script><img src="xxx" onerror="alert(1)">
- 问题主要在前端,改变原有DOM结构,会造成攻击
存储型
- 比如将评论的内容未经转换发送到服务器,服务器存储起来,后来所有用户都可以访问到这个评论,造成所有用户的攻击
解决方案
单功:单向通信
- 半双功:单双向通信
双功:全双向通信
- 轮询:定时向服务器请求数据
- 长轮询:服务器数据返回时才再去请求
- iframe子框架内嵌轮询:服务器不关闭请求,一直向浏览器写入新数据
- 缺点:浏览器一直处于转圈圈状态,可以实现需求
<iframe src="/requestTime">// serverapp.get('/requestTime', (req, res) => {req.setHeader('Content-type', 'text/html')setInterval(() => {res.write(`<script>parent.setTime(${new Date().toLocalString()})</script>`)}, 1000)})
- 缺点:浏览器一直处于转圈圈状态,可以实现需求
EventSource
- 在简单的服务端推送场景下可以满足需求,连接后服务端向浏览器端推送,前端不能推送到服务器端
- 需要设置自定义响应头,告诉浏览器
let event = new EventSource('/message')event.onmessage = function(event) {return event.data}event.onerror = function(err) {console.log(err)}// serveapp.get('/message', function(req, res){res.header('Content-Type', 'text/event-stream')setInterval(function(){res.write(`id:1\nevent:message\ndata:${new Date().toLocalString()}\n\n`)})})
BOM
浏览器窗口高度,outerHeight包含浏览器地址栏以及页签栏,innerHeight为纯页面高度

浏览器窗口宽度
window.innerWidth / window.outerWidth / document.documentElement.clientWidth
页面滚动
window.scrollBy(0, 100); // 相对于当前视口向下滚动100像素window.scrollBy(40, 0); // 相对于当前视口向右滚动40像素window.scrollTo(0, 0); // 滚动到页面左上角window.scrollTo(100, 100); // 滚动到距离屏幕左边及顶边各100像素的位置window.scroll() // 也接收相同的值这几个方法也都接收一个 ScrollToOptions 字典,除了提供偏移值,还可以通过 behavior 属性告诉浏览器是否平滑滚动。// 平滑滚动window.scrollTo({left: 100,top: 100,behavior: 'smooth' // 默认'auto'});
获取页面滚动的距离
都返回相同的值window.pageXoffset / window.scrollX 和 window.pageYoffset / window.scrollY
location
提供加载文档信息及浏览器导航操作
原生获取地址查询参数
let qs = "?q=javascript&num=10";let searchParams = new URLSearchParams(qs);for (let param of searchParams) {console.log(param); // ["q", "javascript"] ["num", "10"]}
更改地址
location.assign("http://www.wrox.com"); // 其它的两种调用方式内部也是使用assign方法window.location = "http://www.wrox.com";location.href = "http://www.wrox.com";
重载页面资源
location.reload(); // 重新加载,可能是从缓存加载location.reload(true); // 重新加载,从服务器加载
navigator
浏览器客户端标识
