牛骨文教育服务平台(让学习变的简单)

作用域

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"