一、什么是作用域
- 作用是对代码的一个读写操作,域是js能够实现的一个范围。
- 在
script
标签中var
的时候,其实是在最大的window上加了一个属性,如果在script
中没有用var
声明,而是直接赋值,那就是自动在window上加一个属性,这是系统在找不到声明的时候,自动加的。
console.log(a);
var a = 1;
console.log(a);
复制代码
console.log(a);
a = 1;
复制代码
a = 1;
console.log(window.a);
复制代码
二、解释器
- js是一种直译式脚本遇到,遇到
script
标签后,解释器就开始工作,没有一个长期的前期准备。 - 解释器执行js代码至少分两步:预解析和执行代码。
- 预解析阶段进行变量声明和函数声明,遇到
var
变量声明后,不去读取赋值,而是自动给变量赋值为undefined,遇到function
函数声明后,不去读/执行函数,而是自动将函数的内容当成一块直接存起来function(){}。function
比var
优先级高,遇到同名的变量名和函数名,函数名会将变量名进行覆盖,而变量名不会将函数名覆盖。如果有重名的函数,则后者会将前者覆盖。 - 解释代码/执行代码期间才真正改变变量的值,先找到预解析找到的变量和函数,如果有能改变变量值的运算
=
、+
、*
、/
、%
、++
、--
,则会修改预先的值。
alert(a);
var a = 1;
alert(a);
function a(){
alert(2);
}
alert(a);
var a = 3;
alert(a);
function a(){
alert(3);
}
alert(a)
a();
复制代码
三、全局作用域和局部作用域
- 全局作用域:最大的作用域是
script
标签之间,全局中的最大对象是window,但是script
标签是分别解释的,代码是自上而下执行的,script
之后还是最大的window,在引入代码的时候,一定要注意引入顺序,因为script
标签是分别解释的。 - 局部作用域:函数内部也是一个空间(函数构建的空间),可以被看做一个局部作用域。
- 如果局部作用域的“预解析空间”(AO-活动对象(Active object))没有找到,那么代码会从上一级的作用域寻找,上级作用域不能在下级作用域寻找。
<script type="text/javascript">
alert(a);
</script>
<script type="text/javascript">
var a = 1;
</script>
复制代码
<script type="text/javascript">
var a = 1;
</script>
<script type="text/javascript">
alert(a);
</script>
复制代码
var a = 1;
function fn1(){
alert(a);
var a = 1;
}
fn1();
alert(a);
复制代码
四、参数
- 形参:相当于隐式声明,在AO上为undefined。
- 实参:会在AO分析的时候,给形参一个初始值。
var a = 1;
function fn1(a){
alert(a);
a = 2;
}
fn1();
alert(a);
复制代码
var a = 1;
function fn1(a){
alert(a);
a = 2;
}
fn1(a);
alert(a);
复制代码
五、作用域的AO分析
- 先看有没有参数,实参会把形参初始化,如果只有形参,那么形参为undefined。
- 再看有没有变量声明。
- 最后看有没有函数声明,函数会把同名变量覆盖。
var age = 99;
function t(age){
alert(age);
}
t(5);
t();
复制代码
function t2(greet){
alert(greet);
function greet(){}
greet = 'hello';
alert(greet);
}
t2(null);
复制代码
function a(b){
alert(b);
function b(){
alert(b);
}
b();
}
a(1);
复制代码
function a(b){
alert(b);
b = function(){
alert(b);
}
b();
}
a(1);
复制代码
六、作用域链
- 内层作用域在寻找变量的时候未找到,会沿着作用域上的AO向上寻找,直到全局。
- AO成链就是作用域链。
;(function(window ,undefined) {
function(){
function(){
function(){
window.document.getElementById()
}
}
}
})(window);
复制代码