本文概览:
- 通过添加
sort来重构相同逻辑部分 - 查看
underscore链式调用源码实现
新的需求: 如果我们添加map函数
紧接着上一篇,如果我们需要添加sort怎么办?那么容易
_.prototype.sort = function () {
const obj = this._wrapped
Array.prototype.sort.apply(obj, arguments)
return chainResult(this, obj)
}
很简单的就实现了上述的需求,但是如果我们现在在看一下我们的实现:
_.prototype.reverse = function () {
const obj = this._wrapped
Array.prototype.reverse.apply(obj, arguments)
return chainResult(this, obj)
}
_.prototype.push = function () {
const obj = this._wrapped
Array.prototype.push.apply(obj, arguments)
return chainResult(this, obj)
}
_.prototype.pop = function () {
const obj = this._wrapped
Array.prototype.pop.apply(obj, arguments)
return chainResult(this, obj)
}
_.prototype.shift = function () {
const obj = this._wrapped
Array.prototype.shift.apply(obj, arguments)
return chainResult(this, obj)
}
_.prototype.unshift = function () {
const obj = this._wrapped
Array.prototype.unshift.apply(obj, arguments)
return chainResult(this, obj)
}
_.prototype.sort = function () {
const obj = this._wrapped
Array.prototype.sort.apply(obj, arguments)
return chainResult(this, obj)
}
_.prototype.value = function () {
return this._wrapped
}
上面所有实例上的方法,包括reverse, push, pop, shift, unshift, srot其实都是相似的,所以我们想到了提取出去,提取成一个叫做handleArrayMethods 的方法
所以将上述实例上的数组的操作方法提取一下
function handleArrayMethods() {
const methods = ['reverse', 'push', 'pop', 'shift', 'unshift', 'sort']
const ArrayMethod = Array.prototype
methods.forEach(method => {
_.prototype[method] = function () {
const obj = this._wrapped
ArrayMethod[method].apply(obj, arguments)
return chainResult(this, obj)
}
})
}
handleArrayMethods()
然后测试一下之前的case, okok, 跑的通,没问题
我们看一下underscore怎么实现的链式调用?
// underscore-array-methods.js
import _ from './underscore.js';
import each from './each.js';
import { ArrayProto } from './_setup.js';
import chainResult from './_chainResult.js';
// Add all mutator `Array` functions to the wrapper.
// 看这个each 函数,就是和我们实现的 handleArrayMethods 差不多的功能
each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
var method = ArrayProto[name];
_.prototype[name] = function() {
var obj = this._wrapped;
if (obj != null) {
method.apply(obj, arguments);
// 这一段为什么实现?暂时不知道啊哎
if ((name === 'shift' || name === 'splice') && obj.length === 0) {
delete obj[0];
}
}
return chainResult(this, obj);
};
});
// Add all accessor `Array` functions to the wrapper.
each(['concat', 'join', 'slice'], function(name) {
var method = ArrayProto[name];
_.prototype[name] = function() {
var obj = this._wrapped;
if (obj != null) obj = method.apply(obj, arguments);
return chainResult(this, obj);
};
});
export default _;
我们看一下_构造函数实现
// 获取 version 版本
import { VERSION } from './_setup.js';
// 声明 _ 构造函数,好像和我们实现的差不多
export default function _(obj) {
if (obj instanceof _) return obj;
if (!(this instanceof _)) return new _(obj);
this._wrapped = obj;
}
_.VERSION = VERSION;
// 添加 value 来获取 _wrapped 的值
_.prototype.value = function() {
return this._wrapped;
};
// Provide unwrapping proxies for some methods used in engine operations
// such as arithmetic and JSON stringification.
_.prototype.valueOf = _.prototype.toJSON = _.prototype.value;
_.prototype.toString = function() {
return String(this._wrapped);
};
在看一下chainResult的实现
// _chainResult.js
import _ from './underscore.js';
// Helper function to continue chaining intermediate results.
export default function chainResult(instance, obj) {
// 为啥_chain是true的时候又给obj包了一下,直接返回instance 不行吗?
return instance._chain ? _(obj).chain() : obj;
}