学习javascript时最困惑的就是函数及其作用域,钻研了这么久也有了一些心得,以下为个人见解,如果有错误请指出,谢谢~
本文中没有讨论通过Function()构造函数创建函数时的情况,因为这种情况下会动态地创建和编译javascript代码,并且创建出来的函数并不使用词法作用域(请参考《JavaScript权威指南》),而是被当作顶级函数来编译。
作用域指的是一个抽象的范围,如果解析一个变量名时能够找到它则说明这个变量存在于这个作用域中。而具体查找的过程则是顺着作用域链从头到尾来查找的。
先来看一段代码,默认在全局作用域内执行,方便起见可以直接在Firebug控制台执行:
var a=0; var b=1; function F(x) { var b=0; arguments.callee.c=1; alert(F.c); alert(F.e); alert(arguments.callee === F); function G(y){ alert(y); alert(F.e); }; G(2); } F.e=0;
我们知道每个javascript执行环境都有一个和它相关联的作用域链,在顶层代码中(不属于任何函数定义的代码),作用域链只由一个对象构成,即全局对象。因此执行之后作用域链就是全局对象,如下所示(注意我们这时候只是定义了函数,但并没有执行):
接下来进入重点了,执行以下代码:
F(1);
在执行一个函数时,会根据函数体创建一个调用对象并且把它添加到作用域链的头部,并且更新指向作用域链头部的指针为新创建的调用对象。函数体内部通过var语句声明的局部变量,有名称的嵌套函数以及函数的形式参数都是这个调用对象的属性。此时作用域链如下所示:
注意F引用的是函数对象,不是调用对象(从作用域链头部开始解析“F”,在全局对象中找到了“F”)。调用对象的属性arguments具有特殊的作用,arguments.callee引用的是该函数的函数对象,即F。因此执行
arguments.callee.c=1;
函数对象F增加了一个属性c,并且定义了嵌套函数G,此时作用域链如下:
因此执行
alert(F.c); alert(F.e);
依次显示1,0。并且执行
alert(arguments.callee === F);
显示true。
执行
G(2);
由于调用了函数,因此又创建了新的调用对象并且添加到作用域链头部,此时作用域链如下:
所以执行
alert(y); alert(F.e);
分别显示2,0。
每当退出一个函数便会移除并销毁相对应的调用对象(因为没有任何引用了,所以被垃圾回收了),作用域链也就恢复到了之前的状态,形成了一种类似堆栈的效果。
最后来看一下闭包,执行以下代码:
function F(){ var id=0; function G(){ return id++; } return G; } var H=F();
执行完毕之后虽然已经退出了函数,但是其调用对象依旧存在,因为全局对象H引用了其内部的函数(弧形箭头所示),如下:
然后执行
H();
注意此时由于H引用的是G,因此指向作用域链头部的指针会从指向全局对象直接改变为指向根据G函数新创建的调用对象B,B成为了作用域链的头部,然后是之前就已经存在的调用对象A和全局对象。作用域链如下:
退出函数之后指向作用域链头部的指针则又重新指向了全局对象,B会被垃圾回收销毁,但是A依然会存在,因为仍然有H引用。
相关推荐
函数和作用域是JavaScript的重要组成部分,我们在使用JavaScript编写程序的过程中经常要用到这两部分内容,作为初学者,我经常有困惑,借助写此博文来巩固下之前学习的内容。 (一)JavaScript函数 JavaScript函数是...
这个作用域链是一个对象列表或对象链。当javascript需要查询变量x的值时,它就开始查看该链的第一个对象。如果那个对象有一个叫x的属性,那么就采用这个属性的值。要是第一个对象没有叫x的属性,那么继续查询链中的...
作用域 Scope Javascript 中的函数属于词法作用域,也就是说函数在它被定义时的作用域中运行而不是在被执行时的作用域内运行。这是犀牛书上的说法。但”定义时”和”执行(被调用)时”这两个东西有些人搞不清楚。...
内层函数只能在外层函数作用域内执行,在内层函数执行的过程中,若需要引入某个变量,首先会在当前作用域中寻找,若未找到,则继续向上一层级的作用域中寻找,直到全局作用域,我们称这种链式的查询关系为作用域链。...
全书共9章,分别介绍了JavaScript函数式编程、一等函数与Applicative编程、变量的作用域和闭包、高阶函数、由函数构建函数、递归、纯度和不变性以及更改政策、基于流的编程、类编程。除此之外,附录中还介绍了更多...
闭包和作用域链是JavaScript中比较重要的概念,这两天翻阅了一些资料,把相关知识点给大家总结了以下。 JavaScript 采用词法作用域(lexical scoping),函数执行依赖的变量作用域是由函数定义的时候决定,而不是...
即使JavaScript中没有正式的私有对象属性的概念,但可以使用闭包来实现公有方法,而通过公有方法可以访问在包含作用域中定义的变量; 有权访问私有变量的公有方法叫做特权方法; 可以使用构造函数模式、原型模式...
函数表达式 ...即函数调用可置于函数声明之前。 1-2.函数表达式: 代码如下:var funcName = function(arg1,arg2,arg3){ //函数体}; ①匿名函数(anonymous function,或拉姆达函数):function关键字
2. 当函数被创建后, 其父级作用域的作用域链中的所有可变对象会被加入到它的[[scope]]中(如果父作用域是全局, 那么当前函数的作用域链中就只会加入一个全局对象). 3. 当函数被执行时, 函数的执行环境会被推入一个...
在 JavaScript 中, 作用域为可访问变量,对象,函数的集合。 JavaScript 函数作用域: 作用域在函数内修改。 JavaScript 局部作用域 变量在函数内声明,变量为局部作用域。 局部变量:只能在函数内部访问。 // 此处...
函数常常使用这些参数来计算一个返回值,这个值也成为函数调用表达式的值。当一个函数在一个对象上被调用的时候,这个函数就叫做方法(method),它的调用所在的对象就会作为函数的一个隐式的参数来传递。读者可能...
作用域、作用域链、执行环境、执行环境栈以及this的概念在javascript中非常重要,本人经常弄混淆,这里梳理一下; 局部作用域函数内部的区域,全局作用域就是window; 作用域链取决于函数被声明时的位置,解析...
在 JavaScript 中, 作用域为可访问变量,对象,函数的集合。 JavaScript 函数作用域: 作用域在函数内修改。 JavaScript 局部作用域 变量在函数内声明,变量为局部作用域。 局部变量:只能在函数内部访问。 实例 //...
•JavaScript的变量作用域是基于其特有的作用域链的。 •JavaScript没有块级作用域。 •函数中声明的变量在整个函数中都有定义。 1、JavaScript的作用域链首先看下下面这段代码: 代码如下:[removed] var rain = 1; ...
本文实例讲述了JavaScript 作用域。分享给大家供大家参考,具体...2. 函数作用域在函数未被调用之前,已经创建 JavaScript:函数作用域提前创建 function func(){ if(1==1){ var name = 'xsk' } console.log(na
在JavaScript中,闭包的诸多特性源自函数调用过程中的作用域链上。 函数调用对象与变量的作用域链 对于JavaScript中的每一次函数调用,JavaScript都会创建一个局部对象以储存在该函数中定义的局部变量;如果在...
1、背景 Javascript中的回调函数,相信大家都不陌生,最明显的例子是做Ajax请求时,提供的回调函数, 实际上DOM节点的事件处理方法(onclick,ondblclick等)也是回调函数。 在使用DWR的时候,回调函数可以作为第一个...
JavaScript的作用域链 这是一个非常重要的知识点了,了解了JavaScript的作用域链的话,能帮助我们理解很多‘异常’问题。 下面我们来看一个小例子,前面我说过的声明提前的例子。 var name = 'Skylor.min'; ...