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可能是为了向前兼容。 由于方法间的连联太频繁,从原型上调来调去太低效,改成如下结构
待续!
机器瞎学/数据掩埋/模式混淆/人工智障/深度遗忘/神经掉线/计算机幻觉/专注单身二十五年