shfshanyue / Daily-Question

互联网大厂内推及大厂面经整理,并且每天一道面试题推送。每天五分钟,半年大厂中
https://q.shanyue.tech
4.92k stars 508 forks source link

【Q691】如何实现一个 ORM 类似的 find 链式调用 #712

Open shfshanyue opened 3 years ago

shfshanyue commented 3 years ago

如下代码所示,使用 find 函数实现链式调用


const data = [
  {userId: 8, title: 'title1'},
  {userId: 11, title: 'other'},
  {userId: 15, title: null},
  {userId: 19, title: 'title2'}
];

// 查找data中,符合where中条件的数据,并根据orderBy中的条件进行排序
const result = find(data).where({
  "title": /\d$/   // 这里意思是过滤出数组中,满足title字段中符合 /\d$/的项
}).orderBy('userId', 'desc');  // 这里的意思是对数组中的项按照userId进行倒序排列

//=> 返回 [{ userId: 19, title: 'title2'}, { userId: 8, title: 'title1' }];
console.log(result.value); 
shfshanyue commented 3 years ago

代码见 codepen,如何实现链式调用

function find (data) {
  return {
    data,
    where (match) {
      this.data = this.data.filter((item) => {
        return Object.entries(match).every(([key, value]) => {
          if (value instanceof RegExp) {
            return value.test(item[key])
          }
          return item[key] === value
        })
      })
      return this
    },

    orderBy (key, type) {
      this.data.sort((x, y) => type !== 'desc' ? x[key] - y[key] : y[key] - x[key])
      return this
    }
  }
}
haotie1990 commented 3 years ago
function find(data) {
  class FindManager {
    constructor(data) {
      this.data = data;
    }
    where(query) {
      const data = [...this.data];
      return new FindManager(data.filter((item) => {
        return Object.entries(query).every(([key, filter]) => {
          if (Object.prototype.toString.call(filter).slice(8, -1) === 'Regex') {
            return filter.test(item[key]);
          } else {
            return filter === item[key];
          }
        });
      }));
    }
    orderBy(key, order) {
      const data = [...this.data];
      data.sort((a, b) => {
        return order === 'asc' ? a[key] - b[key] : b[key] - a[key];
      });
      return new FindManager(data);
    }
    get value() {
      return this.data;
    }
  }
  return new FindManager(data);
}
heretic-G commented 3 years ago

function find (data) {
    const temp = Array.isArray(data) ? [...data] : {...data}
    let opt = {
        where: function where (opt) {
            return find(Object.entries(opt).reduce((prev, [key, match]) => {
                return prev.filter(curr => {
                    return match.test(curr[key])
                })
            }, this))
        },
        orderBy: function order (key, type) {
            return this.sort((prev, next) => {
                switch (type) {
                    case 'desc':
                        return next - prev
                    case 'asc':
                        return prev - next
                    default:
                        return prev - next
                }
            })
        }
    }
    Object.setPrototypeOf(opt, Array.prototype)
    Object.setPrototypeOf(temp, opt)
    return temp
}
vandvassily commented 3 years ago
// 综合一下两位大佬的写法
class Find {
    constructor(data) {
        this.data = [...data];
    }

    where(query) {
        this.data = this.data.filter((item) => {
            return Object.entries(query).every(([key, value]) => {
                if (value instanceof RegExp) {
                    return value.test(item[key]);
                } else {
                    return item[key] === value;
                }
            });
        });

        return this;
    }

    orderBy(key, type) {
        this.data = this.data.sort((a, b) => (type !== 'desc' ? a[key] - b[key] : b[key] - a[key]));

        return this;
    }

    get value() {
        return this.data;
    }
}

function find(data) {
    return new Find(data);
}