javascript函数的定义与执行

要理解javascript函数的定义与执行,首先需要知道这几个重要的概念,现在可以先知道稍后再理解!

函数的执行环境(excution context)、活动对象(call object)、作用域(scope)、作用域链(scope chain)。

接下来,我们以这个函数为例进行分析:

步骤:

1、设置作用域链

当定义函数a的时候,JS解释器会将函数a的作用域链(scope chain)设置为“定义a时a所在的环境”,此处a第一个添加的作用域是window对象。(如果a是一个全局函数,则scope chain中只有window对象。)

个人见解:作用域链里面其实是包含的活动对象,活动对象可以理解为是用来识别作用域的。(就像是一个商场分为A、B、C  三个区,就可以理解为在这个商场的作用域链里面,有A、B、C 3个活动对象,3个范围!(“个人见解,可能不恰当”)。

2、执行环境

当执行函数a的时候,a会进入相应的执行环境(excution context)。

个人见解:创建执行环境分为创建作用域创建活动对象两步。

3、作用域

当创建执行环境的过程中,首先会为a 添加一个scope属性,即a的作用域,其值就是第一步中的scope chain。即a.scope = a的作用域链。

个人见解:可以把作用域和作用域链理解成是名字不同但作用相同!

4、创建活动对象

创建完作用域,紧接着执行环境会创建一个活动对象(call object)。活动对象也是一个拥有属性的对象,但它不具有原型而且不能通过javascript代码直接访问(可以看下面的图或者个人见解理解)。创建完活动对象后,把活动对象添加到a的作用域链的最顶端。此时a的作用域链包含两个对象:a的活动对象和window对象。

下一步是在活动对象上添加一个arguments属性,它保存着调用函数a时所传递的参数。

最后所有的函数a的形参和内部的函数b的引用也被添加到a的活动对象上。在这一步中,完成了函数b的定义,因此如同第3步,函数b的作用域被设置为b所定义的环境,即a的作用域。(就类似于a的作用域链中第一个加入的作用域是window对象。)!

个人见解:(1) 活动对象是一个为了理解而添加的名词,实际不存在,所以不具有原型、也不能用实际代码访问。(类似于磁感线,只是为了描述)

完结:到此,整个函数a从定义到执行的步骤就完成了。此时a返回b的引用给c,又因为函数b的作用域链包含了函数a的活动对象的引用,也就是说b中可以访问到a中定义的所有变量和函数。又函数b被c引用,函数b依赖于a,因此函数a再返回后不会被GC回收(参考最下方javascript的垃圾回收机制)!

当函数b被执行的时候也会像以上步骤一样。因此执行时b的作用域链包含了3个对象:b的活动对象,a的活动对象,window对象,如图所示:

如图所示,当在函数b访问一个变量的时候,搜索顺序是:

b的活动对象 —>b的原型对象(存在的话)—>a的活动对象 —>window对象

变量查找机制:先查找自身的活动对象,如果存在则返回,如果不存在且该函数存在prototype原型对象,则查找原型对象。依次查找a的活动对象、window对象。直到找到为止,如果整个作用域链上没有找到,则返回undefined。

总结:以上提到了两个重要的词语:函数的定义与执行。文中提到函数的作用域是在定义函数的时候就已经确定,而不是在执行的时候确定(参看步骤1和3).用一段代码来说明这个问题:

1 function f(x){
2   var g = function(){ return x;}
3    return g;
4 }
5  var h = f(1);
6 alert(h());

这段代码中变量h指向了f中的那个匿名函数(由g返回,也可以理解为不匿名,因为有名字g(不正规理解))。

(1)h的作用域在定义的时候确定:

个人理解h的作用域链:g的活动对象->f的活动对象->window对象(因为此处h代表的是返回的"g()"函数,既然是定义为准,就应该是定义"g()"函数时确定,所以 h.scope chain = g.scope chain )

网上参考h的作用域链:h的活动对象 ->f的活动对象->window对象

(2)h的作用域在执行(alert( h ( ) )的时候确定:

h的作用域链:h的活动对象->alert的活动对象->window对象。

结果:(1)应该输出1 (2)应该输出undefined  。

实践证明函数的作用域是在定义这个函数的时候就已经确定了!

补充:Javascript的垃圾回收机制

在Javascript中,如果一个对象不再被引用,那么这个对象就会被GC回收。如果两个对象互相引用,而不再被第3者所引用,那么这两个互相引用的对象也会被回收。因为函数a被b引用,b又被a外的c引用,这就是为什么函数a执行后不会被回收的原因。

function a(){

var i = 0;

var b = function(){ alert(++i);}

return b;

}

var c = a();

c();

以上代码如果没有return b; 当函数a执行完后就会被回收!两个对象互相引用(a引用b,b引用a),而不再被第3者所引用(没有返回数据给c),那么这两个互相引用的对象也会被回收。

参考文档:http://www.jb51.net/article/24101.htm  (javascript深入理解js闭包)

时间: 2024-11-11 14:33:13

javascript函数的定义与执行的相关文章

Javascript函数(定义、传值、重载)

Javascript 函数的定义的方式有不止一种. 第一种方式: function fn1(){ alert(typeof fn1); alert(“fn1”); } 在调用的时候直接就可以fu1(); 函数运行的结果就是两个alert:function   fn1. 有必要说明的是,function是一个对象(在后面对对象的说明中也会具体细说),新定义的函数就是function这个类的一个实例.但是function和object的区别就在于在定义两个函数实例fn1和fn2的过程中,实现了对fu

第五章 shell函数的定义、执行、传参和递归函数

第五章 shell函数的定义.执行.传参和递归函数 Bash(Bourne Again shell)也支持函数,在编写大型复杂脚本的时候,可以用函数把代码编写成一个一个功能相对独立的代码块,使代码模块块.结构清晰.有效的减少程序的代码量.但是bash shell是一种解释性语言,执行效率没有编译性语言高. shell函数的定义 格式一:( function name() { command sequence (命令序列) } 格式二: name() { command sequence (命令序

javascript 函数的定义与参数的有无

一.函数定义 function fName(params){ statements; return somevalue;//可以省略 } 注意事项: 1.参数可有,可无.不定义参数,在调用参数时,也可以传入参数: 例如: 1 function add(){ 2 if(arguments.length==1){ 3 alert(arguments[0]); 4 }else if(arguments.length==2){ 5 alert(arguments[0] + arguments[1] );

javascript函数 (二 定义函数的三种方法)

javascript定义函数(声明函数)可以有三种方法:正常方法.构造函数.函数直接量 <html><head></head><body> <script type="text/javascript"> /*javascript定义函数(声明函数)可以有三种方法:正常方法.构造函数.函数直接量.*/ /*1.正常方法 function(param){}*/ function print(msg) { document.writ

javascript 函数1_函数的定义

<!DOCTYPE html> <html> <head> <title>javascript函数</title> <meta charset="UTF-8"> <script type="text/javascript"> //函数的定义第一种方式 function fn1(){ alert("fn1"); } //函数是一个非常特殊的对象,是一个functio

6 JavaScript函数&amp;内置构造&amp;函数提升&amp;函数对象&amp;箭头函数&amp;函数参数&amp;参数的值传递与对象传递

JavaScript函数:使用关键字function定义,也可以使用内置的JavaScript函数构造器定义 匿名函数: 函数表达式可以存储在变量中,并且该变量也可以作为函数使用. 实际上是匿名函数. <body> <p>函数存储在变量后,变量可作为函数使用:</p> <p id="demo"></p> <script> var x = function(a,b){return a+b; }; document.g

JavaScript函数的多种定义方法

缘起 javascript和其他编程语言相比比较随意,所以javascript代码中充满各种奇葩的写法,有时雾里看花,当然,能理解各型各色的写法也是对 javascript语言特性更进一步的深入理解,那么他有几种写法呢? ( function(){…} )() 或者 ( function (){…} () ) 首先要明白两个知识点 js中函数是引用类型: 函数一般执行方式:函数名+(): 下面的例子帮你理解引用类型 var a = function(x,y){ console.log(x + y

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

函数在javascript中可以说是一等公民,也是最有意思的事情,javascript函数其实也是一个对象,是Function类型的实例.因此声明一个函数首先可以使用 Function构造函数: var saySomething = new Function("something","console.log(something)"); saySomething("hello world!"); // 输出hello world! Function

JavaScript 函数定义和调用

普通的函数定义方法: function abs(x):{ if (x >= 0){ return x; }else { return -x ; } } 两种方法是等价的 var abs = function (x):{ if (x >= 0){ return x; }else { return -x ; }; arguments JavaScript还有一个免费赠送的关键字arguments,它只在函数内部起作用,并且永远指向当前函数的调用者传入的所有参数.arguments类似Array但它