函数定义
在Javascript中,定义函数的方式有多种。在此一一介绍:
直接声明
function fn(){
console.log(“使用function语句进行函数定义”);
}
使用函数直接量
var fn = function(){
console.log(“使用函数直接量进行函数定义”)
}
使用Function()构造函数
var fn = new Function(“a”,”b”, “return a+b;”);
第一种和第二种来定义函数时比较常见的,Function()构造函数来定义函数,一般很少用。
我们来看第一种和第二种的区别:
先看个例子:
function func1(){
alert(“1”);
}
func1();
function func1(){
alert(“2”);
}
语句执行结果为2。这里的行为其实非常出乎意料,主要原因是JavaScript 函数声明的”提前”行为。
Javascript允许我们在变量和函数被声明之前使用它们,而第二个定义覆盖了第一种定义(下面会谈到)。
换句话说,上述代码解析后相当于:
function func1(){
alert(“1”);
}
function func1(){
alert(“2”);
}
func1();
再看一个例子:
var func1 = function (){
alert(“1”);
}
func1();
func1 = function (){
alert(“2”);
}
现在语句执行结果为1。func1变量”被提前”了,但是他的赋值并没有被提前。上面代码解析后相当于:
var func1 ; //声明被提前
func1 = function (){
alert(“1”);
}
func1();
func1 = function (){
alert(“2”);
}
推荐阅读:http://www.bootcss.com/article/variable-and-function-hoisting-in-javascript/
函数重载
在同一个作用域内,可以有一组具有相同函数名,仅仅是形参列表不同,这组函数被称作函数重载。然而,从语言角度来说,JS并不支持函数重载。
事实上,在JS的世界里,用相同的名字在同一作 用区域,定义两个函数,而不会引起错误,但真正使用的是最后一个。
但是,这并不能难道万能的JS,它可以通过自身属性去模拟函数重载,请看下面示例:
实现一个计算器函数,如果参数为两个数字,就执行加法运算。如果参数为三个数字,就执行乘法运算。
function calculate() {
if (arguments.length == 2) {
return arguments[0] + arguments[1];
}
if (arguments.length == 3) {
return arguments[0] arguments[1] arguments[2];
}
}
alert(calculate(1, 3));
可以看到JS函数重载是通过arugments对象来实现的。简单介绍下arugments对象: 所有的函数都有自己的一个arugments对象,函数执行时,会将真实的参数,封装成arguments。arguments并不是数组类型,但是可以用调用数组的方式来调用arguments。比如length, index方法。但是push, pop方法是不适用的。
相信很多人应该已经看出上述方式的缺点。随着需求的增多,if分支就会越来越庞大,而且对应的模式也越来越难看。虽然if对于语言来说没啥不好。但我们可 以考虑使用另一个策略来实现这个需求。 这就是一个新的函数重载模式。
代码如下
var map = function(arr, callback, pThis) {
var len = arr.length;
var rlt = new Array(len);
for (var i = 0; i < len; i++) {
if (i in arr) rlt[i] = callback.call(pThis, arr[i], i, arr);
}
return rlt;
}
/**
函数参数重载方法 overload,对函数参数进行模式匹配。默认的dispatcher支持和…以及?,”“表示一个任意类型的参数,”…”表示
多个任意类型的参数,”?”一般用在”,?…”表示0个或任意多个参数@method overload
@static
@optional {dispatcher} 用来匹配参数负责派发的函数
@param {func_maps} 根据匹配接受调用的函数列表
@return {function} 已重载化的函数
/
var FunctionH = {
overload: function(dispatcher, funcmaps) {
if (!(dispatcher instanceof Function)) {
func_maps = dispatcher;
dispatcher = function(args) {
var ret = [];
return map(args, function(o) {
return typeof o
}).join();
}
}
return function() {
var key = dispatcher([].slice.apply(arguments));
for (var i in func_maps) {
var pattern = new RegExp(“^” + i.replace(““, “[^,]_”).replace(“…”, “.“) + “$”);
if (pattern.test(key)) {
return func_maps[i].apply(this, arguments);
}
}
}
}
};
FunctionH.overload 包括两个参数,一个是负责处理匹配条件的dispatcher函数(可缺省),另一个是一组函数映射表,默认dispatcher函数是根据 实际调用的参数类型生成一个字符串,例如调用的三个参数依次为10、”a”、[1,2]将生成”number,string,array”,具体实现模式匹配的时候,将根 据函数映射表的每一个”key”生成一个正则表达式,用这个正则表达式匹配dispatcher函数的返回值,如果匹配,则调用这个key对应的处理函数,否 则依次匹配下一个key。这样刚才那个计算机函数的需求就可以写成为:
var Calculate = FunctionH.overload({
‘number,number’: function () {
return arguments[0] + arguments[1];
},
‘number,number,number’: function () {
return arguments[0] arguments[1] arguments[2];
}
});
alert(Calculate(1,2,3));