我们在进到主题前先来看一段程序码,随後在开发人员工具中观察执行过程
function doSomething(){
var mom = '老妈';
}
doSomething();
首先是函式执行前,这没特别的问题,继续往下看
执行 doSomething()
後,
我们可以看到在 doSomething
作用域中 mom
值为 undefined
再往下一部时,能看到 mom
被赋予 '老妈'
这个值
我们再来看另一个范例
var ming = '小明';
console.log(ming);
此时会回传 '小明'
如果将 console.log()
放在前面
console.log(ming);
var ming = '小明';
这时就会回传 undefined
当我们将宣告的变数 ming
拿掉时,
console.log(ming);
此时会出现 ReferenceError: ming is not defined
为何会有这样的结果呢?
那是因为程序码在执行时会分为两个阶段
首先会先宣告变数,之後才将值赋予到变数中
如下所示
var ming;
ming = '小明';
console.log(ming);
此时结果也是 '小明'
而为什麽现有这种情况产生,就该进到我们的主题了
在前几天的文章中有提到执行环境,
而在建立执行环境时有两个阶段
分别为创造环境和执行这两个阶段
在创造环境时会将所有变数提出来,在记忆体上建立一个空间,
到了执行阶段时,才将时赋予到变数中,
在创造环境把记忆体空间准备好的流程,称为提升(Hoisting)
用以下程序码当范例
var a = 'weiwei';
我们先假设记忆体是一对的,
左边放 key,右边放值
在创造环境中,
记忆体左边会代入 a
这个变数,
而在创造环境中,还不会把值赋予到变数中,
因此记忆体右边会是 undefined
到了执行阶段时,
才将值代入变数中,
因此记忆体右边会是 'weiwei'
但如果使用函式陈述式宣告一个变数时,
在创造环境时就会将整个函式载入进去,
和变数宣告有些许不同
以图表示
在创造环境时,
变数 a
的值还没被载入,但函式的值已经被载入进去了,
而变数 a
要到执行阶段才会将值代入
我们来看范例
我们来看文章开头范例
var ming = '小明';
console.log(ming);
程序码在运行时,会解析为下方的结果
var ming; // 创造阶段
ming = '小明'; // 执行
console.log(ming);
宣告变数就称为创造阶段,
而开始赋予值之後称为执行阶段
函式陈述式范例
function callName() {
console.log('呼叫 weiwei')
}
callName();
此时会回传 '呼叫 weiwei'
,
当我们把 callName()
放在函式前面时
callName();
function callName() {
console.log('呼叫 weiwei')
}
此时的结果也是 '呼叫 weiwei'
为何会这样呢?
我们来拆解这段程序码
// 创造阶段
function callName() {
console.log('呼叫 weiwei')
}
// 执行
callName();
因为在创造阶段时,
其记忆体空间就已经包含完整内容,
所以就算在宣告函式之前执行函式,
也会获得相同的结果
函式表达式范例
var callName = function() {
console.log('呼叫 weiwei')
}
callName();
此时函式结果为 '呼叫 weiwei'
但当我们把 callName()
移到宣告函式前面时
callName();
var callName = function() {
console.log('呼叫 weiwei')
}
此时会出现 callName is not a function
这时我们使用 console.log()
看 callName
的值是什麽
console.log(callName);
var callName = function() {
console.log('呼叫 weiwei')
}
这时会看到 undefined
我们来解析这段程序码
// 创造阶段
var callName;
// 执行
callName = function() {
console.log('呼叫 weiwei')
}
在创造阶段会先准备 callName
这个变数的记忆体空间,
但还没被赋予值,
到了执行阶段时,才将函式赋予到 callName
这个变数上,
因此如果要运行函式表达式中的函式时,
必须在赋予完值後,才能运行该函式
function callName() {
console.log('呼叫 weiwei 1');
}
var callName = function() {
console.log('呼叫 weiwei 2');
}
callName();
该程序码结果为 '呼叫 weiwei 2'
当我们将函式的表达式与陈述式互换位置时,
var callName = function() {
console.log('呼叫 weiwei 2');
}
function callName() {
console.log('呼叫 weiwei 1');
}
callName();
此时结果也是 '呼叫 weiwei 2'
为何会这样呢?
那是因为在创造阶段时,函式是优先的
我们来解析这段程序码
// 函式优先
// 创造阶段
function callName() {
console.log('呼叫 weiwei 1');
}
var callName
// 执行
callName = function() {
console.log('呼叫 weiwei 2');
}
callName();
在创造阶段因为函式优先所以函式放前面,变数放後面
而在执行阶段时,变数被另一个函式盖掉,因此会显示 '呼叫 weiwei 2'
如果将 callName()
往前移
// 函式优先
// 创造阶段
function callName() {
console.log('呼叫 weiwei 1');
}
var callName
// 执行
callName();
callName = function() {
console.log('呼叫 weiwei 2');
}
这时结果会呈现 '呼叫 weiwei 1'
callName();
function callName() {
console.log(ming);
}
var ming = '小明';
该范例结果为 undefined
为何不会出现错误呢?
我们来解析这端程序码
// 创造阶段
function callName() {
console.log(ming);
}
var ming;
// 执行
callName();
ming = '小明';
在创造阶段 callName()
中的 ming
会向外查找全域中的值,
而全域中的 ming
此时为 undefined
因此到了执行阶段执行 callName()
时会回传 undefined
function callName() {
console.log('小明')
}
callName(); // 第一次执行
function callName() {
console.log('weiwei')
}
callName(); // 第二次执行
此时两个结果都是 'weiwei'
为何会这样呢?
我们来看解析
// 创造阶段
function callName() {
console.log('小明')
}
function callName() {
console.log('weiwei')
}
// 执行
callName(); // 第一次执行
callName(); // 第二次执行
因为後面的结果会覆盖掉前面的,
因此显示的结果都是 'weiwei'
whoName();
function whoName() {
if (name) {
name = 'weiwei';
}
}
var name = '小明';
console.log(name);
此时结果为 '小明'
来看解析
// 创造阶段
function whoName() {
if (name) {
name = 'weiwei';
}
}
var name;
// 执行
whoName();
name = '小明';
console.log(name);
在创造阶段中 name
的值为 nudefined
,
在执行阶段中,
whoName()
不管 name
值是什麽,
都会被後面的 name = '小明'
给覆盖掉,
因此结果会显示 '小明'
以上为今天的内容,感谢观看
>>: [CSS] Flex/Grid Layout Modules, part 1
欸!?这个不是在 hello world 的时候讲过了ㄇ?! 对。 其实函式还是有其他东西可以讲解的...
最近公司的EIP专案有个需求。主管在签核一览表里会点击要签核的单子另开一个视窗,需求单位希望主管签完...
有两个二元树,怎麽检查两个树是不是一样的。 思路 一路Traversal下去 程序码 class S...
开始进入分组授课的第二周, 这周的课程包括共同领域的资料结构Stack & Queue及後端...
Definition of a Semigroup 一个集合(Set)或称型别(Type) 有 co...