Underscore骨骼
2011-07-02 15:49 BlueDream 阅读(2398) 评论(2) 编辑 收藏 举报上次写过一篇QWrap骨骼的文章,个人认为,想要了解一个库或框架,首先从他的核心思想入手,理解其思想,那么剩余的就仅仅是方法的堆砌。近年比较火的一个jsMVC框架backbone他的核心强依赖库为underscore。
抽空提取了一下他的骨骼,其实主要就是他的链式操作的实现,别个剩下的就是具体函数的实现了,当然对于Underscore函数式也是它的最大亮点,可以好好看下函数的实现。
<!DOCTYPE html>
<html>
<head>
<title> Underscore骨骼 </title>
</head>
<body>
<script type="text/javascript">
// Underscore骨骼
(function () {
var root = this;
var breaker = {};
var ArrayProto = Array.prototype, ObjProto = Object.prototype;
var nativeForEach = ArrayProto.forEach,
nativeMap = ArrayProto.map,
nativeFilter = ArrayProto.filter,
nativeKeys = Object.keys;
var slice = ArrayProto.slice,
unshift = ArrayProto.unshift,
hasOwnProperty = ObjProto.hasOwnProperty;
// 构造函数
var _ = function (obj) { return new wrapper(obj); };
// 向全局暴露接口
root._ = _;
// 类型检测
_.isNumber = function (obj) {
return !!(obj === 0 || (obj && obj.toExponential && obj.toFixed));
};
_.isFunction = function (obj) {
return !!(obj && obj.constructor && obj.call && obj.apply);
};
// 遍历扩展
var each = _.each = _.forEach = function (obj, iterator, context) {
if (obj === null) return;
if (nativeForEach && obj.forEach === nativeForEach) {
obj.forEach(iterator, context);
} else if (_.isNumber(obj.length)) {
for (var i = 0, l = obj.length; i < l; i++) {
if (iterator.call(context, obj[i], i, obj) === breaker) return;
}
} else {
for (var key in obj) {
if (hasOwnProperty.call(obj, key)) {
if (iterator.call(context, obj[key], key, obj) === breaker) return;
}
}
}
};
// 返回对象上面的函数名
_.functions = _.methods = function (obj) {
return _.filter(_.keys(obj), function (key) { return _.isFunction(obj[key])}).sort();
};
// 过滤数组
_.filter = _.select = function (obj, iterator, context) {
var results = [];
if (obj == null) return results;
if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);
each(obj, function (value, index, list) {
if (iterator.call(context, value, index, list)) results[results.length] = value;
});
return results;
};
// 获取key值
_.keys = nativeKeys || function (obj) {
if (obj !== Object(obj)) throw new TypeError('Invalid object');
var keys = [];
for (var key in obj) if (hasOwnProperty.call(obj, key)) keys[keys.length] = key;
return keys;
};
// 用于实验的map方法
_.map = function (obj, iterator, context) {
var results = [];
if (obj == null) return results;
if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
each(obj, function (value, index, list) {
results[results.length] = iterator.call(context, value, index, list);
});
return results;
};
// 链式操作主要部分
var wrapper = function (obj) { this._wrapped = obj; };
_.prototype = wrapper.prototype;
// 扩展自定义方法到Wrap包装器上
_.mixin = function (obj) {
each(_.functions(obj), function (name) {
addToWrapper(name, _[name] = obj[name]);
});
};
// 是否对结果进行链式包装返回
var result = function (obj, chain) {
return chain ? _(obj).chain() : obj;
};
// 将方法扩展到包装器的原型上
var addToWrapper = function (name, func) {
wrapper.prototype[name] = function () {
var args = slice.call(arguments);
unshift.call(args, this._wrapped);
return result(func.apply(_, args), this._chain);
};
};
// 将所有Underscore上的方法添加到Wrap包装器上
_.mixin(_);
// 扩展Array上的方法到wrap包装器上-包装原数组
each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function (name) {
var method = ArrayProto[name];
wrapper.prototype[name] = function () {
method.apply(this._wrapped, arguments);
return result(this._wrapped, this._chain);
};
});
// 扩展Array上的方法到wrap包装器上-包装返回值
each(['concat', 'join', 'slice'], function (name) {
var method = ArrayProto[name];
wrapper.prototype[name] = function () {
return result(method.apply(this._wrapped, arguments), this._chain);
};
});
// 添加链式方法的实现
wrapper.prototype.chain = function () {
this._chain = true;
return this;
};
// 提取链式包装的内容
wrapper.prototype.value = function () {
return this._wrapped;
};
})();
// 结果测试 步骤:将数组[1,2,3]进行链式包装,然后将其用val * 2来map,紧接着用filter进行val < 5过滤,
// 然后pop,concat最后获取其值value
var re = _([1,2,3]).chain().map(function (val) {
return val * 2;
}).filter(function (val) {
return val < 5;
}).pop().concat(['5']).value();
alert(re);
</script>
</body>
<html>
<head>
<title> Underscore骨骼 </title>
</head>
<body>
<script type="text/javascript">
// Underscore骨骼
(function () {
var root = this;
var breaker = {};
var ArrayProto = Array.prototype, ObjProto = Object.prototype;
var nativeForEach = ArrayProto.forEach,
nativeMap = ArrayProto.map,
nativeFilter = ArrayProto.filter,
nativeKeys = Object.keys;
var slice = ArrayProto.slice,
unshift = ArrayProto.unshift,
hasOwnProperty = ObjProto.hasOwnProperty;
// 构造函数
var _ = function (obj) { return new wrapper(obj); };
// 向全局暴露接口
root._ = _;
// 类型检测
_.isNumber = function (obj) {
return !!(obj === 0 || (obj && obj.toExponential && obj.toFixed));
};
_.isFunction = function (obj) {
return !!(obj && obj.constructor && obj.call && obj.apply);
};
// 遍历扩展
var each = _.each = _.forEach = function (obj, iterator, context) {
if (obj === null) return;
if (nativeForEach && obj.forEach === nativeForEach) {
obj.forEach(iterator, context);
} else if (_.isNumber(obj.length)) {
for (var i = 0, l = obj.length; i < l; i++) {
if (iterator.call(context, obj[i], i, obj) === breaker) return;
}
} else {
for (var key in obj) {
if (hasOwnProperty.call(obj, key)) {
if (iterator.call(context, obj[key], key, obj) === breaker) return;
}
}
}
};
// 返回对象上面的函数名
_.functions = _.methods = function (obj) {
return _.filter(_.keys(obj), function (key) { return _.isFunction(obj[key])}).sort();
};
// 过滤数组
_.filter = _.select = function (obj, iterator, context) {
var results = [];
if (obj == null) return results;
if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);
each(obj, function (value, index, list) {
if (iterator.call(context, value, index, list)) results[results.length] = value;
});
return results;
};
// 获取key值
_.keys = nativeKeys || function (obj) {
if (obj !== Object(obj)) throw new TypeError('Invalid object');
var keys = [];
for (var key in obj) if (hasOwnProperty.call(obj, key)) keys[keys.length] = key;
return keys;
};
// 用于实验的map方法
_.map = function (obj, iterator, context) {
var results = [];
if (obj == null) return results;
if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
each(obj, function (value, index, list) {
results[results.length] = iterator.call(context, value, index, list);
});
return results;
};
// 链式操作主要部分
var wrapper = function (obj) { this._wrapped = obj; };
_.prototype = wrapper.prototype;
// 扩展自定义方法到Wrap包装器上
_.mixin = function (obj) {
each(_.functions(obj), function (name) {
addToWrapper(name, _[name] = obj[name]);
});
};
// 是否对结果进行链式包装返回
var result = function (obj, chain) {
return chain ? _(obj).chain() : obj;
};
// 将方法扩展到包装器的原型上
var addToWrapper = function (name, func) {
wrapper.prototype[name] = function () {
var args = slice.call(arguments);
unshift.call(args, this._wrapped);
return result(func.apply(_, args), this._chain);
};
};
// 将所有Underscore上的方法添加到Wrap包装器上
_.mixin(_);
// 扩展Array上的方法到wrap包装器上-包装原数组
each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function (name) {
var method = ArrayProto[name];
wrapper.prototype[name] = function () {
method.apply(this._wrapped, arguments);
return result(this._wrapped, this._chain);
};
});
// 扩展Array上的方法到wrap包装器上-包装返回值
each(['concat', 'join', 'slice'], function (name) {
var method = ArrayProto[name];
wrapper.prototype[name] = function () {
return result(method.apply(this._wrapped, arguments), this._chain);
};
});
// 添加链式方法的实现
wrapper.prototype.chain = function () {
this._chain = true;
return this;
};
// 提取链式包装的内容
wrapper.prototype.value = function () {
return this._wrapped;
};
})();
// 结果测试 步骤:将数组[1,2,3]进行链式包装,然后将其用val * 2来map,紧接着用filter进行val < 5过滤,
// 然后pop,concat最后获取其值value
var re = _([1,2,3]).chain().map(function (val) {
return val * 2;
}).filter(function (val) {
return val < 5;
}).pop().concat(['5']).value();
alert(re);
</script>
</body>
< /html>