语法
-
typeof
一个class,是function
-
Object.preventExtensions
(不能加属性)
Object.seal
(仅可修改已有属性)
Object.freeze
(这个对象不能变) -
position:sticky
在父元素的范围内,只要不滚出父元素的视野,位置不变,滚出父元素的位置时,元素在父元素的地步,必须要设置 left/right top/bottom -
Set 和 Map 都可以
forEach
,push 和 unshift返回新数组的长度let map = new Map() map.set("1", 111); map.has("1") // true map.get("1") // 111 map.set("name", "hello"); map.forEach((val,key) => { console.log(val,key) }) [...map] // [ ["1", 111], ["name", "hello"] ] [...map.values] // [111, "hello"]
-
队列有enqueue入队和dequeue出队两个方法
-
symbol 哪怕参数一样,也不相等 使用symbol作为key的对象,不能被遍历 和 Object.keys
-
Reflect,Proxy
// === name in obj
Reflect.has(obj,'name')
// 返回obj自有属性
Reflect.ownKeys(obj)
// 如果设置失败 返回false 不报错 Object.defineProperty 会报错
Reflect.defineProperty(obj, 'name' {
value: 'haha'
})
git
-
git是基于文件的不能提交空目录。常见的变通方案就是在目录中提交一个空文件,如“.gitkeep”,从而强制git对其进行版本控制。
-
git 当一个很大项目,分支很多,仓库很大时,可以
git clone -b dev url --depth=1
这样就只会拉一个分支,拉最近一次的提交记录 , git pull 也可以。 -
每次git提交,都会生产一个基于当前提交为父节点的提交。
-
git 的分支也非常轻量。它们只是简单地指向某个提交纪录。
-
在 git 中合并两个分支时会产生一个特殊的提交记录,它有两个父节点。翻译成自然语言相当于:“我要把这两个父节点本身及它们所有的祖先都包含进来。
-
Rebase理解成是“重新设置基线”,实际上就是取出一系列的提交记录,“复制”它们,然后在另外一个地方逐个的放下去。这样得到的提交记录是一条直线。
-
HEAD 是一个对当前检出记录的符号引用 —— 也就是指向你正在其基础上进行工作的提交记录。
History
- 浏览器窗口有一个history对象,用来保存浏览历史,length 是历史的长度
- 这个history是session级别的,关了页面重开或者关了浏览器都没了
back()
是返回上个页面,forward
是下个页面,go
是去第几个页面history.pushState(state,title,url)
和history.replaceState()
,用来在浏览历史中添加和修改记录,不会刷新页面,如果url
添加了#不会触发hashChange
事件,如果url不同域,就报错history.state
是当前页面的数据popstate
除了pushState和replaceState,其他修改历史的方法都会触发
事件循环
垃圾回收机制
就是间歇的不定期的寻找到不再使用的变量,并释放掉它们所指向的内存。JS中最常见的垃圾回收方式是标记清除,是当变量进入环境时,将这个变量标记为“进入环境”。当变量离开环境时,则将其标记为“离开环境”。标记“离开环境”的就回收内存
执行上下文
- 当函数运行时,会创建一个执行环境,这个执行环境就叫执行上下文(Execution Context)
- 执行上下文中会创建一个对象叫作变量对象(Value Object),基础数据类型都保存在变量对象中
- 引用数据类型的值保存在堆里,我们通过操作对象的引用地址来操作对象。
- JS代码在执行的时候会进入一个执行上下文,可以理解为当前代码的运行环境
- 全局执行上下文只有一个,在客户端中一般由浏览器创建,也就是我们熟知的window对象,我们能通过this直接访问到它
- 在JS执行过程会产出多个执行上下文,JS引擎会有栈来管理这些执行上下文
- 执行上下文栈(下文简称执行栈)也叫调用栈,执行栈用于存储代码执行期间创建的所有上下文
- 栈底永远是全局上下文,栈顶为当前正在执行的上下文
当开启一个函数执行时会生成一个新的执行上下文并放入调用栈,执行完毕后会自动出栈
浏览器事件循环
- js 有一个主线程和 call-stack 调用栈,所有的任务都会被放到调用栈等待主线程执行
- js 单线程中的任务分为同步任务和异步任务。同步任务会在调用栈中按照顺序排队等待主线程执行,异步任务则会在异步有了结果后将注册的回调函数添加到任务队列(消息队列)中等待主线程空闲的时候,也就是栈内被清空的时候,被读取到栈中等待主线程执行。
- 调用栈中的同步任务都执行完毕,栈内被清空了,就代表主线程空闲了,这个时候就会去任务队列中按照顺序读取一个任务放入到栈中执行。每次栈内被清空,都会去读取任务队列有没有任务,有就读取执行,一直循环读取-执行的操作,就形成了事件循环
- 定时器会开启一条定时器触发线程来触发计时,定时器会在等待了指定的时间后将事件放入到任务队列中等待读取到主线程执行
- 第一次事件循环中,JavaScript 引擎会把整个 script 代码当成一个宏任务执行,执行完成之后,再检测本次循环中是否寻在微任务,存在的话就依次从微任务的任务队列中读取执行完所有的微任务,再读取宏任务的任务队列中的任务执行,再执行所有的微任务,如此循环。JS 的执行顺序就是每次事件循环中的宏任务-微任务
- 即便主线程为空,setTimeout(fn,0),0毫秒实际上也是达不到的。根据HTML的标准,最低是4毫秒。关于setInterval( fn , ms )来说并不是每隔ms就会执行一遍,而是经过ms后回调函数加入事件队列,所以setInterval未必准确
跨域
- 协议、域名、端口 不一样,就是跨域
- 跨域是一种浏览器策略,和服务器无关,服务器通信的话,是通过防火墙
- CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)
- CORS需要浏览器和服务器同时支持, 和普通的ajax一样,只要服务器实现了CORS接口
- 通过服务器端返回带有Access-Control-Allow-Origin标识的Response header,用来解决资源的跨域权限问题
- CORS请求默认不发送Cookie和HTTP认证信息;如果需要,需要指定头信息Access-Control-Allow-Credentials:true;同时浏览器需要指定参数withCredentials:true
对称加密和非对称加密
- 对称加密
- 快速、简单, 加密解密用同样的秘钥
- 称加密的一大缺点是密钥的管理与分配,如何把密钥发送到需要解密你的消息的人的手里是一个问题
- 常用的是AES和DES
- 非对称加密
- 加密和解密,使用公钥和私钥,私钥只有一方保管,公钥可以给任何人
- 目前最常用的非对称加密算法是RSA算法
- md5是一种不可逆的加密,和以上两种,可以加密解密的不一样
jsonp
let script = document.createElement('script');
script.src = 'http://localhost:8080?callback=handleJsonpCallBack';
function handleScriptComplete(e) {
script.onerror = script.onload = null;
clearTimeout(timeout);
}
script.onerror = script.onload = handleScriptComplete;
let timeout = setTimeout(() => {
handleScriptComplete({
type: 'timeout', target: script})
}, 10000);
document.body.appendChild(script);
function handleJsonpCallBack(res) {
console.log(res)
}
设计模式
- 构建型设计模式 工单构原抽
- 结构型设计模式 外(外观)、组(组合)、适(适配器)、代(代理)、桥(桥接)、装(装饰)、元(享元)
- 行为型设计模式 令(命令)、职(职责)、(观)观察者、(忘)备忘录、(中)中介者, 解(解释器)、迭(迭代器模式)、模(模板方法)、访(访问者)、态(状态模式)、略(策略模式)
WebView和原生是如何通信
- 原生Android调用javascript方法通过在android代码里使用webview的loadUrl进行调用
- js调用原生1,往webview里面注入方法,前端角度理解就是Android创建了一个方法,添加到我们js的window对象里面了,直接调用就可以触发原生的方法。
- js调用原生2 当我们js代码中使用alert(data)时,原生这边可以抓到data数据
- js调用原生3 通过schema方式,Native使用shouldOverrideUrlLoading方法对url协议进行解析
React
react ssr
其实就是react-dom/server 的renderToString方法
react给子元素props加一些属性
const newChildren = React.Children.map(this.props.children, children =>
React.cloneElement(children, {
setFocus: this.setFocus }),
);
react渲染
从拿到最新的数据,到将数据在页面中渲染出来,可以分为两个阶段。
- 调度阶段。这个阶段React用新数据生成新的Virtual DOM,遍历Virtual DOM,然后通过Diff算法,快速找出需要更新的元素,放到更新队列中去。
- 渲染阶段。这个阶段 React 根据所在的渲染环境,遍历更新队列,将对应元素更新。在浏览器中,就是跟新对应的DOM元素。除浏览器外,渲染环境还可以是 Native,硬件,VR 等
react - setState 同步异步
- setState 只在合成事件和钩子函数中是“异步”的,在原生事件和setTimeout 中都是同步的。
- setState 的“异步”并不是说内部由异步代码实现,其实本身执行的过程和代码都是同步的,只是合成事件和钩子函数的调用顺序在更新之前,导致在合成事件和钩子函数中没法立马拿到更新后的值,形成了所谓的“异步”,当然可以通过第二个参数 .setState(partialState, callback) 中的callback拿到更新后的结果。
- setState 的批量更新优化也是建立在“异步”(合成事件、钩子函数)之上的,在原生事件和setTimeout 中不会批量更新,在“异步”中如果对同一个值进行多次setState,setState的批量更新策略会对其进行覆盖,取最后一次的执行,如果是同时setState多个不同的值,在更新时会对其进行合并批量更新。
react - hooks
- react 16.6 增加了memo和lazy,16.8增加了hook
- useContext 传入一个 react.createContext 返回的对象,在函数组件类,代替Consumer直接使用,可以直接拿到数据
- useReducer 和 redux基本一样
- useMemo 和 react.memo 一样,useCallBack和useMemo ,一样,useCallBack传入一个参数,更加简洁
react - fiber
Fiber是什么
- 以前react更新是
stack reconciler (调节器)
是递归更新子组件,在更新一颗很大的dom树,任何交互和渲染都会被阻塞。 - 新的调度策略–
Fiber reconciler
,React fiber就是把大的任务,分解为小任务,然后执行完小任务之后,会去看看有没有新任务需要执行。 - Fiber 是一种轻量的执行线程,同线程一样共享定址空间,线程靠系统调度,并且是抢占式多任务处理,Fiber 则是自调用,协作式多任务处理
Fiber原理
- requestIdleCallback 是浏览器提供的一个 api,可以让浏览器在空闲的时候执行回调,在回调参数中可以获取到当前帧剩余的时间,fiber 利用了这个参数,判断当前剩下的时间是否足够继续执行任务,如果足够则继续执行,否则暂停任务,并调用 requestIdleCallback 通知浏览器空闲的时候继续执行当前的任务
- Fiber为不同的任务设置不同的优先级,同步任务,优先级最高,fiber 架构中一种数据结构就叫做fiber,fiber是一个对象,stateNode就是节点实例的对象, fiber 基于链表结构,拥有一个个指针,指向它的父节点子节点和兄弟节点,在 diff 的过程中,依照节点连接的关系进行遍历
Fiber更新阶段
- Reconcile阶段。此阶段中,依序遍历组件,通过diff 算法,判断组件是否需要更新,给需要更新的组件加上tag。遍历完之后,将所有带有tag的组件加到一个数组中。这个阶段的任务可以被打断。
- Commit阶段。根据在Reconcile阶段生成的数组,遍历更新DOM,这个阶段需要一次性执行完。如果是在其他的渲染环境–Native,硬件,就会更新对应的元素。
Fiber的问题
- 由于 reconciliation 的阶段会被打断,可能会导致 commit 前的这些生命周期函数多次执行
- 还有一个问题是饥饿问题,意思是如果高优先级的任务一直插入,导致低优先级的任务无法得到机会执行,这被称为饥饿问题
浏览器渲染
浏览器内核
- 浏览器是多线程 js引擎是单线程
- 浏览器内核 IE(IE浏览器) : trident 内核 -ms- Firefox(火狐浏览器) : gecko 内核 -moz- Safari(苹果浏览器) :webkit 内核 -webkit-
- 渲染引擎(浏览器内核, 用来解释网页语法并渲染到网页上) 和 js引擎(解析和执行JavaScript来实现网页的动态效果)
- chrome 使用了blink(webkit的变种),替换JavaScriptScore为V8引擎
webkit结构
- webkit分为4 个 部分 webCore、 JavaScriptCore、WebKit Embedding API、WebKit Ports
- WebCore包含了浏览器引擎的核心部分如处理html、dom、css、svg、获取资源、渲染页面过程控制、回调/通知外壳程序以及与Javascript实现的Binding等等;
- WebKit Embedding API是负责浏览器UI与WebKit进行交互的部分,
- WebKit Ports则是让Webkit更加方便的移植到各个操作系统、平台上,提供的一些调用Native Library的接口,比如在渲染层面,在iOS系统中,Safari是交给CoreGraphics处理,而在Android系统中,Webkit则是交给Skia。
浏览器渲染过程
- HTML Parser会把HTML解析成DOM树(DOM树在构建的过程中可能会被CSS和JS的加载而执行阻塞)。
- CSS Parser会把CSS解析成CSSOM树(CSS Object Model)。
- 将DOM和CSSOM合并为渲染树(rendering tree)将会被创建,代表一系列将被渲染的对象。
- 渲染树的每个元素包含的内容都是计算过的,它被称之为布局layout。浏览器使用一种流式处理的方法,只需要一次绘制操作就可以布局所有的元素。
- 将渲染树的各个节点绘制到屏幕上,这一步被称为绘制painting
- WebKit Ports的渲染接口,把渲染树渲染输出到屏幕上
http缓存
http缓存都是从第二次请求开始的。第一次请求资源时,服务器返回资源,并在respone header头中回传资源的缓存参数;第二次请求时,浏览器判断这些请求参数,命中强缓存(Pragma、cache control、expires)就直接200,否则就把请求参数加到request header头中传给服务器,看是否命中协商缓存(Etag Last modified),命中则返回304,否则服务器会返回新的资源
http\https
- http协议使用明文传递数据,不安全,https加了一个安全套接字层,在http的基础上加入了ssl协议,使用证书来验证服务器身份,并对客户端和服务器之间进行加密
- https 主要两个作用 一是 建立一个信息安全通道保证数据传输的安全 二是确认网站的真实性
- https的缺点 增加握手时间 ,页面加载时间增加50%,ssl证书好的比较贵,ssl证书需要绑定IP,不可以在一个IP绑定多个域名,加密范围有限。
HTTPS过程
-
1 client通过发送 Client Hello 报文开始 SSL 通信。报文中包含客户端支持的 SSL 的指定版本、加密组件(Cipher Suite)列表(所使用的加密算法及密钥长度等)。
-
2 服务器可进行 SSL 通信时,会以 Server Hello 报文作为应答。和客户端一样,在报文中包含 SSL 版本以及加密组件。服务器的加密组件内容是从接收到的客户端加密组件内筛选出来的。
-
3 之后服务器发送 Certificate 报文。报文中包含公开密钥证书。
-
4 最后服务器发送 Server Hello Done 报文通知客户端,最初阶段的 SSL 握手协商部分结束。
-
5 SSL 第一次握手结束之后,客户端以 Client Key Exchange 报文作为回应。报文中包含通信加密中使用的一种被称为 Pre-mastersecret 的随机密码串。该报文已用步骤 3 中的公开密钥进行加密。
-
6 接着客户端继续发送 Change Cipher Spec 报文。该报文会提示服务器,在此报文之后的通信会采用 Pre-master secret 密钥加密。
-
7 客户端发送 Finished 报文。该报文包含连接至今全部报文的整体校验值。这次握手协商是否能够成功,要以服务器是否能够正确解密该报文作为判定标准。
-
8 服务器同样发送 Change Cipher Spec 报文。
-
9 服务器同样发送 Finished 报文。
-
10 服务器和客户端的 Finished 报文交换完毕之后,SSL 连接就算建立完成。当然通信会受到 SSL 的保护。从此处开始进行应用层协议的通信,即发送 HTTP 请求。
-
11 应用层协议通信,即发送 HTTP 响应。
-
12 最后由客户端断开连接。断开连接时,发送 close_notify 报文。上图做了一些省略,这步之后再发送 TCP FIN 报文来关闭与 TCP的通信
ajax fetch axios
- ajax 传统方法
var xhr = new XMLHttpRequest();
//步骤二:设置请求的基本参数
xhr.open('get','test.php');
//步骤三:发送请求
xhr.send();
//步骤四:注册onreadystatechange监听事件,只要状态改变就会调用
xhr.onreadystatechange = function () {
if (ajax.readyState == 4 && ajax.status == 200) {
//步骤五 如果能够进到这个判断 说明数据完美到手
console.log(ajax.responseText);//操作返回内容
}
}
- fetch 原生方法,在window身上,自带了promise实现,但是默认请求不带cookie,不支持超时控制
- axios是基于promise对原生ajax的封装,提供了一些并发请求的接口
http2
谷歌推出的spdy协议,目标是优化HTTP协议的性能,通过二进制分帧、首部压缩、多路复用和优先级、服务器推送(服务器向客户端推送资源无需客户端明确的请求)等技术,缩短网页的加载时间并提高安全性,SPDY协议的核心思想是尽量减少TCP连接数。SPDY并不是一种用于替代HTTP的协议,而是对HTTP协议的增强。
- 多路复用 http1 同一域名下的连接有一定数量限制,一般不超过10个,http2.0的多路复用,就是一个连接 可以多重请求响应
- 二进制分帧 在 应用层http2 和 传输层 tcp 加了一个 二进制分帧层
- 服务端推送 HTTP / 2的另一个强大的新功能是服务器为单个客户端请求发送多个响应的能力