Skip to content

多层对象的时间旅行实现 #4

@SoloJiang

Description

@SoloJiang

emmm...这个题目不太对,普通的时间旅行对象需要做的只是,去记录对象被修改的过程,然后根据需求把不同时刻修改的对象取出来再用就行了。

经常我们会遇到一个场景,去把一个含有不同维度的数组降维处理,从而更加方便的去遍历数组得到自己想要的数据。

代码如下:

class FlatArray {
  constructor(targetArr) {
    this.resultArr = targetArr
    // 循环判断目标数组中是否还有成员是数组
    while (this.resultArr.some(item => Array.isArray(item))) {
      this.operation()
    }
  }
  operation() {
    // 将数组展开
    this.resultArr = [].concat(...this.resultArr)
  }
  get() {
    return this.resultArr
  }
}

const test = new FlatArray([1, 2, [3, 4, [5, 6]], [7, 8], 9])

console.log(test.get())

这段代码比较简单,所以不多做解释了,重点就是通过 concat 和数组扩展进行组合。那么来谈谈我们今天要做任务之一吧,去组装一个对象,换句话说是将对象升维。举一个简单的例子:

有这样一个字符串 'hello',我们要做的是将其处理成

{
  h: {
    e: {
      l: {
        l: {
          o: 'target'
        }
      }
    }
  }
}

任务之二是 将这个对象变成可以时间旅行的,即每次 set 操作都会把原来的对象记录下来并且可查询。

分析任务一

任务一的核心是怎么将字符串的每个字符关联起来,并且能够依次有一一对应的关系,简单的分析就知道应该使用 reduce 来做,代码如下:

  set(path, value) {
    // to be implemented
    let target = Object.create(null);
    let pathArr = path.split("."); // 转换成数组
    let len = pathArr.length;
    // 将每个成员转化成对象,并且依次关联
    let targetObj = pathArr
      .map(item => {
        let nullObject = Object.create(null);
        nullObject[item] = item;
        return nullObject;
      })
      .reverse()
      .reduce((prev, next, index) => {
        // operation
      });
  }

接下来只需要考虑:最后一个元素的 key 对应的 value 是由参数决定;后一个字符为前一个字符的 key 值这两种情况就行了,处理代码为:

if (index === 1) {
  prev[pathArr[len - 1]] = value;
}
next[pathArr[len - 1 - index]] = prev;
return next;

大功告成!我们已经成功的将字符串转化成了一个多层的对象~

分析任务二:

我们需要做的很简单,即每次进行 set 操作的时候给对象加一个时间戳即可。

get(time) {
    // to be implemented
    if (time) {
      let i = 0;
      if (this.history.length > 1) {
        this.history.some((item, index) => {
          if (item.time > time) {
            i = index - 1;
            return true;
          }
          return false
        });
        return this.history[i].data;
      }
    }
    return this.object;
 }

整个下来的代码就是:

class TimeTravelObject {
  constructor() {
    this.object = Object.create(null);
    this.history = [];
  }
  get(time) {
    // to be implemented
    if (time) {
      let i = 0;
      if (this.history.length > 1) {
        this.history.some((item, index) => {
          if (item.time > time) {
            i = index - 1;
            return true;
          }
        });
        return this.history[i].data;
      }
    }
    return this.object;
  }
  set(path, value) {
    // to be implemented
    let target = Object.create(null);
    let pathArr = path.split(".");
    let len = pathArr.length;
    let targetObj = pathArr
      .map(item => {
        let nullObject = Object.create(null);
        nullObject[item] = item;
        return nullObject;
      })
      .reverse()
      .reduce((prev, next, index) => {
        if (index === 1) {
          prev[pathArr[len - 1]] = value;
        }
        next[pathArr[len - 1 - index]] = prev;
        return next;
      });
    const now = Date.now();
    this.object = targetObj;
    this.history.push({
      time: now,
      data: targetObj
    });
  }
}

代码链接

emmm….写完这些大概花了 40 分钟,还是花了太久了,主要的时间就是花在如何去更好的依次关联字符串的字符,让它们依次嵌套。。。

说下后来,又经过启发想到的实现方法,可以通过字符串正则匹配,将其处理成 JSON.stringify的形式,然后 parse成目标对象,我觉得这样效率和性能上肯定是远远超过我上面的时间方法,要是有时间也去尝试一下这种做法。

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions