js~函数声明与函数表达式
1 概述
js是一门动态语言,动态语言只有运行时的概念。运行时处理的一切都是对象,包括对象赋值、对象执行;这些对象是有区别的,如函数对象可以使用函数操作符'()'调用,而像{}、[]等就不能使用函数操作符。 故在运行时,语言设计上的不同成份会有不同的处理方式。本文的关注点是运行时函数声明和函数表达式的不同处理。
2 概念
js定义函数的方式有2种,一是函数声明,二是函数定义。
2.1 函数声明
独立的函数体定义,结尾不加分号; 如,function 函数名称 () {函数体}
2.2 函数表达式
在表达式中赋给变量,或者在对象中赋给对象属性; 如,var 变量 = function [函数名称] () {}; //函数名称可以不定义,作为匿名函数
3 示例
测试环境: node.js v0.9.5-pre
/** * Auther: dzh <dzh_11@hotmail.com> * Version: t_func_expr_decl.js,v 1.0 2013/04/30 14:47:04 * Runtime: node.js v0.9.5-pre */ /*函数声明*/ console.log("------------Test 1-------------"); function func_decl () { function func_decl_inner () { return "func_decl_inner";} //函数声明可以嵌套定义 return "func_decl" + "&" + func_decl_inner.name; } console.log(func_decl.name) //输出“func_decl”,说明函数声明也是对象 console.log(func_decl()); //输出“func_decl&func_decl_inner” console.log("------------Test 2-------------"); /*函数表达式*/ var func = function () { function func_decl_inner () { return "func_decl_inner";} //函数表达式里可以定义函数声明 return "anonymous function" + "&" + func_decl_inner.name; }; console.log(func()); //输出“anonymous function&func_decl_inner” // 作为函数参数调用 console.log("------------Test 3-------------"); var func_invoked = function (func) { try{ return func(); }catch (e){ var func_type = typeof func; return "func's type is "+ func_type + ", but it need function type. " + e.toString(); } }; console.log(func_invoked(func)); //输出“anonymous function&func_decl_inner” console.log(func_invoked(func_decl)); //输出“func_decl&func_decl_inner” // 赋值给变量 console.log("------------Test 4-------------"); var func_ref = func; var func_decl_ref = func_decl; //函数声明赋值给变量,并被作为函数调用 console.log(func_decl_ref()); //输出“func_decl&func_decl_inner” console.log(func_ref()); //输出“anonymous function&func_decl_inner” // 赋值给对象属性 console.log("------------Test 5-------------"); var obj = { // function func_decl () {return "func_dec"} //错误“SyntaxError: Unexpected identifier”,对象内部不能定义函数声明 func: func, func_decl: func_decl, //函数声明可以赋值给对象属性,并作为函数被调用 func_def: function func_def (){ return "func_def";} }; console.log(obj.func_decl()); //输出“func_decl&func_decl_inner“ console.log(obj.func()); //输出“anonymous function&func_decl_inner” console.log(obj.func_def()); //输出“func_def”
4 总结
- 函数声明和函数表达式就实质而言没有不同,都是函数对象,都能赋给变量、对象属性和作为函数参数,然后用函数操作符调用执行。
这点和《JavaScript Patterns》中译名《JavaScript模式》62页“声明Vs表达式: 名称和变量声明提升“中的”它们的定义不能分配给变量或属性,也不能以参数形式出现在函数调用中。“不符。 我觉得这和js解释器有关系,但从语言设计角度,声明和表达式直接定义在处理上应该是保持一致的,因为它们都是函数对象。
- 函数声明只能出现在全局对象、函数声明中。函数声明中可以定义函数声明,内部声明的作用域是父函数对象。
函数声明不能出现在其他对象定义中(如{}),我觉得原因是简化对象语法设计,{对象属性:函数表达式}的形式满足内部定义函数的需求,同时保持对象key:value形式的一致性。
5 参考
《JavaScript模式》 O'REILLY Stoyan Stefanov著 60-62页 “消除术语的歧义” “声明Vs表达式: 名称和变量声明提升“