JavaScript 实现函数重载及类的多构造函数

这个是之前一篇 (http://www.vilic.info/blog/archives/610) 的升级版, 添加了更强的对 “类” 的支持, 取消了Null类型, 顺便修正了一些bug.

脚本链接: http://www.vilic.info/vejis/vejis-mo.js

然后是用法:

/* 函数的用法 */

//创建一个函数并定义重载1
//这里也可以使用 var fn = _(); 创建空函数, 并在以后添加重载
var fn = _(function () {
    alert(“No arguments!”);
});

//重载2
fn._(String, function (str) {
    alert(“You got me a string: ” + str + “.”);
});

//重载3
fn._(String, Integer, function (str, n) {
    alert(“The string is: ” + str + “; and the integer is: ” + n + “.”);
});

fn();
fn(“test1”);
fn(“test2”, 123);

/* 类的用法 */
//定义一个类
var C = class_(function () {
    var x;

    //成员函数
    this.getX = _(function () {
        return x;
    });

    /* 也可无构造函数 */
    //构造函数重载1
    C._(Integer, function (i) {
        x = “Integer: ” + i;
    });

    //构造函数重载2
    C._(String, function (s) {
        x = “String: ” + s;
    });
});

//创建两个C的实例
var c1 = new C(“abc”);
var c2 = new C(123);

alert(c1.getX());
alert(c2.getX());

JavaScript完美实现函数重载

今天Google了一下JS的函数重载, 居然没有发现自己的文章, 结果在博客内搜索了下, 才发现是SEO的问题.

于是, 在这里贡献出暑假的时候写的JS函数重载, 其实它本身是自己的类库vejis的一部分, 不过vejis估计短时间内不会完善了, 所以现在把代码单独提出来, 供大家使用. 至少这是目前我见过的最爽的JS函数重载.

先看示例代码:

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd“>

<html xmlns=”http://www.w3.org/1999/xhtml“>
<head>
    <title>JavaScript完美实现函数重载</title>
    <script src=”vejis-mo.js” type=”text/javascript”></script>
    <script type=”text/javascript”>
        /*
            这个函数重载代码是vejis库的一部分, 现在单独提取出来分享.
            vejis命名空间下有两个特殊的类型, Integer和Null, 在调用vejis.use(vejis)后即可直接使用.
        */

        /*
            使用vejis命名空间, 将目标对象的方法和属性拷贝到window对象, 第二个参数可选, 指示是否覆盖.
            Method, _等都是vejis的成员.
        */

        vejis.use(vejis, true);

        //定义一个方法
        var test = new Method();
       
        //重载, 1个String类型的参数
        test.overload(String, function (msg) {
            alert(msg);
        });
       
        //重载, 1个Integer类型的参数
        test.overload(Integer, function (n) {
            alert(“The integer given is ” + n + “.”);
        });

        test(“Hello, Vejis!”);
        test(57);

        //以下为简写
        var test2 = _(function () {
            alert(“No arguments given.”);
        });

        test2._(Object, String, function (obj, str) {
            alert(“You’ve given me a Object and a String!”);
        });

        //自定义的类型
        test2._(MyClass, function (mc) {
            alert(mc.description);
            mc.sayHello();
        });

        test2();
        test2({}, “”);
        test2(new MyClass());

        function MyClass() {
            this.description = “This is my class.”
            this.sayHello = _(function () {
                alert(“Hello! I am MyClass!”);
            });
        }
    </script>
</head>
<body>
</body>
</html>

木哈哈, 是不是很爽~ 其实这里不止可以实现JS重载普通的函数, 还可以重载类型, 慢慢发掘吧~

脚本在这里, 当然, 因为只是提取的函数重载部分, 其他的我能删的都删了:

http://www.vilic.info/vejis/vejis-mo.js

2011.3.13 文件有改动, 详见: http://www.vilic.info/blog/archives/638

Vejis 开发笔记 2010.8.16

Version: 0.0.0.3

再次改进了重载算法. 然后开始各种杂项的开发, 比如string, array命名空间. 其中部分有enhance方法, 用于加强相应的原型.

之前创建可重载的函数时, 是通过函数内部创建之后return的. 但是一直想使用类似new的方法. 今天也算巩固了下之前很久听说过的一个知识:

function Test() {
    return fn;
    function fn() {
        alert(‘Test OK!’);
    }
}

var test = new Test();
test();

你认为上面的代码能弹出 “Test OK!” 吗? 答案是可以的. 但是这个时候, test instanceof Text == false. 也就是说, test此时并非Test的实例, 而是一个function(){}.

在vejis里, 虽然我最终用类似的方法实现了new Method的操作, 但得到的方法也并非Method的实例:

vejis.use(vejis, true); //使用vejis命名空间, 并且覆盖已有的方法和属性.

var test = new Method(); //创建一个可重载的方法.
test.overload(function(){ //添加一个无参数的重载.
    alert(‘Test’);
});

test(); //执行test方法.
alert(test instanceof Method); //结果是false;

另外还有包含了JSON2.js文件, 准备起床之后实现简单的AJAX函数, 我看着JQuery的, 头晕啊. 太有跳跃性了. 没打算做得它那么全, 满足我日常使用即可.

Vejis 开发笔记 2010.8.15

Version: 0.0.0.2

更改了函数重载的实现, 将原来的字符串变成了类, 扩展性更强. 见下面的MyClass.

vejis.use(vejis, true);

var test = _();

test._(Integer, function (n) {
    alert(‘Integer: ‘ + n);
});

test._(MyClass, function (obj) {
    obj.alert();
});

var obj = new MyClass();
test(18);
test(obj);

function MyClass() {
    this.alert = function () {
        alert(‘It\’s a new Class!’);
    };
}

Vejis 开发笔记 2010.8.14

Version: 0.0.0.1

选择的是BSD协议. 现在有接近200行了. 主要功能是createFunction. 下面来一段演示的代码:

vejis.use(vejis, true);

var test = createFunction();

test._(‘string’, function (name) {
    alert(‘name: ‘ + name);
});

test._(‘int’, function (age) {
   alert(‘age: ‘ + age);
});

呵呵, 看出来了吧, 函数重载. 不过在这个简单的例子上, 你可能觉得有点多余, 看看这个, 这个是vejis里的一个函数, 有4个重载:

var argsCountError = this.argsCountError = createFunction();

argsCountError._(‘integer’, function (count) {
   if (arguments.callee._caller.arguments.length != count)
      error(‘The method needs ‘ + count + ‘ argument’ + (count > 1 ? ‘s.’ : ‘.’));
});

argsCountError._(‘integer, integer’, function (least, most) {
   if (least >= most) error(‘”least” must be smaller than “most”‘);
   var count = arguments.callee._caller.arguments.length;
   if (count < least) error(‘The method needs at least ‘ + least + ‘ argument’ + (least > 1 ? ‘s.’ : ‘.’));
   if (count > most) error(‘The method needs at most ‘ + most + ‘ argument’ + (most > 1 ? ‘s.’ : ‘.’));
});

argsCountError._(‘null, integer’, function (least, most) {
   arguments = arguments.callee._caller.arguments;
   least = 0;
   argsCountError(least, most);
});

argsCountError._(‘integer, null’, function (least, most) {
   arguments = arguments.callee._caller.arguments;
   most = 25;
   argsCountError(least, most);
});

目前为止, 变量类型支持string, number, number:integer, boolean, object, object:array, object:null, function, 考虑到不同人的习惯, integer和boolean分别可以简写作int和bool. 个人觉得在函数重载很多, 而调用次数不多(其实只要不是大数量的枚举, 遍历什么的, 都不算多)时, 这个功能是非常实用的.

另外vejis.use(namespace, overwrite)也是个比较实用的东西, 虽然目前功能还非常简单, 但以后会慢慢增强.

其他的很弱, 也没什么特色了. 慢慢来.