Skip to main content

setTimeout 实现 setInterval

1. 为什么使用 setTimeout 实现 setInterval?

setInterval 的作用是每隔一段指定时间执行一个函数,但是这个执行不是真的到了时间立即执行,它真正的作用是每隔一段时间将事件加入事件队列中去,只有当当前的执行栈为空的时候,才能去从事件队列中取出事件执行。所以可能会出现这样的情况,就是当前执行栈执行的时间很长,导致事件队列里边积累多个定时器加入的事件,当执行栈结束的时候,这些事件会依次执行,因此就不能到间隔一段时间执行的效果。

针对 setInterval 的这个缺点,我们可以使用 setTimeout 递归调用来模拟 setInterval,这样我们就确保了只有一个事件结束了,我们才会触发下一个定时器事件,这样解决了 setInterval 的问题

实现

简单实现

function mySetInterval(fn, timeout) {
function interval() {
fn();
setTimeout(interval, timeout);
}
setTimeout(interval, timeout);
}

还可以加个控制器,控制是否继续执行

function mySetInterval(fn, timeout) {
// 控制器,控制定时器是否继续执行
var timer = {
flag: true,
};

// 设置递归函数,模拟定时器执行。
function interval() {
if (timer.flag) {
fn();
setTimeout(interval, timeout);
}
}
// 启动定时器
setTimeout(interval, timeout);
// 返回控制器
return timer;
}

2. JavaScript 中如何实现一个类?怎么实例化这个类?

构造函数法 用 new 关键字生成实例对象

缺点是用到了 this 和 prototype,编写复杂,可读性差

function Mobile(name, price) {
this.name = name;
this.price = price;
}
Mobile.prototype.sell = function () {
alert(this.name + ",售价 $" + this.price);
};
var iPhone = new Mobile("iPhone", 1000);
iPhone.sell();

Object.create 法 用Object.create() 生成实例对象。

缺点是不能实现私有属性和私有方法,实例对象之间也不能共享数据

var Person = {
firstName: "Mark",
lastName: "Yun",
age: 25,
introduce: function () {
alert("I am " + Person.firstName + " " + Person.lastName);
},
};

var person = Object.create(Person);
person.introduce();

// Object.create 要求IE9,低版本浏览器可以自行部署
if (!Object.create) {
Object.create = function (o) {
function F() {}
F.prototype = o;
return new F();
};
}

极简主义 消除 this 和 prototype,调用createNew() 得到实例对象

优点是容易理解,结构清晰,符合传统的面向对象编程的构造

var Cat = {
age: 3, // 共享数据,定义在类对象内,createNew外
createNew: function () {
var cat = {};
cat.name = "cat1";
var sound = "didi"; // 私有属性,定义在createNew 内,输出对象外
cat.makeSound = function () {
alert(sound); // 暴露私有属性
};
cat.changeAge = function (num) {
Cat.age = num; // 修改共享数据
};
return cat;
},
};
var cat = Cat.crateNew();
cat.makeSound();
``
ES6 语法糖 class
new 关键字生成实例对象
```js
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return "(" + this.x + "," + this.y + ")";
}
}
var point = new Point();