要理解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).用一段代码来说明这个问题:
 function f(x){
var g = function(){ return x;}
return g;
}
var h = f(1);
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执行完后就会被回收!b引用a,而b不再被第3者c所引用(没有返回数据给c),那么这两个互相引用的对象也会被回收。

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

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

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

    Javascript 函数的定义的方式有不止一种. 第一种方式: function fn1(){ alert(typeof fn1); alert(“fn1”); } 在调用的时候直接就可以fu1() ...

  2. JavaScript 函数的定义-调用、注意事项

    函数定义 函数语句定义 function(a,b){ return a+b; } 表达式定义 var add = function(a,b){return a+b}; //函数表达式可以包含名称,这在 ...

  3. JavaScript 函数全局变量定义

    在 JavaScript 中, 作用域 影响着变量的作用范围.在函数外定义的变量具有 全局 作用域.这意味着,具有全局作用域的变量可以在代码的任何地方被调用. 没有使用var关键字定义的变量,会被自动 ...

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

    javascript定义函数(声明函数)可以有三种方法:正常方法.构造函数.函数直接量 <html><head></head><body> <sc ...

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

    JavaScript函数:使用关键字function定义,也可以使用内置的JavaScript函数构造器定义 匿名函数: 函数表达式可以存储在变量中,并且该变量也可以作为函数使用. 实际上是匿名函数. ...

  6. 在JavaScript函数中使用EL表达式注意的事项

    最近在使用JSP显示从Servlet带过来的数据时,大量的使用到了EL表达式,并且有些EL表达式是在使用到JavaScript的函数时作为参数传入的,举个例子,比如下面的样子: 这个HTML标签的意思 ...

  7. JS:javascript 函数后面有多个小括号是怎么回事?f( )( )( )...

    有时我们看见js函数后面跟着多个小括号是怎么回事?f( )( )( )... f()意思是执行f函数,返回子函数 f()()执行子函数,返回孙函数 f()()()执行孙函数 ()()表示定义并执行,使 ...

  8. JavaScript函数、对象和数组

    一.JavaScript函数 1.定义函数:函数的通用语法如下 function function_name([parameter [, ...]]) { statements; } 由关键字func ...

  9. 深入理解javascript函数定义与函数作用域

    最近在学习javascript的函数,函数是javascript的一等对象,想要学好javascript,就必须深刻理解函数.本人把思路整理成文章,一是为了加深自己函数的理解,二是给读者提供学习的途径 ...

随机推荐

  1. eclipse-搭建maven的war项目集合spring注解方式

    工具:eclipse 4.4.2 版本号:20150219-0600 jdk:1.7 1.下图创建maven工程,然后next 下图选择工程保存位置(这里选择默认),next 下图选择webapp项目 ...

  2. maven中snapshot快照库和release发布库的区别和作用

    在使用maven过程中,我们在开发阶段经常性的会有很多公共库处于不稳定状态,随时需要修改并发布,可能一天就要发布一次,遇到bug时,甚至一天要发布N次.我们知道,maven的依赖管理是基于版本管理的, ...

  3. Java容器之旅:容器基础知识总结

    下图展示了Java容器类库的完备图,包括抽象类和遗留构件(不包括Queue的实现). 常用的容器用黑色粗线框表示,点线框表示接口,虚线框表示抽象类,实线框表示类,空心箭头表示实现关系.Produce表 ...

  4. Leetcode First Bad Version

    You are a product manager and currently leading a team to develop a new product. Unfortunately, the ...

  5. Objective-C 中基于RunTime实现的反射

    一.反射 反射,一般表现在字符串和Class转换,字符串和内部方法转换,字符串和属性的转换(取值和赋值). 二.Objective-C中的反射 OC的反射是基于其Runtime实现的. 以执行某个函数 ...

  6. MVC5-6 帮助类

    视图帮助类 HtmlHelper HtmlHelper给我们封装了大量的常用方法,使我们的开发更具高效.那么其中有哪里是我们常用的呢? BingForm 生成form表单 上图简单的使用了Html.B ...

  7. 大家是怎么做Code Review的?

    先说说我们公司现在的做法,一个团队被人为地分为两个阵营:Senior Developers和Junior Developers,比例差不多是1:1,Senior Developers就担负着对Juni ...

  8. 数据结构作业——N!的位数(斯特灵公式)

    Description 求N!的位数 Input 输入第一行为一个正整数 n(1<=n<=25000). Output 输出 n!的位数. Sample Input 1020 Sample ...

  9. 强大的windbg定位内存泄露,两句命令搞定!

    1.简单配置在windbg程序目录下有个gflags.exe,运行后设置: 运行CMD.EXE,输入"D:\Debugging Tools for Windows (x86)\gflags. ...

  10. linux cat 的深入用法

    命令基于centos6系列,翻译基于官方原文的意思. catcat - concatenatefiles 1117.www.qixoo.qixoo.com and print on the stand ...