JavaScript中函数声明与函数表达式的区别详解(2)

//**Simulated processing sequence for Question 2** function foo(){ //a declaration for each function expression var bar = undefined; var bar = undefined; //first Function Expression is executed bar = function() { return 3; }; // Function created by first Function Expression is invoked return bar(); // second Function Expression unreachable } alert(foo()); //3

你可能会说,这还能解释的通,但是 Question 3 的答案错了,我在 Firebug 运行会报错。

把代码保存在 HTML 文件中,之后在 Firefox 上运行试试。或者在 IE8、Chrome 或 Safari 控制台中运行。显然 Firebug 控制台在“global(全局)”作用域(实际并不是全局的,而是特有的“Firebug”作用域——试着在 Firebug 控制台中运行“this == window”你就知道了)运行代码时,不会将函数提升。

Question 3 和 Question 1 的逻辑相似。这次是 foo 函数被提升了。

Question 4 就很简单了,根本就没有函数提升……

可以这么说,但是如果根本没有提升的话,TypeError 会是“bar not defined”,而不是“bar not a function”。此例中确实没有函数提升,但是有变量提升。因此 bar 在开始就被声明了,但是它的值并没有定义。其它代码都是按顺序执行的。

//**Simulated processing sequence for Question 4** function foo(){ //a declaration for each function expression var bar = undefined; var bar = undefined; return bar(); //TypeError: "bar not defined" //neither Function Expression is reached } alert(foo());

还应该注意什么?

官方是禁止在非功能模块(比如 if)中使用 Function Declaration 的。但是所有浏览器都支持,但是各自的解释方式不同。

例如下面的代码段在 Firefox 3.6 中会抛错,因为它将 Function Declaration 解释成了 Function Statement(见上文),所以 x 没有定义。但是在 IE8、Chrome 5 和 Safari 5 中,会返回函数 x(和标准的 Function Declaration 一样)。

function foo() { if(false) { function x() {}; } return x; } alert(foo());

可以看出使用 Function Declaration 可能会引起混淆,那么它有什么优点吗?

你可能会说 Function Declaration 很宽松啊——如果试图在声明前使用函数,提升确实可以修正顺序,以便函数可以正确调用。但是这种宽松不利于严谨的编码,从长远的角度来看,很有可能会促进而不是阻止意外的发生。毕竟,程序员按特定的顺序排列语句是有原因的。

那么还有其它理由支持 Function Expression 的吗?

你猜呢?

1)Function Declaration 感觉像是要模仿 Java 风格的方法声明,但是 Java 方法和 JavaScript 并不一样。在 JavaScript 中,函数是含值的 living 对象。Java 方法仅是对元数据的存储。下面的两段代码都定义了函数,但是只有 Function Expression 看着像创建了对象。

//Function Declaration function add(a,b) {return a + b}; //Function Expression var add = function(a,b) {return a + b};

2)Function Expression 用处更多。Function Declaration 只能作为“statement”孤立存在。它所能做的就是创建一个当前作用域下的对象变量。相比之下,Function Expression(根据定义)是大型结构的一部分。如果想要创建匿名函数、给 prototype(原型)添加函数或是将函数用作其它对象的 property(属性),都可以用 Function Expression。每当用高阶应用,比如 curry 或 compose,创建新的函数时都是在用 Function Expression。Function Expression 和 Functional Programming(函数式编程)分不开。

//Function Expression var sayHello = alert.curry("hello!");

Function Expression 有缺点吗?

Function Expression 创建的函数大多是匿名的。比如下面的函数是匿名的,today 只是一个匿名函数的引用:

var today = function() {return new Date()}

这会有问题吗?多数情况下不会,但是就像 Nick Fitzgerald 指出的,调试匿名函数会很烦。他建议使用 Named Function Expressions (NFEs)作为工作区:

var today = function today() {return new Date()}

但是如 Asen Bozhilov 所说(和 Kangax 文档)NFEs 在 IE9 以下无法正确执行。

结论

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wzfppf.html