如何在 Javascript 中对对象进行切片?

Posted

技术标签:

【中文标题】如何在 Javascript 中对对象进行切片?【英文标题】:How can I slice an object in Javascript? 【发布时间】:2017-01-13 04:14:03 【问题描述】:

我试图使用 Array.prototype 对对象进行切片,但它返回一个空数组,除了传递参数之外还有什么方法可以切片对象,还是只是我的代码有问题?谢谢!!

var my_object = 
 0: 'zero',
 1: 'one',
 2: 'two',
 3: 'three',
 4: 'four'
;

var sliced = Array.prototype.slice.call(my_object, 4);
console.log(sliced);

【问题讨论】:

最接近的方法是使用delete object.property 删除密钥,并确保在此之前将该属性存储在单独的变量中。 您的预期输出是什么?切片对象没有任何意义 - 它没有任何意义,但如果你能解释你希望你的预期输出是什么,我们可以努力实现。 我尝试创建一个新数组,仅使用我可能需要的属性,即:var obj = car: 'audi', engine: 'diesel', color: 'blue' as输出我想要一个只有“颜色”属性的新对象。 我想要一个新对象 - 但Array.slice 返回一个数组 【参考方案1】:

const res = Object.fromEntries(Object.entries(my_object).slice(0,4));

【讨论】:

【参考方案2】:

我试图使用Array.prototype 对对象进行切片,但它返回一个空数组

那是因为它没有 .length 属性。它将尝试访问它,获取undefined,将其转换为一个数字,获取0,并从对象中切出最多那么多属性。为了达到预期的结果,您必须为它分配一个length,或者手动通过对象的迭代器:

var my_object = 0: 'zero', 1: 'one', 2: 'two', 3: 'three', 4: 'four';

my_object.length = 5;
console.log(Array.prototype.slice.call(my_object, 4));

var sliced = [];
for (var i=0; i<4; i++)
    sliced[i] = my_object[i];
console.log(sliced);

【讨论】:

所以我想除了手动修改对象、添加长度或迭代器之外别无他法...... 别被愚弄了,继续往下看吧,@trad 现在有最好的答案,还有其他几个聪明的答案。【参考方案3】:

最好的现代解决方案是 Object.fromEntriesObject.entries 的组合。

const foo = 
    one: 'ONE',
    two: 'TWO',
    three: 'THRE',
    four: 'FOUR',


const sliced = Object.fromEntries(
    Object.entries(foo).slice(1, 3)
)

console.log(sliced)

【讨论】:

我很好奇,您是否将其与其他方法进行了基准测试?本能地似乎很慢,但我可能错了。这绝对是最优雅的解决方案恕我直言。 我没有测试过。我的猜测是我的解决方案有点慢,但接受的答案没有返回密钥,而且在我看来不是很干净。【参考方案4】:

你可以reduceObject.keys函数的结果

const myObject = 
 0: 'zero',
 1: 'one',
 2: 'two',
 3: 'three',
 4: 'four'
;

const sliced = Object.keys(myObject).slice(0, 2).reduce((result, key) => 
                    result[key] = myObject[key];

                    return result;
                , );

console.log(sliced);

【讨论】:

最好的!喜欢它。【参考方案5】:

尝试将“长度”属性添加到 my_object,然后您的代码应该可以工作:

    var my_object = 
     0: 'zero',
     1: 'one',
     2: 'two',
     3: 'three',
     4: 'four',
     length: 5
    ;
    
    var sliced = Array.prototype.slice.call(my_object, 4);
    console.log(sliced);

【讨论】:

【参考方案6】:
var obj = 0: 'zero', 1: 'one', 2: 'two', 3: 'three', 4: 'four';
var result = Object.keys(obj).slice(0,2).map(key => ([key]:obj[key]));

console.log(result);

[ '0': '零' , '1': '一' ]

【讨论】:

【参考方案7】:

还没有人提到Object.entries(),这可能是最灵活的方式。此方法在枚举属性时使用与for..in 相同的顺序,即属性最初输入对象的顺序。您还可以获得具有属性和值的子数组,因此您可以使用其中任何一个或两者都使用。最后,您不必担心属性是数字或设置额外长度属性(就像使用 Array.prototype.slice.call() 时所做的那样)。 这是一个例子:

const obj = 'prop1': 'foo', 'prop2': 'bar', 'prop3': 'baz', 'prop4': 'prop': 'buzz';

您想要对前两个值进行切片:

Object.entries(obj).slice(0,2).map(entry => entry[1]);
//["foo", "bar"]

所有的键?

