javascript 知识点整理 03 作用域

这部分内容的整理都来自于《js高级程序设计》

执行环境、作用域

执行环境

  • 执行环境
    所有的代码都是在环境中执行的。执行环境定义了变量能够访问到的数据的范围,决定了他们各自的行为。

  • 变量对象
    变量对象存储着当前环境中的所有变量、函数。
    每一个执行环境都有对应的变量对象,变量对象其实是一种底层数据结构,无法通过代码访问。

  • 全局环境
    全局环境指的是当前环境的最外围的执行环境。
    不同的宿主环境有不同的全局环境,一般浏览器环境下全局环境指的就是window对象。
    全局环境的变量对象存储这全局环境中的全局变量、属性等。

  • 环境初始化
    在函数体中,所有的变量声明(var)和函数声明(函数表达式则不会)都会被提前

    1
    2
    3
    4
    5
    6
    func();
    function func() {
    console.log(a); // undefined
    var a = "a" ;
    console.log(a); // "a"
    }
    • 虽然a变量存在于func的执行环境中,第一次打印a时会在当前环境的作用域中寻找变量a,但是由于环境的初始化 ,变量a会在函数体的开始部分声明,但是到了第二行才被赋值,所以第一次打印会返回undefined.
    • 虽然func函数声明位于func()函数执行之后,但是由于函数声明被提前,所以也可以正确解析

      代码执行的过程

    1. 变量声明,函数声明,参数创建(形参)
    2. 函数表达式,代码执行


作用域

  • 作用域链
    执行环境在执行代码的时候,会为对应的变量对象创建一个作用域链。
    作用域链定义了当前环境内的变量如何有序的访问允许范围内的数据。

  • 作用域链的构成
    作用域链的顶端是当前环境的变量对象,往后是外层环境的变量对象,依次往复,最外层是全局环境的变量对象。
    如果当前环境是一个函数,那么其变量对象就是当前函数的活动对象。活动对象初始只有arguments一个变量。

  • 标识符解析/作用域链的主要作用
    标识符会沿着作用域链进行解析。如果无法在当前环境下找到标识符,则会顺着作用域链往后查询。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//内部环境获取外部数据
var color1 = "red" ;
function getColor() {
var color2 = "blue" ;
console.log(color1);
}
getColor(); //"red"
//外部环境无法获取内部数据
var color1 = "red" ;
function foo() {
var color2 = "blue" ;
function bar() {
var color3 = "yellow" ;
console.log(color2);
}
}
foo(); //"blue"
console.log(color1); //"red"
console.log(color2); //undefined

作用域链定义了内部环境可以查询外部环境的数据,但是外部环境无法对内部环境进行操作。(因此可以进行函数体的封装)

  • 延长作用域链

使用with语句可以将传入对象添加到当前作用域链的最顶端

1
2
3
4
5
6
7
8
9
10
function func () {
var rst = "current url is :" ;
with(location) {
var url = href ; //href是location对象的属性,当前执行环境是location对象
var rst = rst + url ;
}
return rst ;
}

eval bind apply call try-catch

  • 没有块级作用域

说白了就是在if和for-in等语句内部创建的局部变量,在当前执行环境内都是可以访问得到

  • 变量声明

var可以声明局部变量,不用的话是声明全局变量。

严格模式要求必须要先声明,不然会导致错误