1、JS中的作用域原理是通过作用域链来实现的
当一个函数被定义时(注意是被定义)这个时候 会将它定义刻的scope chain链接到这个函数对象的[[scope]]属性形成一个完整的作用域链
2、作用域链的访问机制
请看下面这个例子
function factory() {
var name = 'laruence';
var intro = function(){
var age = 0;
alert('I am ' + name);
}
return 0;
}
我想大多数人都知道intro函数可以访问name,而在factory中不能访问age,这与大多数编程语言相同,js搜索变量是按照作用域链向上一步一步查找的
3、作用域链剖析
但是有些问题这样你还是会产生疑惑,请看下面的代码
var name = 'laruence';
function echo() {
alert(name);
var name = 'eve';
alert(name);
}
echo();
你觉得答案是什么?
laruence
eve
如果你觉得是这样,那么你可以看看下面的内容了因为正确答案是这样
undefined
eve
4、函数的活动对象
在一个函数对象被调用的时候,会创建一个活动对象(也就是一个对象), 然后对于每一个函数的形参,都命名为该活动对象的命名属性, 然后将这个活动对象做为此时的作用域链(scope chain)最前端, 并将这个函数对象的[[scope]]加入到scope chain中
也就是我们找变量其实是在这个活动对象里找的,参数也是在这个活动对象中保存着
下面给出例子
var fun = function(l,r)
{
var name = 'JOJO'
}
此时活动对象中的值(注意,因为现在还是定义阶段所以活动对象中的值会定义为undefined)
object{
l:'undefined',
r:'undefined'
name:'undefined'
}
那么这个活动对象是什么时候创建的呢,答案是预编译阶段
5、JS的预编译阶段
没错,JS是有预编译阶段的,有的同学可能会问,为啥,JS不是解释型语言吗,其实解释性语言也有预编译,它只是不用编译而已,言归正传,下面我们看一个例子
<script>
alert(typeof eve); //function
function eve() {
alert('I am Laruence');
};
</script>
没错,这个时候eve已经被预编译为函数类型了,JS在执行每一段JS代码之前, 都会首先处理var关键字和function定义式(函数定义式和函数表达式).
6、对问题的解释
现在我们回到标题3的那个问题,并对它做出解释
var name = 'laruence';
function echo() {
alert(name);
var name = 'eve';
alert(name);
}
echo();
在预编译过程中函数echo的活动对象已经被浏览器引擎预编译了如下
object:{
name:'undefined'
}
这个时候函数的活动对象中已经有name了,是函数中var 的 name 但是函数中对name的赋值却在第一个alert(name)之后,所以答案是“undefined”
事实上与函数外部的 var name = ‘laruence’;没有关系
这篇博文参考
https://www.cnblogs.com/tyfqwer/p/6268147.html
我做了一些自己的理解与思考,原文更加详细