目标
实现一个 query 方法,实现对数据的链式查询和处理
要求
query传入参数为原始数据(数据格式,每个元素都是对象)- 通过进行链式调用对数据执行操作,支持的方法有
where(predicate):根据参数的条件进行筛选,参数与[].filter的参数类似orderBy(key,desc):根据key的值进行排列,默认升序排列,当第二个参数为true时降序排列groupBy(key):根据key的值对数据元素进行分组,合并为二维数组excuse():执行所有处理并返回最终结果
- 执行
execute方法时才真正执行操作并返回结果 - 请结合下面示例理解需求
function query(data) {
// 在这里输入你的代码
}
const data = [
{ name: "foo", age: 16, city: "shanghai" },
{ name: "bar", age: 24, city: "hangzhou" },
{ name: "fiz", age: 22, city: "shanghai" },
{ name: "baz", age: 19, city: "hanzghou" },
{ name: "bae", age: 23, city: "hangzhou" },
];
query(data)
.where((item) => item.age > 18)
.orderBy("name")
.groupBy("city")
.execute();
// 结果返回
[
[
{ name: 'bae', age: 23, city: 'hangzhou' },
{ name: 'bar', age: 24, city: 'hangzhou' }
],
[ { name: 'baz', age: 19, city: 'hanzghou' } ],
[ { name: 'fiz', age: 22, city: 'shanghai' } ]
]
我的实现
function query(data) {
if (!(this instanceof query)) return new query(data);
this.wrapper = data;
this.callbcakFnStack = [];
}
// where方法
query.prototype.where = function (predicate) {
const _where = function (predicate) {
const len = this.wrapper.length;
const _newArr = [];
if (typeof predicate !== "function") {
throw new Error("传入的参数必须是函数");
}
for (let i = 0; i < len; i++) {
if (predicate.call(this.wrapper, this.wrapper[i], i)) {
if (typeof this.wrapper[i] === "object") {
_newArr.push({ ...this.wrapper[i] });
} else {
_newArr.push(this.wrapper[i]);
}
}
}
this.wrapper = _newArr;
return this;
};
this.pushCallBack(_where.bind(this, predicate));
return this;
};
// orderBy方法
query.prototype.orderBy = function (key, desc) {
const _orderBy = function (key, desc) {
this.wrapper.sort((pre, next) => {
if (typeof pre[key] === "string") {
if (desc) return next[key].localeCompare(pre[key]);
return pre[key].localeCompare(next[key]);
} else if (typeof pre[key] === "number") {
if (desc) return next[key] - pre[key];
return pre[key] - next[key];
} else if (typeof pre[key] === "object" && pre[key] != null) {
throw new Error("目前暂不支持为属性为对象排序");
}
});
return this;
};
this.pushCallBack(_orderBy.bind(this, key, desc));
return this;
};
// groupBy方法
query.prototype.groupBy = function (key) {
const _groupBy = function (key) {
const res = [];
this.wrapper.forEach((n) => {
res[n[key]] = res[n[key]] ? [...res[n[key]], n] : [n];
});
this.wrapper = Object.values(res)
return this;
};
this.pushCallBack(_groupBy.bind(this, key));
return this;
};
// execute 方法
query.prototype.execute = function () {
while(this.callbcakFnStack.length) {
const cb = this.callbcakFnStack.shift()
cb()
}
return this.wrapper;
};
query.prototype.pushCallBack = function (cb) {
this.callbcakFnStack.push(cb);
};
const data = [
{ name: "foo", age: 16, city: "shanghai" },
{ name: "bar", age: 24, city: "hangzhou" },
{ name: "fiz", age: 22, city: "shanghai" },
{ name: "baz", age: 19, city: "hanzghou" },
{ name: "bae", age: 23, city: "hangzhou" },
];
const _ = query(data)
.where((item) => item.age > 18)
.orderBy("name")
.groupBy("city")
.execute();
console.log(_);