Javascript 元编程初探 [1]

引子

元编程会有如下的定义:

一种计算机程序的编写方式,它可以将其它程序(或者其本身)作为数据进行编写和操作,或者在编译时做一部分工作,在运行的时候做另外一部分工作。

在这里讲到的很多也许只和程序对于工作机制的操作有关,但是作为初探也许也就足够了。 鉴于我也是边学边写的这篇文章,如果有谬误之处,还请指出。

创建带有默认参数的函数

function repeat(func, times) {
    times = (Object.prototype.toString.call(times) === '[object Undefined]')?1:times;
    for(var i = 0; i < times; i++){
        func();
    }
}   

在函数中使用 Object.prototype.toString.call(times) 是为了解决 javascript 判断值为空的问题,使用这种写法才会比较的安全。一般情况下 false, 0, undefined, null 还有 空字符串 都会被判断成 false。

创建自优化的行数

在浏览器的实现上会有许多的不同,有时候就需要使用分支。一般情况下都是监测需要调用的对象或者属性是否存在,进而进行下一步的操作,像下面的一样:

function addEvent(elem, type, func){
    if (document.addEventListener) {
        elem.addEventListener(type, func);
    } else {
        elem.attachEvent(type, func);
    }
}

虽然这段代码可能还有很多其它的问题,但是这段代码每次在执行时都会进行一次判断,然而理论上应该可以做到只在第一次运行的时候进行判断: 当第一次调用的时候,针对特定的浏览器去将自己重写成另外的一个版本

function newAddEvent (elem, type, func) {
    if (document.addEventListener){
        newAddEvent = function(element, type, func){
            element.addEventListener(type, func);
        }
    } else {
        newAddEvent = function(element, type, func){
            element.attachEvent(type, func);
        }
    }
    newAddEvent(elem, type, func);
}

在这个函数中,第一次调用的时候会进行判断支持的方法类型,然后就会替换掉原来函数的内容,最后都会执行新的函数。虽然这个是一个简单的例子,但是可以把它引申并且使用到其它复杂的环境中去,这样就可以提高运行的效率了。

面向特征编程(AOP)

面向特征编程的全称是: Aspect-oriented Programming。面向特征编程本质上就是使用函数执行前后的代码去扩展当前的函数,而不是使用继承的方式去扩展。

在调试一段代码的时候,需要在这个代码被调用的时候写一些日志,包括 传入的参数以及函数调用之后的返回值,并且这样不会影响到函数的正常执行 ,我们可以这样写:

Bar = {
    foo: function(){ ... }
};

Bar.foo = Bar.foo.debug(function(original, args){
        var _r;
        console.log(args);
        _r = original(args);
        console.log(_r);
        return _r;
});

(注: 此处的参数部分简略写了,不要在意这些细节~) 我在这里扩展了Function的prototype的方法,将原始函数作为第一个参数传入,其实还可以稍加改变,在新的一个函数上进行这种包装。 接下来我们来看看debug的实现:

Function.prototype.debug = function(debugger) {
    var _selfMethod = this; // 原始方法的引用
    return function(){
        var args = [];
        for (var i = 0, argsLength = arguments.length; i < argsLength; i++) {
            args.push(arguments[i]);
        }
        return debugger.apply(this, [_selfMethod.bind(this)].concat(args));
    }
};

这段代码首先保存了原始函数的一个引用,然后将参数传入debugger并使用apply执行。


第一次在segmentFault写blog,也是算对自己的一种鞭策吧,记录一些所学习的知识,分享一写学习的心得。

你可能感兴趣的:(javascript,元编程)