函数声明与函数表达式

从一个傻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没有被定义”。】

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值