作用域
作用域是当前的执行上下文,值和表达式在其中“可见”或可被访问。如果一个变量或表达式不在当前的作用域中,那么它是不可用的。作用域也可以堆叠成层次结构,子作用域可以访问父作用域,反过来则不行。
JavaScript 的作用域分以下三种:
- 全局作用域:脚本模式运行所有代码的默认作用域
- 模块作用域:模块模式中运行代码的作用域
- 函数作用域:由函数创建的作用域
此外,用 [let] 或 [const]声明的变量属于额外的作用域:
- 块级作用域:用一对花括号(一个代码块)创建出来的作用域
由于函数会创建作用域,因而在函数中定义的变量无法从该函数外部访问,也无法从其他函数内部访问 在代码中任何地方都能访问到的对象拥有全局作用域,一般来说以下几种情形拥有全局作用域:
- 最外层函数 和在最外层函数外面定义的变量拥有全局作用域
var outVariable = "我是最外层变量"; //最外层变量
function outFun() { //最外层函数
var inVariable = "内层变量";
function innerFun() { //内层函数
console.log(inVariable);
}
innerFun();
}
console.log(outVariable); //我是最外层变量
outFun(); //内层变量
console.log(inVariable); //inVariable is not defined
innerFun(); //innerFun is not defined
- 所有末定义直接赋值的变量自动声明为拥有全局作用域
function outFun2() {
variable = "未定义直接赋值的变量";
var inVariable2 = "内层变量2";
}
outFun2();//要先执行这个函数,否则根本不知道里面是啥
console.log(variable); //未定义直接赋值的变量
console.log(inVariable2); //inVariable2 is not defined
- 所有 window 对象的属性拥有全局作用域
一般情况下,window 对象的内置属性都拥有全局作用域,例如 window.name、window.location、window.top 等等。
全局作用域有个弊端:如果我们写了很多行 JS 代码,变量定义都没有用函数包括,那么它们就全部都在全局作用域中。这样就会 污染全局命名空间, 容易引起命名冲突。
// 张三写的代码中
var data = {a: 100}
// 李四写的代码中
var data = {x: true}
这就是为何 jQuery、Zepto 等库的源码,所有的代码都会放在(function(){....})()中。因为放在里面的所有变量,都不会被外泄和暴露,不会污染到外面,不会对其他的库或者 JS 脚本造成影响。这是函数作用域的一个体现。
函数作用域,是指声明在函数内部的变量,和全局作用域相反,局部作用域一般只在固定的代码片段内可访问到,最常见的例如函数内部。
function doSomething(){
var blogName="浪里行舟";
function innerSay(){
alert(blogName);
}
innerSay();
}
alert(blogName); //脚本错误
innerSay(); //脚本错误
JavaScript 变量生命周期
JavaScript 变量生命周期在它声明时初始化。
局部变量在函数执行完毕后销毁。
全局变量在页面关闭后销毁。