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