underscore的封装和扩展
// 1. 不污染全局环境 (function() { // 2. 保留之前同名变量 var previousUnderscore = window._; var _ = function(obj) { return new wrapper(obj); }; // 模块化 if (typeof define === 'function' && define.amd) { define('underscore', [], function() { return _; }); } else if (typeof exports !== 'undefined') { if (typeof module !== 'undefined' && module.exports) { exports = module.exports = _; } exports._ = _; } else { window['_'] = _; } // 3. undersocre链式方案 var wrapper = function(obj) { this._wrapped = obj; }; // 链式包装函数 var result = function(obj, chain) { return chain ? _(obj).chain() : obj; }; // 触发可链式函数 wrapper.prototype.chain = function() { // this._chain用来标示当前对象是否使用链式操作 this._chain = true; return this; }; // 当触发可链式后,用这个来取结果值 wrapper.prototype.value = function() { return this._wrapped; }; // 4.将_的静态方法,赋值给_对象 var ArrayProto = Array.prototype, forEach = ArrayProto.forEach, push = ArrayProto.push; _.each = forEach; _.type = function(obj){ return Object.prototype.toString.call(obj).slice(8,-1).toLowerCase(); } _.isFunction = function(fn){ return (_.type(fn) == "function"); } _.functions = function(obj) { var names = []; for (var key in obj) { if (_.isFunction(obj[key])) names.push(key); } return names.sort(); } _.mixin = function(obj) { forEach.call(_.functions(obj), function(name) { var func = _[name] = obj[name]; _.prototype[name] = function() { var args = [this._wrapped]; push.apply(args, arguments); return result( func.apply(_, args),this._chain); }; }); }; // _是返回wrapper的实例,该实例没有_.protoype的方法 // 所以把 _.prototype 指向了 wrapper.prototype, // 之后往_.prototype添函数,也就是向wrapper.prototype添函数 _.prototype = wrapper.prototype; _.prototype.constructor = _; _.mixin(_); // 5.扩展_对象的方法 // 这些数组方法本身不可链式 forEach.call(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) { var method = ArrayProto[name]; wrapper.prototype[name] = function() { var wrapped = this._wrapped; // 调用Array对应的方法并返回结果 method.apply(wrapped, arguments); var length = wrapped.length; if ((name == 'shift' || name == 'splice') && length === 0) { delete wrapped[0]; } return result(wrapped, this._chain); }; }); // 这些数组方法本身可链式 forEach.call(['concat', 'join', 'slice'], function(name) { var method = ArrayProto[name]; wrapper.prototype[name] = function() { return result(method.apply(this._wrapped, arguments), this._chain); }; }); })(); // 使用实例 // 不可链式方法,使其可链式 // var errorTest = [1,2].push(3).push(4); // push这个函数返回的是函数长度,所以这里会报错 var underscore_obj = _([1, 2]).chain().push(3).push(4); var result_arr = underscore_obj.value(); console.log(result_arr);
合乎自然而生生不息。。。