函数作用域
JavaScript函数是指一个特定代码块,可能包含多条语句,可以通过名字来供其它语句调用以执行函数包含的代码语句。
作用域指的是变量存在的范围。JavaScript只有两种作用域:
- 全局作用域:变量在整个程序中一直存在,所有地方都可以读取。
- 函数作用域:变量只在函数内部存在。
在函数外部声明的就是全局变量,可以在函数内部读取。
var a = 1;
function fn() {
console.log(a);
}
fn(); // 1
在函数内部定义的变量,外部无法读取,这就是局部变量。
function fn() {
var b = 1;
}
b; // Uncaught ReferenceError: b is not defined
函数本身也是一个值,也有自己的作用域。它的作用域与变量一样,就是其声明时所在的作用域,与其运行时所在的作用域无关。
var a = 1;
function fn1(){
function fn2(){
console.log(a)
}
function fn3(){
var a = 4
fn2()
}
var a = 2
return fn3
}
var fn = fn1();
fn() // 2
上面的代码中,我们需要的结果是fn()
的最终输出。我们先一层一层的往上找,fn()
等于fn1()
,所以我们看一下fn1()
的结果。fn1()
里面定义了a
等于2,这就覆盖了全局变量的a
等于1。这时告诉我们返回值是fn3()
,我们在去看fn3()
。fn3()
里面的返回值是fn2()
,fn2()
直接打印了a
的值,并没有设定a
的值。这时,我们就需要去fn2()
的父层去找a
。此时,发现var a = 2
,所以结果为2。
这里我们是通过作用域链来寻找结果的,作用域链是在一个大的作用域下形成的一个关系层。子对象会一级一级的向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的;但是子对象的变量,对父对象是不可见的。
我们在解析函数时应遵守以下规则:
- 函数在执行的过程中,先从自己的内部找变量。
- 如果找不到,再从创建当前函数所在的作用域去找,以此往上。
- 注意找的是变量当前的状态。
立即执行函数表达式
在JavaScript中,一对圆括号()
是一种运算符,跟在函数明之后,表示调用该函数。比如,fn()
就表示调用fn
函数。
立即执行函数表达式是一种利用JS函数生成新作用域的编程方法。
有时我们需要在定义函数之后,立即调用该函数。这时,你不能在函数的定义之后加上圆括号,这会产生语法错误。
funtion() {/*内容*/}();
// Uncaught SyntaxError: Unexpected token {
这是因为,function
可以被当作表达式,也可以当作语句来执行。
为了避免解析上的歧义,JavaScript引擎规定 ,如果function
关键字出现在行首,一律解释成语句。
解决方法就是不要让function
出现在行首,让引擎将其理解成一个表达式。
( function () {} () );
( function () {} ) ();
! function () {} ();
~ function () {} ();
- function () {} ();
+ function () {} ();
这些写法是都是可以的。通常情况下,只对匿名函数使用这种“立即执行函数表达式”。它有三个作用:
- 令函数中声明的变量绕过变量声明前置规则
- 避免新变量被解释成全局变量或函数名占用全局变量名的情况
- 在禁止访问函数内变量声明的情况下,允许外部对函数的调用