# 一、函数去抖和函数节流
# 1.1 函数去抖(debounce)
当调用函数n秒后,才会执行该动作,若在这n秒内又调用该函数则取消前一次并重新计算执行时间(频繁触发的情况下,只有足够的空闲时间,才执行代码一次)
function debounce(delay, cb) {
let timer
return function () {
if (timer) clearTimeout(timer)
timer = setTimeout(function () {
cb()
}, delay)
}
}
2
3
4
5
6
7
8
9
# 1.2 函数节流(throttle)
函数节流的基本思想是函数预先设定一个执行周期,当调用动作的时刻大于等于执行周期则执行该动作,然后进入下一个新周期(一定时间内js方法只跑一次。比如人的眨眼睛,就是一定时间内眨一次)
function throttle(cb, delay) {
let startTime = Date.now()
return function () {
let currTime = Date.now()
if (currTime - startTime > delay) {
cb()
startTime = currTime
}
}
}
2
3
4
5
6
7
8
9
10
JavaScript专题之跟着 underscore 学节流
# 二、实现一个sleep函数
js不像java一样有sleep()方法,但由于js是单线程的,可以利用伪死循环阻塞主线程来达到延迟执行的效果
function sleep(delay) {
// 获取一个初始时间
let startTime = new Date().getTime()
// 如果时间差小于延迟时间,就一直循环
while (new Date().getTime() - startTime < delay) {
continue
}
}
2
3
4
5
6
7
8
# 三、进程和线程的区别
**进程(process):**是cpu资源分配的最小单位(是能拥有资源和独立运行的最小单位),是并发执行的程序在执行过程中分配和管理资源的基本单位,是一个动态概念。
**线程(thread):**是cpu调度的最小单位(是建立在进程基础上的一次程序运行单位),是进程内可调度的实体,比进程更小的独立运行的基本单位。
个进程有一个或多个线程,线程之间共同完成进程分配下来的任务,打个比方: ● 假如进程是一个工厂,工厂有它的独立的资源 ● 工厂之间相互独立 ● 线程是工厂中的工人,多个工人协作完成任务 ● 工厂内有一个或多个工人 ● 工人之间共享空间
再完善完善概念: ● 工厂的资源 -> 系统分配的内存(独立的一块内存) ● 工厂之间的相互独立 -> 进程之间相互独立 ● 多个工人协作完成任务 -> 多个线程在进程中协作完成任务 ● 工厂内有一个或多个工人 -> 一个进程由一个或多个线程组成 ● 工人之间共享空间 -> 同一进程下的各个线程之间共享程序的内存空间(包括代码段、数据集、堆等)
# 四、谈谈js的垃圾回收机制
js拥有自动的垃圾回收机制,当一个值在内存中失去引用时,垃圾回收机制会根据特殊的算法找到它,并将其回收,释放内存。
# 4.1 标记清除法(常用)
(1).标记阶段:垃圾回收器会从根对象开始遍历。每一个可以从根对象访问到的对象都会被添加一个标识,于是这个对象就被标识为可到达对象; (2).清除阶段:垃圾回收器会对堆内存从头到尾进行线性遍历,如果发现有对象没有被标识为可到达对象,那么就将此对象占用的内存回收,并且将原来标记为可到达对象的标识清除,以便进行下一次垃圾回收操作;
优点:实现简单 缺点:可能会造成大量的内存碎片
# 4.2 引用计数清除法
(1).引用计数的含义就是跟踪记录每个值被引用的次数,当声明了一个变量并将一个引用类型赋值给该变量时,这个值的引用次数就是1。相反,如果包含对这个值引用的变量又取得了另外一个值,这个值的引用次数就减1。 (2).当这个引用次数变成0时,则说明没有办法再访问这个值了,就可以将其所占的内存空间给回收。这样,垃圾收集器下次再运行时,就会释放那些引用次数为0的值所占的内存。
优点: (1).可即刻回收垃圾
缺点: (1).计数器值的增减处理繁重 (2).实现繁琐复杂 (3).循环引用无法回收
# 五、new关键字做了什么?
使用new操作符调用构造函数实际上会经历以下4个步骤: (1).创建一个新对象 (2).将构造函数的作用域赋给新对象(因此this就指向了这个新对象) (3).执行构造函数中的代码(为这个新对象添加属性、方法) (4).返回新对象
var obj = {}
obj.__proto__ = Base.prototype
Base.call(obj)
2
3