事件机制的核心就是发布-订阅模式。维护一个对象,对象的 key 存的是事件 type,对应的 value 为触发相应 type 的回调函数,即 listeners,然后 trigger 时遍历通知,即 forEach 进行回调执行。
1 | class EventTarget { |
1 | // 测试 |
事件机制的核心就是发布-订阅模式。维护一个对象,对象的 key 存的是事件 type,对应的 value 为触发相应 type 的回调函数,即 listeners,然后 trigger 时遍历通知,即 forEach 进行回调执行。
1 | class EventTarget { |
1 | // 测试 |
在JS中,我们可以使用 setTimeout
和 setIntarval
实现动画,但是 H5 的出现,让我们又多了两种实现动画的方式,分别是 CSS 动画(transition
、animation
)和 H5的canvas
实现。除此以外,H5还提供了一个专门用于请求动画的API,让 DOM 动画、canvas动画、svg动画、webGL动画等有一个专门的刷新机制。
传统的javascript 动画是通过定时器 setTimeout 或者 setInterval 实现的。但是定时器动画一直存在两个问题
- 动画的循时间环间隔不好确定(推荐的最佳循环间隔是17ms(大多数电脑的显示器刷新频率是60Hz,1000ms/60))
- 定时器第二个时间参数只是指定了多久后将动画任务添加到浏览器的UI线程队列中,如果UI线程处于忙碌状态,那么动画不会立刻执行
requestAnimationFrame
方法会告诉浏览器希望执行动画并请求浏览器在下一次重绘之前调用回调函数来更新动画。
1 | window.requestAnimationFrame(callback) |
cancelAnimationFrame()
以取消动画。在使用和实现上, requestAnimationFrame
与 setTimeout
类似。举个例子:
1 | let count = 0; |
document.hidden
属性是否可见(true),可见状态下才能继续执行以下步骤requestAnimationFrame
将回调函数追加到动画帧请求回调函数列表的末尾
注意:当执行 requestAnimationFrame(callback)的时候,不会立即调用 callback 回调函数,只是将其放入回调函数队列而已,同时注意,每个 callback回调函数都有一个 cancelled 标志符,初始值为 false,并对外不可见。requestAnimationFrame
自带函数节流功能,采用系统时间间隔,保持最佳绘制效率,不会因为间隔时间的过短,造成过度绘制,增加页面开销,也不会因为间隔时间过长,造成动画卡顿,不流程,影响页面美观。
浏览器的重绘频率一般会和显示器的刷新率保持同步。大多数采用 W3C规范,浏览器的渲染页面的标准频率也为 60 FPS(frames/per second)即每秒重绘60次,requestAnimationFrame的基本思想是 让页面重绘的频率和刷新频率保持同步,即每 1000ms / 60 = 16.7ms执行一次。
通过 requestAnimationFrame
调用回调函数引起的页面重绘或回流的时间间隔和显示器的刷新时间间隔相同。所以 requestAnimationFrame
不需要像 setTimeout
那样传递时间间隔,而是浏览器通过系统获取并使用显示器刷新频率。例如在某些高频事件(resize,scroll 等)中,使用 requestAnimationFrame
可以防止在一个刷新间隔内发生多次函数执行,这样保证了流程度,也节省了开销setTimeout
或setInterval
不准的情况(JS是单线程的,setTimeout
任务被放进异步队列中,只有当主线程上的任务执行完以后,才会去检查该队列的任务是否需要开始执行,造成时间延时)。
setTimeout
的执行只是在内存中对图像属性进行改变,这个改变必须要等到下次浏览器重绘时才会被更新到屏幕上。如果和屏幕刷新步调不一致,就可能导致中间某些帧的操作被跨越过去,直接更新下下一帧的图像。即 掉帧
使用 requestAnimationFrame
执行动画,最大优势是能保证回调函数在屏幕每一次刷新间隔中只被执行一次,这样就不会引起丢帧,动画也就不会卡顿requestAnimationFrame
执行过程,我们知道只有当页面激活的状态下,页面刷新任务才会开始,才执行 requestAnimationFrame
,当页面隐藏或最小化时,会被暂停,页面显示,会继续执行。节省了 CPU 开销。
注意:当页面被隐藏或最小化时,定时器setTimeout
仍在后台执行动画任务,此时刷新动画是完全没有意义的(实际上 FireFox/Chrome 浏览器对定时器做了优化:页面闲置时,如果时间间隔小于 1000ms,则停止定时器,与requestAnimationFrame
行为类似。如果时间间隔>=1000ms,定时器依然在后台执行)1 | // 在浏览器开发者工具的Console页执行下面代码。 |
我们可以使用 requestAnimationFrame
实现setInterval
及 setTimeout
1 | // setInterval实现 |
1 | // setTimeout 实现 |
同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;
异步任务指的是,不进入主线程、而进入”任务队列”(task queue)的任务,只有”任务队列”通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。只要异步任务有了运行结果,就在”任务队列”之 中放置一个事件。
任务队列中存着的是异步任务,这些异步任务一定要等到执行栈清空后才会执行。
同步就是发出一个请求后什么事都不做,一直等待请求返回后才会继续做事;异步就是发出请求后继续去做其他事,这个请求处理完成后会通知你,这时候就可以处理这个回应了。
PWA作为2018最火热的技术概念之一,对提升Web应用的安全、性能和体验有着很大的意义,非常值得我们去了解与学习。
PWA是Progressive Web App的英文缩写,也就是渐进式增强WEB应用。目的就是在移动端利用提供的标准化框架,在网页应用中实现和原生应用相近的用户体验。
一个 PWA 应用首先是一个网页, 可以通过 Web 技术编写出一个网页应用. 随后添加上 App Manifest 和 Service Worker 来实现 PWA 的
安装和离线等功能。
我们需要理解的是,PWA不是某一项技术,或者某一个新的产物;而是一系列Web技术与标准的集合与应用。通过应用这些新的技术与标准,可以从安
Reflect 是一个内置的对象,它提供拦截 JavaScript 操作的方法。这些方法与处理器对象的方法相同。Reflect不是一个函数对象,因此它是不可构造的。
Reflect这个对象在新版本的chrome是支持的, ff比较早就支持Proxy和Reflect了,要让node支持Reflect可以安装harmony-reflect;
Reflect不是构造函数, 要使用的时候直接通过Reflect.method()调用, Reflect有的方法和Proxy差不多, 而且多数Reflect方法原生的Object已经重新实现了。
与大多数全局对象不同,Reflect没有构造函数。你不能将其与一个new运算符一起使用,或者将Reflect对象作为一个函数来调用。Reflect的所有属性和方法都是静态的(就像Math对象)。
函数其实就是一个封装一段代码段的对象,那函数名其实仅是用来引用函数对象的一个普通变量
写代码的时候我们避免不了要重复用一些代码,一直重复写很耗时,而且不美观也不利于维护,因此函数的出现就是来让代码重用,便于维护。
一段代码,可能被反复使用,可以定义为函数,然后调用函数来使用这段代码。
在JavaScript中函数就是对象。函数不同于其他对象的决定性特点是,函数存在一个被称为[[Call]]的内部属性。内部属性无法通过代码访问而是
定义了代码执行时的行为。ECMAScript为JavaScript的对象定义了多种内部属性,这些内部属性都用双重中括号来标注。
[[Call]]属性是函数独有的,表明该对象可以被执行。由于仅函数拥有该属性,ECMAScript定义了typeof操作符对任何具有[[Call]]属性的对
象返回 [object Function]
ES6 或 TS 引入了块级作用域,通过let和const、class等可以定义块级作用域里的变量,块级作用域内的变量不存在变量提升,且存在暂时性死区
(在代码块内,使用let或const声明变量前该变量都是不可改变的)。常见的if语句,for循环的循环体内都可以定义块级变量。那么switch语句中的块级作用域是什么呢? 先给出结论:
switch语句中的块级作用域,在整个switch语句中,而不是对于每一个case生成一个独立的块级作用域。
在JS中,大家通常用typeof
来判断基本类型,instanceof
来判断引用类型。
typeof一般只能返回如下几个结果:number,boolean,string,function,object,undefined字符串
对于Array,null等特殊对象使用typeof一律返回object,而函数返回function这正是typeof的局限性。
在判断除Object类型的对象(基本类型)时比较方便。
object instanceof constructor
instanceof 运算符用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性。
换种说法就是左侧的对象是否是右侧对象的实例。
1 | '123' instanceof String // true |