1. 全局预处理——先扫描函数声明,再扫描变量声明;
- 函数:用声明的方式创建的函数;
- 变量:用var定义的变量;初始化为undefined;
如果出现命名冲突 时:
- 函数声明:覆盖;
- 变量声明:忽略;
例如:
<script>
f(); //fff
g(); //TypeError: g is not a function
function f() {
console.log('fff');
}
var g = function () {
console.log('ggg');
}
</script>
f()函数是声明方式创建的函数,g()是函数表达式,全局预处理时词法环境中,只能是用声明的方式创建的函数。
因此,全局预处理时g()从语义上看,应该是函数,但是由于g()是函数表达式,不会在词法环境中,所以调用时会报错。
例如:
console.log(a); // undefined
console.log(b); //ReferenceError: b is not defined
var a = 1;
b = 2;
同理,词法环境中只有用var定义的变量。
例如:
alert(f); //function f(){alert('567');}
var f = 1;
function f() {
alert('123');
}
var f = 2;
function f() {
alert('567');
}
var f = function() {
alert('890');
}
命名冲突时,函数具有“优先权”,变量会直接被忽略,而函数会被覆盖。
2. 全局执行过程
例如:
alert(a); //undefined
alert(b); //ReferenceError: b is not defined
alert(f); //function f() {console.log('f');}
alert(g); //undefined
var a = 1;
b = 2;
alert(b); //2
function f() {
console.log('f');
}
var g = function () {
console.log('g');
}
alert(g); //function () {console.log('g');}
为了分析方便我们可以使用词法环境:
LexicalEnvironment {} === window;
全局预处理时:
window {
//先扫描函数声明:
f: 指向函数,
//再扫面变量声明:
a: undefined,
g: undefined
}
全局执行时:
window {
f: 指向函数,
a: 1,
b: 2,
g: 指向函数
}
3. 函数预处理阶段
- 每调用一次,产生一个词法环境(或执行上下文Execution Context);
- 先传入函数的参数,若参数值为空,初始化undefined;
- 然后是内部函数声明,若发生命名冲突,会覆盖;
- 接着就是内部var变量声明,若发生命名冲突,会忽略;
4. 函数执行阶段
-
给预处理阶段的成员赋值;
- 无var声明的变量,会成为全局成员;
例如:
function f(a, b) {
alert(a); //1
alert(b); //funciton b(){}
var a = 100;
function b() {
}
}
f(1, 2);
VO(Variable Object)——>变量对象
函数中的激活对象:
VO(functionContext)=== AO;
代码中:
AO(f) {
a: 1, //变量命名冲突,忽略
b: 指向函数, //函数命名冲突,覆盖
}
例如:
function test(a, b) {
alert(a); //10
alert(b); //undefined
alert(c); //undefined
alert(d); //function d(){}
alert(e); //undefined
//alert(x); //ReferenceError: x is not defined
var c = 10;
alert(c); //10
function d() {
}
var e = function _e() {
};
alert(e); //function _e(){}
(function x() {
});
b = 20;
alert(b); //20
}
test(10)
函数预处理时:
AO(test) {
//参数:
a: 10,
b: undefined,
//函数声明:
d: 指向函数,
//变量声明:
c: undefined,
e: undefined
}
函数执行时:
AO(test) {
a: 10,
b: 20,
d: 指向函数,
c: 10,
e: 指向函数
}
热门评论
“命名冲突时,函数具有“优先权”,变量会直接被忽略,而函数会被覆盖。”
这个说法不对吧,理解了变量声明提升就很好理解了。如果把代码改一下,把alert放最后
var f = 1;
function f() {
alert('123');
}
var f = 2;
function f() {
alert('567');
}
var f = function() {
alert('890');
}
alert(f);
最后输出是
function() {
alert('890');
}
和是否变量、函数并没有关系
帮助挺大,本人对函数作用域跟闭包比较感兴趣,然而现在在外面没工具敲代码,后面看起来有点费劲,因为后面很多都是引用前面声明的,要看懂作者要表达的意思要翻上去几遍…