从一个傻x问题开始……画地为牢一下午,还是第二天才发现问题所在。下面把问题挂出来,大家引以为戒。
初学JavaScript的宝宝额,写了一段想绕死我自己的程序,不要觉得怎么这么搞笑额 [ 翻白眼 ]
(function(){
function fn(){
document.write('1');
setTimeout('fn()',3000);
}
})()
fn函数为什么不执行为什么为什么…呵呵,不调用怎么执行!以上代码只是让外层函数立即执行,fn()函数并没有被调用。
将里层函数fn()添小括号立即执行后,还出现了一个问题:setTimeout() 的第一个参数写为代码串,即为 setTimeout(“fn()”,3000) 形式时会出错,改为 setTimeout( fn, 3000) 会正确执行。setTimeout()方法的第一个参数可以是代码串,仿照setTimeout("alert('out!')",3000),写了第一种形式,但有错误额…这是什么原因?待我慢慢道来。
javascript中函数定义有两种方式。
1. 函数声明
形式为 function fn( ) { },ECMAScript规范规定函数声明必须始终带有一个标识符,也就是我们常说的函数名,即这里的fn。
函数名在自身作用域和父作用域内是可获取的。
就像变量声明必须以“var”开头一样,函数声明必须以“function”开头。
函数声明只能以fn( )形式调用。
2. 函数表达式
形式通常为var fn = function( ){ },函数定义为表达式语句的一部分,通常是变量赋值的形式。
函数定义部分可以是匿名的,也可以是命名的,但此时函数名在作用域外是不可获取的。
函数表达式不能以“function开头”!所以下面例子中最后一个匿名表达式要用小括号将其括起来。这点,另一篇关于立即执行的笔记中有说明噢。
函数表达式可以后面加括号立即调用该函数,而函数声明不可以。
匿名函数属于函数表达式。然后就出现了以下各种形式。
//annoymous function expression
var fn = function(){
return 3;
}
//named function expression
var fn = function a(){
return 3;
}
//self invoking function expression
(function sayHello(){
alert('hello!');
})(); //这里加小括号立即执行,是因为这是一个函数表达式。sayHello看起来像是一个函数声明,实则因为加了括号,不再以function开头,变为表达式。
关于函数声明和函数表达式二者的区别,除了上面列出的各种外,还有一个函数提升的问题,这里就不多讲啦。
回到最初的问题,现在将代码改为如下。
(function (){
function fn(){
document.write('1');
setTimeout('fn()',3000);
}
fn();
})();
将外层函数剥掉显得更直观,当初出错就是因为受外层函数的影响。现在代码如下。
(function fn(){
document.write('1');
setTimeout('fn()',3000);
})();
问题来了……此时仍然不能运行,报错 fn is not defined……
我尝试修改为以下两种形式,都能正确执行。
(function fn(){
document.write('1');
setTimeout(fn,3000);
})();
function fn(){
document.write('1');
setTimeout('fn()',3000);
}
fn();
尝试解读……欢迎批评指正。
首先,修改后的第一种写法传递的是Function,它会从当前作用域向上查找,直到找到fn。实名函数可以在自身作用域中调用自己,就是这个道理。而且此时fn变量实际指向了一个内存地址。
而最开始的字符串写法仅仅是个字符串,按值传递,下次调用或者运行时内存在哪里已经不确定了,所以找不到作用域。此时只能在全局中查找,而恰巧定义的fn函数并不在全局中。当fn()函数被括号包裹立即执行时,已经形成了一个私有作用域,fn只在该私有域下存在,所以会报错“fn没有被定义”。
那修改后的第二种写法也是字符串形式,为什么就可以了呢?因为此时只在全局中查找!修改后的fn()是在全局中定义的。
这与之前理解的setTimeout是一个Window对象方法无关,不管setTimeout是什么的方法,只要能访问到参数函数就能执行。
以下是之前理解的,有误,勿参考!!
【首先setTimeout是一个window对象方法,当第一个参数写为'fn()'字符串形式时,其实执行的是window.fn()。当fn()函数被括号包裹立即执行时,已经形成了一个私有作用域,fn只在该私有域下存在,在全局内不存在,所以会报错“fn没有被定义”。】