JavaScript:小心意外提升!
挑战
撰写
解决方案
参考
挑战
让我先抛出一个小挑战。请将此处
替换// Your code here为实际代码,并打印Flag!
function generateSecret() {
return Date.now() + Math.random() * 10000;
}
const mySecretKey = generateSecret();
// Your code here
if (mySecretKey === 42) {
console.log('Flag!');
} else {
console.log('Bad secret!');
}
撰写
为了打印 Flag,我们需要了解函数提升的工作原理。
myFunction();
function myFunction() {
console.log('My function was called!');
}
这段代码片段有效My function was called!,即使该函数是在调用之后声明的,也能正确打印结果。
这得益于函数提升(Hoisting)机制。
以下是MDN给出的简要定义:
例如,从概念上讲,严格意义上的提升定义认为变量和函数声明会被物理地移动到代码顶部,但实际上并非如此。相反,变量和函数声明在编译阶段会被加载到内存中,但它们仍然保留在你在代码中输入它们的位置。
这意味着前面的代码可以理解为:
function myFunction() {
console.log('My function was called!');
}
myFunction();
函数声明和定义被移到了实际代码执行之前,这使得我们可以在函数声明之前就使用它。
但是,如果我们声明同一个函数两次会发生什么呢?
function myFunction() {
console.log('My function was called!');
}
myFunction();
function myFunction() {
console.log('My *evil* function was called!');
}
剧透警告:邪恶函数被调用了!
提升后,之前的代码可以理解为:
function myFunction() {
console.log('My function was called!');
}
function myFunction() {
console.log('My *evil* function was called!');
}
myFunction();
由于最后一个声明myFunction是邪恶的,所有对它的调用都myFunction将指向邪恶的函数!
解决方案
为了解决这个问题,我们只需要重新声明该generateSecret函数即可。
function generateSecret() {
return Date.now() + Math.random() * 10000;
}
const mySecretKey = generateSecret();
// Your code here
function generateSecret() {
return 42;
}
if (mySecretKey === 42) {
console.log('Flag!');
} else {
console.log('Bad secret!');
}
参考
MDN:函数提升
MDN:函数
Medium:提升你的 JavaScript 函数提升知识