1

我正在处理一个object我需要保留 的顺序的地方entries,即使有些keys是字母数字而另一些是整数。(是的,我知道。)

我开始的对象如下所示:

{
  a: 'the',
  quick: 'quick',
  b: 'brown',
  fox: 'fox'
}

操作后,对象应如下所示:

{
  a: 'the',
  0: 'quick',
  b: 'brown',
  1: 'fox'
}

但。因为javascript 对象中的迭代顺序插入顺序不同(首先迭代整数),所以如果我直接进行此操作,我将不会得到正确排序的结果:

let myReindexedObject = {};

myReindexedObject['a'] = 'the';
myReindexedObject['0'] = 'quick';
myReindexedObject['b'] = 'brown';
myReindexedObject['1'] = 'fox';

console.log(myReindexedObject);

我试图通过构建一个Map(与 不同object,保留进入顺序)来解决这个问题,然后我可以将其转换为object.

资料来源:(我改编了 Luke Horvat 的这个要点:Convert ES6 Map to Object Literal。)

你能猜到会发生什么吗?

let myMap = new Map();

myMap.set('a', 'the');
myMap.set('0', 'quick');
myMap.set('b', 'brown');
myMap.set('1', 'fox');

let myArray = Array.from(myMap);

let myReindexedObject = myArray.reduce((myReindexingObject, [key, value]) => {
  return Object.assign(myReindexingObject, { [key]: value })
}, {});

console.log(myReindexedObject);

有什么方法可以使用基于整数的keys类似0并且仍然以自定义顺序1保留条目?object

还是我需要考虑其他方法?

4

2 回答 2

2

在写上面问题的过程中,我在打字的时候突然想到:

(首先迭代整数)

JavaScript 引擎识别的integer数字和人类识别的数字当然是不一样的。

对于任何人来说,这两个:

1

1.

在印刷上并不相同,但它们几乎是等价的。

对于任何 javascript 解释器来说,它们是完全不同的:第一个是整数;第二个不是。


工作示例:

let myReindexedObject = {};

myReindexedObject['a'] = 'the';
myReindexedObject['0.'] = 'quick';
myReindexedObject['b'] = 'brown';
myReindexedObject['1.'] = 'fox';

console.log(myReindexedObject);


如果 javascript 解释器需要识别这些索引,它可以这样做,使用正则表达式:

/d+\./

并且,一旦确定,如果它需要知道string对应的整数,它可以使用:

parseInt(myIndex);

我现在将使用这种方法。

如果有人可以提出更好的方法,我将很乐意投票并接受。

于 2021-11-12T17:39:30.193 回答
2

我们可以定义我们自己的对象,它跟踪属性。通过拦截所需的功能,我们可以使其工作。
使用代理很容易实现:

// DEMO
let o = new CoolObject();
o['a'] = 'the';
o['0'] = 'quick';
o['b'] = 'brown';
o['1'] = 'fox';
o['c'] = 'jumped';
delete o['c'];

console.log('Object.keys: ', Object.keys(o));
console.log('JSON.stringify: ', JSON.stringify(o));
console.log('console.log: ', o);
console.log('Object.getOwnPropertyNames: ', Object.getOwnPropertyNames(o));
console.log('obj.propertyIsEnumerable("keys"): ', o.propertyIsEnumerable('keys'));
console.log('obj.propertyIsEnumerable("a"): ', o.propertyIsEnumerable('a'));
<script src="https://cdn.jsdelivr.net/gh/OnkarRuikar/temp@main/CoolObject.js"></script>
See console logs for output.

注意插入有序的属性名称。除了方法之外,结果getOwnPropertyNames也是插入排序的。


CoolObject 类定义:

(function () {
      // original functions
      let _keys = Object.keys;
      let _getOwnPropertyNames = Object.getOwnPropertyNames;
      let _defineProperty = Object.defineProperty;
      let _stringify = JSON.stringify;
      let _log = console.log;

      // main feature definition
      let CoolObject = function () {
        let self = this;
        let handler = {
          _coolKeys: [],

          set(target, key, val) {
            let keys = this._coolKeys;
            if (!keys.some(k => k === key))
              keys.push(key);

            target[key] = val;
          },

          get(target, key) {
            return target[key];
          },

          keys() {
            return this._coolKeys.slice(0);
          },

          deleteProperty(target, key) {
            let keys = this._coolKeys;
            const index = keys.indexOf(key);
            if (index > -1) {
              keys.splice(index, 1);
            }

            delete target[key];
          },

          defineProperty(obj, prop, val) {
            let keys = this._coolKeys;
            if (!keys.some(k => k === prop))
              keys.push(prop);
            _defineProperty(self, prop, val);
          },

          getOwnPropertyNames(obj) {
            let props = _getOwnPropertyNames(obj);
            return [...new Set([...this._coolKeys, ...props])];
          },

          // many improvements can be done here
          // you can use your own modified pollyfill
          stringifyHelper(obj, replacer, space) {
            let out = '{';
            for (let key of this._coolKeys) {
              out += `"${key}":${_stringify(obj[key], replacer, space)}, `;
            }
            out += '}';
            return out;
          },

        };

        _defineProperty(self, 'keys', { value: () => handler.keys() });
        _defineProperty(self, 'getOwnPropertyNames', { value: (o) => handler.getOwnPropertyNames(o) });
        _defineProperty(self, 'stringify', { value: (...args) => handler.stringifyHelper(...args) });

        return new Proxy(self, handler);
      } // CoolObject end


      // ----- wrap inbuilt objects -----
      Object.keys = function (obj) {
        if (!(obj instanceof CoolObject))
          return _keys(obj);
        return obj.keys();
      }

      Object.defineProperty = function (obj, prop, val) {
        if (!(obj instanceof CoolObject))
          _defineProperty(...arguments);
        obj.defineProperty(...arguments);
      }

      Object.getOwnPropertyNames = function (obj) {
        if (!(obj instanceof CoolObject))
          return _getOwnPropertyNames(obj);
        return obj.getOwnPropertyNames(obj);
      }

      JSON.stringify = function (obj, replacer, indent) {
        if (!(obj instanceof CoolObject))
          return _stringify(...arguments);
        return obj.stringify(...arguments);
      }

      console.log = function () {
        let myArgs = [];
        for (let arg of arguments) {

          if (arg instanceof CoolObject) {
            let keys = arg.keys();
            arg = Object.assign({}, arg);
            for (let key of keys) {
              arg[`.${key}`] = arg[key]
              delete arg[key];
            }
          }

          myArgs.push(arg);
        }
        _log(...myArgs);
      }

      window.CoolObject = CoolObject;
    })();

该对象在数组handler中维护属性名称。_coolKeys并跟踪添加和删除操作。为了让对象表现得像一个原始对象,我们需要包装一些内置的 API,比如 Object.keys()。


注意:对于演示,我已经实现了最低限度的粗略代码。可以做很多改进。您可以根据需要拦截更多内置 API。

于 2022-01-29T08:38:50.223 回答