作用域
通常来说,一段程序代码中所用到的名字并不是总有效和可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域,作用域的使用提高了程序逻辑的局部性,增强了程序的可靠性,减少了名字冲突。
简单理解:就是代码名字(变量)在某个范围内起作用和效果。
JS的作用域(es6)之前:全局作用域和局部作用域。
全局作用域:整个script标签或者是一个单独的js文件。
局部作用域:在函数内部就是局部作用域(函数作用域),这个代码的名字只在函数内部起效果和作用。
变量的作用域
根据作用域的不同,我们变量分为全局变量和局部变量。
全局变量:在全局作用域下声明的变量。
注意:如果在函数内部没有声明,直接赋值的变量也属于全局变量。
var num = 10;//num就是一个全局变量
局部变量:在局部作用域下声明的变量,或者说在函数内部的变量。
注意:函数的形参也可以看做是局部变量。
function fun() {
var num1 = 10; //num1就是局部变量,只在函数内部使用
}
全局变量可以在函数内部使用,局部变量不可以在函数外部使用。
从执行效率来看全局变量和局部变量:
- 全局变量只有浏览器关闭的时候才会销毁,比较占内存资源。
- 局部变量当我们程序执行完毕就会销毁,比较节约内存资源。
作用域链
只要是代码就有一个作用域,写在函数内部的叫局部作用域,如果函数中还有函数,那么在这个作用域中就又可以诞生一个作用域,根据在内部函数可以访问外部函数变量的这种机制,用链式查找决定那些数据能被内部函数访问,就称为作用域链。
作用域链:内部函数访问外部函数的变量,采取的是链式查找的方式来决定取那个值,这种结构我们称为作用域链。(就近原则)
案例:结果是几?
var a = 1;
function fn1() {
var a = 2;
var b = '22';
fn2();
function fn2() {
var a = 3;
fn3();
function fn3() {
var a = 4;
console.log(a); //a的值为4
console.log(b); //b的值为22
}
}
}
fn1();
预解析
JavaScript代码是由浏览器中的JavaScript解析取来执行的。
JavaScript解析器在运行JavaScript代码的时候分为两步:预解析和代码执行。
- 预解析:js引擎会把js里面的所有var还要function提升到当前作用域的最前面。
- 代码执行:按照代码书写的顺序从上往下执行。
预解析分为变量预解析(变量提升)和函数预解析(函数提升)
- 变量提升:就是把所有的变量声明提升到当前的作用域前面,不提升赋值操作。
console.log(num); //undefined
var num = 10;
//相当于执行了以下代码:
var num;
console.log(num);
num = 10;
fun();
var fun = function() {
console.log(11);
}
//相当于执行了以下代码
var fun;
fun();
fun = function() {
console.log(11);
}
- 函数提升:就是把所有的函数声明提升到当前作用域的最前面,不调用函数。
注意:函数表达式调用必须写在函数表达式的下面。
案例:
var num = 10;
function fn() {
console.log(num);
var num = 20;
console.log(num);
}
fn();
//相当于以下代码:
var num;
function fn() {
var num;
console.log(num);
num = 20;
console.log(num);
}
num = 10;
fn();