方法1:立即执行函数表达式(IIFE)—— 一次性狂欢
正如Douglas Crockford在《JavaScript: The Good Parts》中所说:“IIFE是一个自包含的模块,它封装了一些私有变量,并通过改变词法作用域来避免全局变量的污染。”
(function() {
console.log('派对开始!');
// 所有的宾客都已经到场,派对结束了。
})();
// '派对开始!' 被打印出来,然后派对就结束了。
方法2:使用闭包—— 神秘的盒子
Kyle Simpson在《You Don't Know JS》系列中讨论了闭包的魔力:“闭包允许一个函数在其词法作用域之外被调用,同时仍然能够访问定义时的作用域链。”
function openMysteryBox() {
let magicBall = '发光吧!';
console.log(magicBall);
// 魔法球发光后消失了
openMysteryBox = null;
}
openMysteryBox(); // '发光吧!' 被打印出来,然后魔法球消失了。
方法3:使用标志变量—— 哨兵
Michael McMillan在《JavaScript Pattern and Best Practice》中提到了使用标志变量的模式:“这是一种防止事件处理器被多次绑定的简单方法。”
let alarmRung = false;
function soundAlarm() {
if (alarmRung) return; // 如果警报已经响过,哨兵什么也不做
console.log('警报响起!');
alarmRung = true; // 哨兵完成了他的任务
}
soundAlarm(); // '警报响起!' 被打印出来,然后哨兵就放松了警惕。
方法4:使用Array.from或扩展运算符—— 一群人的合唱
MDN Web Docs在介绍Array.from()时提到:“它可以用于将类数组对象(如NodeList)或可迭代对象(如Set)转换为数组实例。”
const singers = [
function() { console.log('歌手1的歌声'); },
function() { console.log('歌手2的歌声'); }
];
// 使用Array.from
const performance = Array.from(singers, singer => singer());
// 或者使用扩展运算符
const performance = [...singers].map(singer => singer());
// 每个歌手都唱了一次,然后合唱团一起表演。
方法5:使用Promise—— 期待已久的事件
Promise在ECMAScript规范中被定义为“一个代表异步操作的最终完成(或失败)及其结果值的对象。”
let meteorShowerHappened = false;
function watchMeteorShower() {
if (meteorShowerHappened) return Promise.resolve(); // 如果流星雨已经发生过,直接安心睡觉
// 等待流星雨的降临
return new Promise((resolve) => {
setTimeout(() => {
console.log('流星雨来了!');
resolve();
meteorShowerHappened = true; // 流星雨已经发生,可以安心睡觉了
}, 1000);
});
}
watchMeteorShower().then(() => console.log('安心地去睡觉'));
收尾
至此,我们探讨了五种确保JavaScript函数只执行一次的方法。无论是通过IIFE的狂欢派对,闭包的神秘盒子,标志变量的哨兵,还是Array.from和Promise的合唱与期待,每种方法都有其独特的魅力和适用场景。希望这些生动的语言和形象的比喻能帮助你更好地理解和记忆这些重要的编程技巧。当然,欢迎评论区补充~
现在,就让我们带着这些知识去征服代码的世界吧!