前端事件流
事件流程如下:
捕获阶段:事件从根元素开始向触发事件的目标元素进行传递,传递过程中,如果中间有元素注册了事件处理函数,并且 useCapture 参数值为 true ,那么此事件处理函数就会执行,IE9+和其他标准浏览器支持。
目标阶段:触发目标元素对应事件,并执行注册的事件处理函数。
冒泡阶段:从目标元素开始向根元素传递,传递过程中,如果中间有元素注册了事件处理函数,且 useCapture 值为 false,此事件处理函数就会执行。
什么是闭包?这就是闭包!
有权访问另一个函数作用域内变量的函数都是闭包。
HTTP缓存机制和原理
强制缓存
(1) Expires
Expires 的值为服务端返回的到期时间,即下一次请求时,请求时间小于服务端返回的到期时间,直接使用缓存数据。
不过 Expires 是HTTP 1.0的东西,现在默认浏览器均默认使用 HTTP 1.1,所以它的作用基本忽略。
另一个问题是,到期时间是由服务端生成的,但是客户端时间可能跟服务端时间有误差,这就会导致缓存命中的误差。
所以HTTP 1.1 的版本,使用Cache-Control替代。
(2) Cache-Control
Cache-Control 是最重要的规则。常见的取值有 private、public、no-cache、max-age,no-store,默认为 private。
- private: 客户端可以缓存
- public: 客户端和代理服务器都可缓存(前端的同学,可以认为 public 和 private 是一样的)
- max-age=xxx: 缓存的内容将在 xxx 秒后失效
- no-cache: 需要使用对比缓存来验证缓存数据(后面介绍)
- no-store: 所有内容都不会缓存,强制缓存,对比缓存都不会触发(对于前端开发来说,缓存越多越好,so…基本上和它说886)
对比缓存
(1) Last-Modified / If-Modified-Since
Last-Modified:
服务器在响应请求时,告诉浏览器资源的最后修改时间。
If-Modified-Since:
再次请求服务器时,通过此字段通知服务器上次请求时,服务器返回的资源最后修改时间。
服务器收到请求后发现有头 If-Modified-Since 则与被请求资源的最后修改时间进行比对。
若资源的最后修改时间大于 If-Modified-Since,说明资源又被改动过,则响应整片资源内容,返回状态码 200;若资源的最后修改时间小于或等于 If-Modified-Since,说明资源无新修改,则响应HTTP 304,告知浏览器继续使用所保存的cache。
(2) Etag / If-None-Match (优先级高于Last-Modified / If-Modified-Since)
Etag:
服务器响应请求时,告诉浏览器当前资源在服务器的唯一标识(生成规则由服务器决定)。
If-None-Match:
再次请求服务器时,通过此字段通知服务器客户段缓存数据的唯一标识。
服务器收到请求后发现有头 If-None-Match 则与被请求资源的唯一标识进行比对,
不同,说明资源又被改动过,则响应整片资源内容,返回状态码 200;相同,说明资源无新修改,则响应 HTTP 304,告知浏览器继续使用所保存的 cache。
defer 和 async
1、defer
如果 script 标签设置了该属性,则浏览器会异步的下载该文件并且不会影响到后续 DOM 的渲染;
如果有多个设置了 defer 的 script 标签存在,则会按照顺序执行所有的 script;
defer 脚本会在文档渲染完毕后,DOMContentLoaded 事件调用前执行。
2、async
async 的设置,会使得 script 脚本异步的加载并在允许的情况下执行;
async 的执行,并不会按着 script 在页面中的顺序来执行,而是谁先加载完谁执行。
使用 js 的 FileReader对象实现上传图片时的图片预览功能
废话不多说线上代码
1 |
|
HTTPS 验证原理
https 在真正请求数据前,先会与服务有几次握手验证,以证明相互的身份,以下图为例
性能优化
减少请求数量(sprite、combo)
善用缓存(application cache、http缓存、CDN、localstorage、sessionstorage,备忘录模式)
减少选择器消耗(从右到左),减少DOM操作(DOM和JavaScript解释器的分离)
CSS的回流与重绘
reflow(回流)
说到页面为什么会慢?那是因为浏览器要花时间、花精力去渲染,尤其是当它发现某个部分发生了点变化影响了布局,需要倒回去重新渲染, 该过程称为reflow(回流)。
reflow 几乎是无法避免的。现在界面上流行的一些效果,比如树状目录的折叠、展开(实质上是元素的显 示与隐藏)等,都将引起浏览器的 reflow。鼠标滑过、点击……只要这些行为引起了页面上某些元素的占位面积、定位方式、边距等属性的变化,都会引起它内部、周围甚至整个页面的重新渲 染。通常我们都无法预估浏览器到底会 reflow 哪一部分的代码,它们都彼此相互影响着。
repaint(重绘)
如果只是改变某个元素的背景色、文 字颜色、边框颜色等等不影响它周围或内部布局的属性,将只会引起浏览器 repaint(重绘)。
repaint 的速度明显快于 reflow(在IE下需要换一下说法,reflow 要比 repaint 更缓慢)。
对称加密及非对称加密
- 对称加密
发送方和接收方需要持有同一把密钥,发送消息和接收消息均使用该密钥。
相对于非对称加密,对称加密具有更高的加解密速度,但双方都需要事先知道密钥,密钥在传输过程中可能会被窃取,因此安全性没有非对称加密高。
- 非对称加密算法
接收方在发送消息前需要事先生成公钥和私钥,然后将公钥发送给发送方。发送放收到公钥后,将待发送数据用公钥加密,发送给接收方。接收到收到数据后,用私钥解密。
在这个过程中,公钥负责加密,私钥负责解密,数据在传输过程中即使被截获,攻击者由于没有私钥,因此也无法破解。
非对称加密算法的加解密速度低于对称加密算法,但是安全性更高。
—- 以下更新于 2018-12-11 —-
link 和 @import 区别
- 从属关系区别
@import是 CSS 提供的语法规则,只有导入样式表的作用;link是HTML提供的标签,不仅可以加载 CSS 文件,还可以定义 RSS、rel 连接属性等。
- 加载顺序区别
加载页面时,link标签引入的 CSS 被同时加载;@import引入的 CSS 将在页面加载完毕后被加载。
- 兼容性区别
@import是 CSS2.1 才有的语法,故只可在 IE5+ 才能识别;link标签作为 HTML 元素,不存在兼容性问题。
- DOM可控性区别
可以通过 JS 操作 DOM ,插入link标签来改变样式;由于 DOM 方法是基于文档的,无法使用@import的方式插入样式。
CSS 权重优先级顺序
!important > 行内样式 > ID > 类、伪类、属性 > 标签名 > 继承 > 通配符
观察者模式
1 | /* Pubsub */ |
两大数相加
1 | function sumStrings (a, b) { |
设备像素比
物理像素(physical pixel)
一个物理像素是显示器(手机屏幕)上最小的物理显示单元,在操作系统的调度下,每一个设备像素都有自己的颜色值和亮度值。
设备独立像素(density-independent pixel)
设备独立像素(也叫密度无关像素),可以认为是计算机坐标系统中得一个点,这个点代表一个可以由程序使用的虚拟像素(比如: css像素),然后由相关系统转换为物理像素。 所以说,物理像素和设备独立像素之间存在着一定的对应关系,这就是接下来要说的设备像素比。
设备像素比(device pixel ratio )
设备像素比(简称dpr)定义了物理像素和设备独立像素的对应关系,它的值可以按如下的公式的得到:
1 | 设备像素比 = 物理像素 / 设备独立像素 // 在某一方向上,x方向或者y方向 |
—- 以下更新于 2018-12-13 —-
双向绑定原理(简单思路)
实现一个监听器Observer,用来劫持并监听所有属性,如果有变动的,就通知订阅者。
实现一个订阅者Watcher,每一个Watcher都绑定一个更新函数,watcher可以收到属性的变化通知并执行相应的函数,从而更新视图。
实现一个解析器Compile,可以扫描和解析每个节点的相关指令(v-model,v-on等指令),如果节点存在v-model,v-on等指令,则解析器Compile初始化这类节点的模板数据,使之可以显示在视图上,然后初始化相应的订阅者(Watcher)。
—- 以下更新于 2019-2-12 —-
面向对象的三个基本特征
- 封装
- 继承
- 多态
—- 以下更新于 2019-2-24 —-
JS继承 · 类
ES5 和 ES6 子类 this
生成顺序不同。ES5 的继承先生成了子类实例,再调用父类的构造函数修饰子类实例,ES6 的继承先生成父类实例,再调用子类的构造函数修饰父类实例。这个差别使得 ES6 可以继承内置对象。
1 | function MyES5Array() { |
ES5/ES6 的继承除了写法以外还有什么区别?
1、class
声明会提升,但不会初始化赋值。Foo
进入暂时性死区,类似于 let
、const
声明变量。
1 | const bar = new Bar(); // it's ok |
2、class
声明内部会启用严格模式。
1 | // 引用一个未声明的变量 |
3、class
的所有方法(包括静态方法和实例方法)都是不可枚举的。
1 | // 引用一个未声明的变量 |
4、class
的所有方法(包括静态方法和实例方法)都没有原型对象 prototype,所以也没有[[construct]]
,不能使用 new
来调用。
1 | function Bar() { |
5、必须使用 new
调用 class
。
1 | function Bar() { |
6、class
内部无法重写类名。
1 | function Bar() { |
Vue 组件的 data 必须是一个函数
一个组件的 data
选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝。
1 | data: function () { |
如果 Vue 没有这条规则,点击某个按钮组件就可能影响到其它实例。
防抖及节流
防抖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15/**
* 防抖函数
* TODO: 防止多次提交按钮,只执行最后提交的一次
* 原理: 在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。
* 适用场景: 按钮多次点击等
*/
export const debounce = (fn, delay = 500) => {
let timer = null
return function (...args) {
clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this, args)
}, delay)
}
}节流
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17/**
* 节流函数
* TODO: 固定时间内只执行一次,防止超高频次触发位置变动
* 原理: 规定在一个单位时间内,只能触发一次函数。如果这个单位时间内触发多次函数,只有一次生效。
* 适用场景: 滚动事件等
*/
export const throttle = (fn, delay = 500) => {
let flag = true
return function (...args) {
if (!flag) return
flag = false
setTimeout(() => {
fn.apply(this, args)
flag = true
}, delay)
}
}更多内容,请移步↓