JavaScript学习笔记 作用域和 Global 及 window 对象

  《JavaScript 高级语言程序设计》第三章的变量小节介绍了定义局部变量和全局变量的方法,其中介绍的全局变量定义是这样的

function test() {
	message = "hi"; //全局变量
}

  相比于局部变量的定义,它只是省略了 var 操作符。当时我就想,这全局变量的定义还挺方便的,比局部的还简单(学过C语言,全局比局部要多加关键字的)!可我接着往下看的时候却发现,这是一种不被推荐的做法...说什么在局部作用域中定义全局变量很难维护,还会因为忽略 var 操作符导致响应变量不会被马上定义,从而导致不必要的混乱!

  我哪里关心它会造成什么混乱,我只想知道全局变量到底该怎么定义。接着往下看,可我却发现变量这一小节讲完了,开始进入数据类型了。这这这,这什么情况?变量就这么完了?全局变量怎么定义都没说清楚呢!

  吓得我赶紧去看目录。嗯,回来之后安心多了,变量和作用域到第四章才讲,我只是还没看到(虽然我有看一本书之前必先看目录的良好习惯,但这件事说明我是那种目录看过一遍就忘的人...)。继续看我的第三章。可是,如何定义全局变量呢?先把问题记在小本本上。

执行环境和作用域

  执行环境,简称为环境,是 JavaScript 中最重要的一个概念。它定义了变量或函数有权访问的其他数据,决定了它们各自的行为。每个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个对象当中(我们无法直接访问这个对象,但解析器处理数据时会用到它)。当某一执行环境中的所有代码执行完毕后,该环境被销毁,保存在其中的所有变量和函数也随之销毁。

  上文的红色字体有没有让你想到函数?跟执行环境一样,当函数执行完毕后,里面的变量和函数(若有嵌套函数)也会被销毁。这当然不是偶然,事实上,每一个函数都有自己的执行环境。

  执行环境分为全局执行环境函数执行环境。其中,全局执行环境是指最外层的执行环境;而函数执行环境则指函数花括号内的局部的执行环境。

  我认为执行环境是针对每一行代码而言的,指的是这行代码执行时所处的环境。执行环境决定着环境内每行代码执行时有权访问的数据(变量或函数),换一种说法:执行环境里面的代码有权访问该环境内的数据(变量或函数),再换一种说法:在环境中定义的变量或函数的作用域就是它所在的执行环境

  结合全局执行环境的概念,全局变量就是在最外层执行环境内定义的变量。看来全局变量的定义方法比我想的简单得多!无需任何特别的声明方法,只需要在最外层定义就可以了...

在代码上说明

// 最外层环境,即全局环境,
var color = "blue"; // 全局变量,因为在全局环境中定义

function text() {
	// 函数执行环境,即局部环境
	mycolor = "red"; // 局部变量,只在 text_1 函数内部有效
}

作用域链

  当代码在一个环境中执行时,会创建变量对象的一个作用域链。作用域链的用途是,保证执行环境对有权访问的所有变量和函数的有序访问。一个执行环境的作用域链是其自己的变量对象和其所有上级执行环境变量对象的集合(以上面的代码为例:text 函数的上级执行环境就是全局执行环境,如果在 text 函数内定义了一个新函数,则这个新函数的执行环境就是 text 的子执行函数)。

  作用域链的前端,始终都是当前执行代码所在环境的变量对象,作用域链的下一个变量对象则是包裹当前环境的环境的变量对象(即当前环境的父级环境的变量对象)。下面代码中的注释能更形象的说明这一点

var age = 18;
// 这里是全局执行环境,我们假设其变量对象名为: one
// 则该环境的作用域链为:(one)

function text_1() {
	var sex = "man";
	// 这里是局部执行环境,我们假设其变量对象名为:two
	// 则该环境的作用域链为:(two, one)
	
	function text_2() {
		var name = "阿珍";
		// 这里也是局部环境,我们假设其边来那个对象名为:three
		// 则该环境的作用域链为:(three, two, one)
	}
}
// 可以看出,作用域链是有序的

  以上代码为例,当我们在 text_2 函数中访问一个变量时,首先会在 text_2 的变量对象(即 three)中检索该变量;若没有找到,则沿着其作用域链依次检索后面的变量对象(即 two);若还没找到,则在全局执行环境的变量对象中检索(即 one),若还是找不到,就抛出异常,提示该变量没有定义。这就是为什么外面定义的变量在函数里面能用了。

为什么 test_1 中不能使用 test_2 中的变量?

  答:因为每个环境可以向上检索作用域链,而不能向下检索。因为执行环境中的所有代码执行完毕后,该环境被销毁,保存在其中的所有变量和函数也随之销毁,所以对于 test_1 中的代码而言 test_2 中的变量对象是不存在的(要么还没创建,要么已被销毁)。

可以用一句话来总结变量的作用域:内可访外,而外不可访内

Global 和 window 对象

  Global 对象在某种意义上是作为一个“兜底对象”来定义的。即不属于其他对象的属性和方法最终都是它的属性和方法。事实上,没有全局变量或全局函数,在全局作用域内定义的方法和属性都是 Global 对象的方法和属性。也可以理解为 Global 对象就是所谓的全局

  Global 对象并不能直接访问,但 Wbe 浏览器都是将这个全局对象作为 window 对象的一部分加以实现的。所以在全局作用域中声明的变量和函数,就都成了 window 对象的属性。

  而 window 对象可以直接访问

var age = 18;
alert(window.age); //18

你可能感兴趣的:(Wbe)