Javascript 函数及其执行环境和作用域

 函数在javascript中可以说是一等公民,也是最有意思的事情,javascript函数其实也是一个对象,是Function类型的实例。因此声明一个函数首先可以使用 Function构造函数:

var saySomething = new Function("something","console.log(something)");
saySomething("hello world!");  // 输出hello world!

Function构造函数可以接受多个参数,但最后一个参数被视为函数体,当然这种方法不直观,因此大部分时候我们使用如下声明:

var saySomething = function(something){
    console.log(something);
};
saySomething("hello world!");  // 输出hello world!

或者:

function saySomething(something){
    console.log(something);
};
saySomething("hello world!");  // 输出hello world!

这样直观也便于理解多了。

由于函数是一个对象,因此函数名就是一个指向函数对象的指针。如下面示例代码:

示例1:

function makeCounter() {
    var i = 0;
    console.log( ++i );
}

var counter2=makeCounter;   //无输出
counter2();  //输出:1
counter2();  //输出:1

 var counter2=makeCounter; 这句其实就是将函数makeCounter的引用给了counter2, counter2就是一个别名,它们都指向同一个函数。因此这句 无输出

 接来下的 counter2(); 两次就是对函数调用两次,每次调用, 局部变量 i 在调用结束后就不能范问了,因此两次返回的结果都是 输出:1

 

当函数第一次被调用时,会创建一个执行环境,以及相应的作用域链。执行环境中定义变量和函数都保存在一个称为变量对象的结构中。执行环境通常可分为全局执行环境和局部执行环境。全局执行环境是最外围的执行环境,根据js的宿主不同而异,在web中是 window对象,在node中是 globle对象。因此所有的全局变量和函数都属于全局执行环境,也就是 window对象的属性和方法。

每个函数都有自己的执行环境,当代码执行进入一个函数时首先将会创建一个执行环境,这个过程首先是创建活动对象,活动对象在一开始是只包含一个变量,即arguments对象,然后是 this对象 以及其他的内部变量。作用域链保存这函数有权访问的执行环境的先后顺序,作用域链的最前端始终是当前执行的代码所在的环境的活动对象,下一个是包含该函数的外部环境,再下一个是包含该函数的外部的外部环境,这样类推,直至全局环境。

当访问一个变量时,需要搜索该变量标识符。搜索过程从作用域链的最前端开始,向上逐级查找,直至第一个找到时停止,如果直到全局环境的活动对象中都找不到,说明该变量未声明。

var color="blue";
function getColor(){
    var color='red';
    return color;
}
console.log(getColor());   // 输出:red

getColor函数首先在当前的执行环境中找到了 color定义,于是输出 red,停止。

 

var color="blue";
function getColor(){
    return color;
}
console.log(getColor());   // 输出:blue

getColor函数首先在当前的执行环境中没有找到 color定义,于是向上一层查找,在全局环境中找到了 color定义,于是输出 blue。

 

另外一个需要注意的是 javascript中是没有块级作用域的,不像 C,Java等,在一对花括号 {  } 包围起来的区域都有自己的作用域。

if(true){
    var color="blue";
}
console.log(color);   // 输出:blue

由于 javascript没有块级作用域,因此,在 { } 之外,仍然能够访问到 color 为 blue的定义。

 

posted @ 2014-09-20 23:55  Tong Zeng  阅读(272)  评论(0编辑  收藏  举报