我们先来看看下面这段code的执行结果
当我们执行 doSomthing 的 function 的时候,会发现一开始 mom 是 undefined,继续执行以后 mom 才会 被赋值成字串的 '老妈'。
如果我们执行下面的code,会发生甚么事情呢?
console.log(name);var name = '小美';
答案是
但如果今天是这样的话
console.log(name2);// var name2 = '小美';
执行结果
而这个就是我们今天要讨论的主题 -- 提升
首先我们在执行环境之前,还有一个 创造环境 会先被执行。
可以从这张图看到,我们在创造环境的时候,会是先把变数名称放到记忆体中,而记忆体就像是物件的感觉,一个 keyname 对应一个 value 值。
接着就到 执行 的步骤,这时候才会把 值 赋予到记忆体对应的 value 的空间。
在创造环境的时候,把记忆体空间準备好,这个流程我们就叫做 -- 提升
比较不同的是,当使用 函式陈述式 的时候,会在 创造环境 阶段,直接把 keyname 以及 value 都放在记忆体中。
如果由这个例子来看,在创造环境的时,function 的 keyname 以及 value 都已经存在于记忆体中,到执行环境的时候,变数 a 才被赋值。
var a = '1'; console.log(a);
所以这段程式码可以拆解成这样
// 创造阶段 var a; // 执行阶段 a = '1'; console.log(a);
再来我们看另一段code
function call () { console.log('呼叫'); } call();
这样的结果很明显会显示 '呼叫' 没问题。
那么改成这样呢
call(); function call () { console.log('呼叫'); }
还是一样会显示 '呼叫',因为在 执行阶段 已经将 function 记录在记忆体中,而执行阶段才会执行 call(); 的程式码。
所以 函式陈述式 不管放在哪里都没关係。
那如果是下面的程式码呢?
call(); var call = function () { console.log('呼叫'); }
执行结果会是:
透过这样的方式(函式表达式)宣言function的话,就会跟变数的过程一样:
// 创造阶段 var call; // 执行阶段 call(); call = function () { console.log('呼叫'); }
那再来看到下面的例子,最后印出来的结果会是甚么呢?
function call () { console.log('call 1'); } var call = function () { console.log('call 2'); }; call();
答案会是 call 2
因为虽然在 创造环境 的时候, call 的记忆体位置是装着 console.log('call 1'); 。
但在 执行步骤 的时候, call 的记忆体位置被替换成 console.log('call 2'); 。
所以最后的执行结果是 call 2。
就算替换两段 function 的位置,结果还是会一样。
var call = function () { console.log('call 2'); }; function call () { console.log('call 1'); } call();
最后再来看一个练习题:
call(); function call () { if (dog) { dog = 'shiba'; } } var dog = 'husky'; console.log(dog);
这样的执行结果,答案会是甚么呢?
// husky
让我们拆解流程来看看
// 创造阶段 function call () { if (dog) { dog = 'shiba'; } } var dog; // 执行阶段 call(); dog = 'husky'; console.log(dog);
虽然 function 中的判断式有执行,但是这时候变数 dog 是 undefined ,判断是会认为是 false,而不会进 dog = 'shiba'; 的赋值的动作。
最后来到 dog = 'husky';, 所以console.log 出来的就是 husky。
总结:函式陈述式在创造期间就已经“载入”,变数在执行期间赋值。
透过这些实例说明,希望可以让大家更了解 hoisting 的概念。 汪汪