Javascript中的函数“在定义它们的作用域里运行,而不是在执行它们的作用域里运行”,这是权威指南里抽象而精辟的总结。
分三步
1 分析参数
2分析变量声明
3分析函数声明
具体步骤
0: 函数运行前的1瞬间, 生成 Active Object (活动对象),下称AO 活动对象(activeObject)可理解为一个记录当前执行的方法【内部执行信息】的对象,记录内部变量集(variables)、内嵌函数集(functions)、实参(arguments)、作用域
链(scopeChain)等执行所需信息,其中内部变量集(variables)、内嵌函数集(functions)是直接从语法分析树
1:
1.1 函数声明的参数,形成AO的属性,值全是undefined,
1.2 接收实参,形成AO相应的属性的值
2把声明的参数,放到活动对象的属性里,形成active object的属性,值全是undefined
3分析变量的声明,(前面加var)如var age 如果AO上已经有age属性则不做任何修改,如果AO上没有age属性,则添加AO属性,因此事没赋值,因此是undefined
4分析函数声明, 如function foo(){}, 则把函数赋给AO.foo属性
注,如果在此之前foo属性已经存在怎么办------答:无情覆盖
1 function t(age){ 2 alert(age); 3 } 4 5 t(5); // 5 6 t(); //undefined 7 8 /* 9 词法分析过程 10 AO {age:undefined} 11 12 13 运行过程 14 t(5) -->AO.age = 5; alert(AO.age) ;//5 15 t() -->AO.age ;// 没得到赋值,还是undefined 16 */
稍微难点的
在函数内部声明var age = 99 ;
function t2(age){ var age=99; alert(age); } t(5);// 99
分析过程
1 形成AO={}
2 分析形参。AO={age;undefined}
3分析var age 发现AO已经有age属性,因此不做任何修改
执行过程
var age =99;
alert(age);
再看这个容易错的题
function t3(greet) { var greet = 'hello'; // 试着把这一句变成 var greet;再做分析 alert(greet); function greet() { } alert(greet); } t3(null); // hello hello /* 词法分析过程: 0: AO = {} 1: 1.1 分析参数 AO = {greet:undefined} 1.2 分析参数 AO = {greet:null} 2: 分析greet变量声明,AO已经有greet属性,因此不做任何影响 3: 分析greet函数声明, AO.greet = function() {} , 被覆盖成函数 执行过程: greet = 'hello'; alert(greet); alert(greet); */
* 函数声明与函数表达式的区别
表达式必有返回值,把返回值(即匿名函数)赋给了一个变量.