Object.entries(obj).slice(0).map(entry => entry[0]);
//["prop1", "prop2", "prop3", "prop4"]

最后一个键值对?

Object.entries(obj).slice(-1)
//[ ['prop4', 'prop': 'buzz'] ]

【讨论】:

Object.entries 肯定是一种有用的了解方法(显然是 ECMA 262 的新方法)......但它似乎只是产生一个数组数组,这并不是 OP 的真正含义要求。 Object.entries 在 IE 中不受支持。 不幸的是,这个解决方案将产生一个新的数组而不是一个新的对象。当我们想要对一个对象进行切片时,我们期望的是一个切片的对象,而不是一个切片的数组。 我爱你这个答案@Trad【参考方案8】:

// Works, but acts weird when things get serious
// Avoids screwing with the properties of my_object
// You don't get Object.create() until ES5.1
function lazySlice(obj, idx) 
  var newObj = Object.create(obj,  length: value: Object.keys(obj).length ),
  idx = idx || 0;

  return Array.prototype.slice.call(newObj, idx);


// Only gives you own enumerable properties with keys "0" to n
// Preserves element order (based on key number)
// Ignores non-numbered keys
// You don't get Object.keys() until ES5
function enumSlice(obj, idx) 
  var arr = [], 
    keys = Object.keys(obj),
    idx = idx || 0;

  for (var i = 0; i <= keys.length - 1; i++)
    if (keys[i] >= idx && keys[i] % 1 === 0 && keys[i] >= 0 && keys[i].indexOf('e') < 0) 
      arr.push(obj[keys[i]]);

  return arr;


var my_object = 
  0: 'zero',
  1: 'one',
  2: 'two',
  3: 'three',
  4: 'four'
; 
console.log(lazySlice(my_object, 3));      // [ 'three', 'four' ]
console.log(enumSlice(my_object, 3));      // [ 'three', 'four' ]

var mixed_object = 
   "9": 'nine',
   "2": 'two',
   "1": 'one',
   "7": 'seven',
   "7.5": 'seven point five',
   "1e4": 'sneaky',
   "-4": 'negative four',
   "0": 'zero',
   "length": 35
;
console.log(lazySlice(mixed_object));      // [ 'zero', 'one', 'two', , , , , 'seven',  ]
console.log(enumSlice(mixed_object));      // [ 'zero', 'one', 'two', 'seven', 'nine' ]

【讨论】:

【参考方案9】:

除非它有一个 [Symbol.iterator] 生成器函数并且 length 属性存在,否则你不能。比如;

var my_object =  0: 'zero', 1: 'one', 2: 'two', 3: 'three', 4: 'four', length:5 ,
       sliced;

my_object[Symbol.iterator] = function* ()
                                          var oks = Object.keys(this);
                                          for (var key of oks) yield this[key];
                                         ;

sliced = Array.prototype.slice.call(my_object, 2);
console.log(sliced);

【讨论】:

一个迭代器一个长度就足够了,你不需要两者。 @Bergi 这就是我想到的只有一个迭代器......我刚刚用一个迭代器进行了测试,但它不起作用..我不确定只有 length 属性它不过会好的。不只是一个迭代器不会削减。可能是我错过了什么。 slice 不关心迭代器(它只关心长度),Array.from(my_object).slice(4) 会。我以为你在谈论迭代时想到了Array.from…… @Bergi 试试.slice(2) @Bergi 好的,你是对的,只有length 属性很好。必须纠正。【参考方案10】:

你没有在你的问题中提到它,但这看起来非常像一个参数对象。

使用Array.from() 将其转换为数组,然后像使用任何其他数组一样使用它。只要是可枚举的对象。

有关旧浏览器的 polyfill,请参阅 https://developer.mozilla.org/en-US/docs/Web/javascript/Reference/Global_Objects/Array/from

【讨论】:

【参考方案11】:

我认为它可以帮助你:

var my_object =  0: 'zero', 1: 'one', 2: 'two', 3: 'three', 4: 'four' ;

var sliced = Object.keys(my_object).map(function(key)  return my_object[key] ).slice(4);

console.log(sliced);

【讨论】:

缺点是 keys() 不能保证以任何特定顺序返回对象的键。

以上是关于如何在 Javascript 中对对象进行切片?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Bash 中对数组进行切片

如何在 Swift 中对字符串进行切片? [复制]

如何在 Excel VBA 中对数组进行切片?

如何在 TensorFlow 中对批次进行切片并在每个切片上应用操作

如何在 TensorFlow 中对数据集进行切片?

如何在 Perl 6 中对形状数组进行切片?