Ruby's Louvre

每天学习一点点算法

导航

less源码学习

mass Framework决定用less作为自己的CSS重用工具,决定好好学习一下它的源码,说不定以后用mass Framework重写它。

一上来是个经典结构:自动执行函数

(function (window, undefined) {

})(window)

接着是加载器相关的内容

  function require(arg) {
        return window.less[arg.split('/')[1]];
    };

    // amd.js
    //如果引入AMD的加载器,则把它当成一个AMD模块
    if (typeof define === "function" && define.amd) {
        define("less", [], function () {
            return less;
        } );
    }

再接着ecma262v5的语言补丁,我们总得支持IE6

if (!Array.isArray) {
        Array.isArray = function(obj) {
            return Object.prototype.toString.call(obj) === "[object Array]" ||
            (obj instanceof Array);
        };
    }
    if (!Array.prototype.forEach) {
        Array.prototype.forEach =  function(block, thisObject) {
            var len = this.length >>> 0;
            for (var i = 0; i < len; i++) {
                if (i in this) {
                    block.call(thisObject, this[i], i, this);
                }
            }
        };
    }
    if (!Array.prototype.map) {
        Array.prototype.map = function(fun /*, thisp*/) {
            var len = this.length >>> 0;
            var res = new Array(len);
            var thisp = arguments[1];

            for (var i = 0; i < len; i++) {
                if (i in this) {
                    res[i] = fun.call(thisp, this[i], i, this);
                }
            }
            return res;
        };
    }
    if (!Array.prototype.filter) {
        Array.prototype.filter = function (block /*, thisp */) {
            var values = [];
            var thisp = arguments[1];
            for (var i = 0; i < this.length; i++) {
                if (block.call(thisp, this[i])) {
                    values.push(this[i]);
                }
            }
            return values;
        };
    }
    if (!Array.prototype.reduce) {
        Array.prototype.reduce = function(fun /*, initial*/) {
            var len = this.length >>> 0;
            var i = 0;

            // no value to return if no initial value and an empty array
            if (len === 0 && arguments.length === 1) throw new TypeError();

            if (arguments.length >= 2) {
                var rv = arguments[1];
            } else {
                do {
                    if (i in this) {
                        rv = this[i++];
                        break;
                    }
                    // if array contains no values, no initial value to return
                    if (++i >= len) throw new TypeError();
                } while (true);
            }
            for (; i < len; i++) {
                if (i in this) {
                    rv = fun.call(null, rv, this[i], i, this);
                }
            }
            return rv;
        };
    }
    if (!Array.prototype.indexOf) {
        Array.prototype.indexOf = function (value /*, fromIndex */ ) {
            var length = this.length;
            var i = arguments[1] || 0;

            if (!length)     return -1;
            if (i >= length) return -1;
            if (i < 0)       i += length;

            for (; i < length; i++) {
                if (!Object.prototype.hasOwnProperty.call(this, i)) {
                    continue
                }
                if (value === this[i]) return i;
            }
            return -1;
        };
    }

    if (!Object.keys) {
        Object.keys = function (object) {
            var keys = [];
            for (var name in object) {
                if (Object.prototype.hasOwnProperty.call(object, name)) {
                    keys.push(name);
                }
            }
            return keys;
        };
    }

    if (!String.prototype.trim) {
        String.prototype.trim = function () {
            return String(this).replace(/^\s\s*/, '').replace(/\s\s*$/, '');
        };
    }

接着是宿主环境检测与把命名空间放到全局变量下:


 var less, tree;

    if (typeof environment === "object" && ({}).toString.call(environment) === "[object Environment]") {
        //如果是在Rhino环境中
        // Details on how to detect Rhino: https://github.com/ringo/ringojs/issues/88
        if (typeof(window) === 'undefined') {
            less = {}
        } else                                {
            less = window.less = {}
        }
        tree = less.tree = {};
        less.mode = 'rhino';
    } else if (typeof(window) === 'undefined') {
        //如果是在node.js环境中
        less = exports,
        //我们可以把几个模块合并到一个JS文件中,因此如果是打包了,是调当前文件中的tree模块
        tree = require('./tree');
        less.mode = 'node';
    } else {
        //如果是在浏览器环境中
        if (typeof(window.less) === 'undefined') {
            window.less = {}
        }
        less = window.less,
        tree = window.less.tree = {};
        less.mode = 'browser';
    }

下面就是正式的解析器的内容了最主要的用法是new(less.Parser)().parse,是没有传参,env可能是为了向前兼容。 由于方法间的连联太频繁,从原型上调来调去太低效,改成如下结构 // function (){ /*内部方法与对象*/ return parser = {} }

待续!

posted on 2012-09-15 10:59  司徒正美  阅读(1947)  评论(1编辑  收藏  举报