🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
## 作用域 **1.1 作用域** 几乎所有的编程语言都有作用域的概念,简单的说,作用域就是变量与函数的可访问范围,即作用域控制着变量与函数的可见性和生命周期。 作用域有全局作用域和局部作用域(一般是在函数内)之分。 **1.1.1 全局作用域** 在代码中任何地方都能访问到的对象拥有全局作用域。 一般来说,拥有全局作用域有以下几种情况: **(1)在最外层的函数和在最外层函数外面定义的变量拥有全局作用域** 例子: ``` var name = 'tg'; function test(){ var name2 = 'tg'; } ``` 在上面的例子中,变量name和函数test()就拥有全局作用域 **(2)所有未定义而直接赋值(不用var关键字声明)的变量被自动声明为拥有全局作用域** ``` funciton test(){ var age = 10; name = 'tg'; } test(); console.log(age); // 会报错undefined console.log(name); // "tg" ``` 变量name拥有全局作用域,而age在函数外面是无法访问到的 **(3)所有window对象的属性拥有全局作用域** window对象的内置属性都由拥有全局作用域,比如window.location、Date对象等 **1.1.2 局部作用域** 局部作用域不像全局作用域,它被限定在一个范围内,最常见的局部作用域就是在函数内部,我们也称为**函数作用域**。 **函数作用域**是指变量能够被使用的代码区间。超出作用域的变量值一般为undefined,或者被其他同名变量值所覆盖。 ``` funciton test(){ var age = 10; console.log(age); } test(); // 10 console.log(age); // 会报错undefined ``` 在上面的例子中,在函数外面是无法访问到变量age的,但在函数内部是可以访问的。 要记住,对于变量或函数,它的作用域取决于定义时的作用域,而不是在调用它的作用域中。 **1.2 作用域链** 在ES 5中,将作用域链称为**词法环境**。 当代码在一个作用域中执行时,会创建变量对象的一个作用域链(scope chain)。 作用域链的用途:保证对执行环境有权访问的所有变量和函数的有序访问。 作用域链的前端,始终都是当前执行的代码所在作用域的变量对象。如果这个环境是函数,则将其活动对象作为变量对象,然后对于每一个函数的形参,都命名为该活动对象的命名属性。 活动对象在最开始只包含一个变量,即arguments对象(在全局环境中是不存在的)。 看一个例子: ``` var name = 'p'; function test(){ var name = 'tg'; function get(){ console.log(name); } get(); } test(); // "tg" ``` 当执行get()时,将创建函数get()的执行环境(调用对象),并将该对象置于作用域链的前端(开头),然后将函数test()的调用对象链接在之后,最后是全局对象,然后从作用域链的前端开始查找标识符name,很显然,变量name的值是"tg"; 作用域链:get() -> test() -> window 每次进入一个新的作用域,都会创建一个用于搜索变量和函数的作用域链。 函数的局部变量不仅有权访问函数作用域中的变量,而且有权访问其他包含(父)环境,乃至全局作用域。但是全局作用域只能访问在全局作用域中定义的变量和函数,不能直接访问局部作用域中的任何数据。 变量的作用域有助于确定应该何时释放内存。 **1.3 JavaScript没有块级作用域** JavaScript中并没有块级作用域。也就是说,对于if、for、while、switch等块结构是没有作用域的。 ``` if(true){ var name = 'tg'; } console.log(name); // "tg" ``` 在if语句里定义了一个name变量,但它并不会向在函数内那样,但函数执行结束后就销毁,而是会一直存在,因为它被添加到了当前的执行环境(也就是全局环境)中。 对于for循环也是一样: ``` for(var i = 0; i < 10; i++){ //循环体 } console.log(i); // 10 ``` **(1)声明变量** 使用var声明的变量会自动被添加到最接近的环境中,比如在函数内部,最接近的环境就是函数的局部环境。如果初始化变量没有使用var声明,会自动被添加到全局环境中。 **(2)查询标识符** 标识符的查询规则是:逐级向上查询,如果在局部环境中找到了该标识符,搜索过程就停止,变量就绪,否则,会继续向上查询,直到全局环境的变量对象,如果在全局环境中也没有找到这个标识符,就表示该变量尚未声明(通常会报错)。 ``` var name = 'tg2'; function test(){ var name = 'tg'; console.log(name); // "tg" } test(); ``` 在上面的例子中,在函数内部已经找到了name标识符,所以返回的是"tg"