จะวนซ้ำวัตถุ JavaScript ได้อย่างไร


422

ฉันมีวัตถุใน JavaScript:

{
    abc: '...',
    bca: '...',
    zzz: '...',
    xxx: '...',
    ccc: '...',
    // ...
}

ฉันต้องการใช้การforวนซ้ำเพื่อรับคุณสมบัติ และฉันต้องการวนซ้ำในส่วน (ไม่ใช่คุณสมบัติของวัตถุทั้งหมดในครั้งเดียว)

ด้วยอาร์เรย์ที่เรียบง่ายฉันสามารถทำได้ด้วยforลูปมาตรฐาน:

for (i = 0; i < 100; i++) { ... } // first part
for (i = 100; i < 300; i++) { ... } // second
for (i = 300; i < arr.length; i++) { ... } // last

แต่จะทำอย่างไรกับวัตถุ?


22
โปรดทราบว่าคุณสมบัติของวัตถุจะไม่ถูกจัดเก็บตามลำดับ เมื่อคุณวนซ้ำวัตถุไม่มีการรับประกันตามลำดับที่ปรากฏ
James Allardice

คำตอบ:


850

สำหรับวัตถุส่วนใหญ่ให้ใช้for .. in:

for (let key in yourobject) {
  console.log(key, yourobject[key]);
}

ด้วย ES6 หากคุณต้องการทั้งคีย์และค่าพร้อมกันให้ทำ

for (let [key, value] of Object.entries(yourobject)) {
    console.log(key, value);
}

เพื่อหลีกเลี่ยงการบันทึกคุณสมบัติที่สืบทอดให้ตรวจสอบกับhasOwnProperty :

for (let key in yourobject) {
   if (yourobject.hasOwnProperty(key)) {
      console.log(key, yourobject[key]);
   }
}

คุณไม่จำเป็นต้องตรวจสอบhasOwnPropertyเมื่อทำการวนกุญแจถ้าคุณใช้วัตถุอย่างง่าย (ตัวอย่างเช่นคุณทำด้วยตัวเอง{})

เอกสาร MDN นี้อธิบายเพิ่มเติมโดยทั่วไปเกี่ยวกับวิธีจัดการกับวัตถุและคุณสมบัติ

หากคุณต้องการที่จะทำ "ในชิ้น" ที่ดีที่สุดคือการแยกกุญแจในอาร์เรย์ เนื่องจากไม่รับประกันการสั่งซื้อนี่เป็นวิธีที่เหมาะสม ในเบราว์เซอร์สมัยใหม่คุณสามารถใช้

let keys = Object.keys(yourobject);

เพื่อให้เข้ากันได้มากขึ้นคุณควรทำสิ่งนี้:

 let keys = [];
 for (let key in yourobject) {      
     if (yourobject.hasOwnProperty(key)) keys.push(key);
 }

จากนั้นคุณสามารถทำซ้ำคุณสมบัติของคุณตามดัชนีyourobject[keys[i]]::

for (let i=300; i < keys.length && i < 600; i++) { 
   console.log(keys[i], yourobject[keys[i]]);
}

3
OP ต้องการดำเนินการนี้เป็นชิ้น ๆ ไม่ใช่ทุกปุ่มในลูปเดียว
Pawel

ใช่. ไม่ใช่วัตถุเต็มในหนึ่งวง
nkuhta

2
@Cerbrus OP allready รู้วิธีการวนซ้ำอาร์เรย์ในส่วนต่างๆ ใช้keysจากรหัสที่กำหนดควรจะเพียงพอ
โยชิ

2
@Cerbrus โปรดอ่านก่อนแสดงความคิดเห็น! อะไรที่ไม่ชัดเจนใน"การจะเข้ากันได้มากขึ้นคุณควรที่จะทำเช่นนี้" ?
Denys Séguret

2
@ am05mhz อย่างที่ฉันบอกไปมันไร้ประโยชน์กับวัตถุส่วนใหญ่ แต่ไม่ใช่สำหรับทุกคน ลองสิ่งนี้: jsbin.com/hirivubuta/1/edit?js,console,output
Denys Séguret

61

นี่เป็นอีกวิธีแก้ปัญหาซ้ำสำหรับเบราว์เซอร์ที่ทันสมัย:

Object.keys(obj)
  .filter((k, i) => i >= 100 && i < 300)
  .forEach(k => console.log(obj[k]));

หรือไม่มีฟังก์ชั่นตัวกรอง:

Object.keys(obj).forEach((k, i) => {
    if (i >= 100 && i < 300) {
        console.log(obj[k]);
    }
});

อย่างไรก็ตามคุณต้องพิจารณาว่าคุณสมบัติในวัตถุ JavaScript ไม่ได้ถูกจัดเรียงนั่นคือไม่มีคำสั่งซื้อ


ถ้าฉันจะแยกวงมันจะเริ่มจากจุดเริ่มต้นของวัตถุในครั้งถัดไปนั่นไม่ใช่วิธีที่ถูกต้อง
nkuhta

21

ใช้Object.entriesคุณทำอะไรแบบนี้

 // array like object with random key ordering
 const anObj = { 100: 'a', 2: 'b', 7: 'c' };
 console.log(Object.entries(anObj)); // [ ['2', 'b'],['7', 'c'],['100', 'a'] ]

กระบวนการ Object.entries () วิธีการส่งกลับอาร์เรย์ของคุณสมบัติที่นับได้ของวัตถุที่กำหนด [คีย์ค่า]

ดังนั้นคุณสามารถวนซ้ำวัตถุและมีkeyและvalueสำหรับแต่ละวัตถุและรับสิ่งนี้

const anObj = { 100: 'a', 2: 'b', 7: 'c' };
Object.entries(anObj).map(obj => {
   const key   = obj[0];
   const value = obj[1];

   // do whatever you want with those values.
});

หรือเช่นนี้

// Or, using array extras
Object.entries(obj).forEach(([key, value]) => {
  console.log(`${key} ${value}`); // "a 5", "b 7", "c 9"
});

สำหรับการอ้างอิงให้ดูที่เอกสาร MDN สำหรับรายการวัตถุ


17

ด้วยคุณสมบัติใหม่ของ ES6 / ES2015 คุณไม่จำเป็นต้องใช้วัตถุอีกต่อไปเพื่อทำซ้ำแฮช คุณสามารถใช้แผนที่ แผนที่จาวาสคริปต์เก็บคีย์ตามลำดับการแทรกซึ่งหมายความว่าคุณสามารถทำซ้ำได้โดยไม่ต้องตรวจสอบ hasOwnProperty ซึ่งเป็นแฮ็คจริงๆ

วนซ้ำแผนที่

var myMap = new Map();
myMap.set(0, "zero");
myMap.set(1, "one");
for (var [key, value] of myMap) {
  console.log(key + " = " + value);
}
// Will show 2 logs; first with "0 = zero" and second with "1 = one"

for (var key of myMap.keys()) {
  console.log(key);
}
// Will show 2 logs; first with "0" and second with "1"

for (var value of myMap.values()) {
  console.log(value);
}
// Will show 2 logs; first with "zero" and second with "one"

for (var [key, value] of myMap.entries()) {
  console.log(key + " = " + value);
}
// Will show 2 logs; first with "0 = zero" and second with "1 = one"

หรือใช้สำหรับแต่ละ:

myMap.forEach(function(value, key) {
  console.log(key + " = " + value);
}, myMap)
// Will show 2 logs; first with "0 = zero" and second with "1 = one"

1
forEach เป็นหนึ่งที่ต้องการ
pungggi

14

ถ้าคุณต้องการที่สำคัญและความคุ้มค่าเมื่อ iterating คุณสามารถใช้สำหรับ ... ของวงกับObject.entries

const myObj = {a: 1, b: 2}

for (let [key, value] of Object.entries(myObj)) {
    console.log(`key=${key} value=${value}`)
}

// output: 
// key=a value=1
// key=b value=2

7

วิธีที่เชื่อถือได้เพียงวิธีเดียวคือการบันทึกข้อมูลออบเจ็กต์ของคุณไปยัง 2 อาร์เรย์หนึ่งในคีย์และอีกหนึ่งสำหรับข้อมูล:

var keys = [];
var data = [];
for (var key in obj) {
    if (obj.hasOwnProperty(key)) {
        keys.push(key);
        data.push(obj[key]); // Not necessary, but cleaner, in my opinion. See the example below.
    }
}

จากนั้นคุณสามารถวนซ้ำอาร์เรย์ตามปกติ:

for(var i = 0; i < 100; i++){
    console.log(keys[i], data[i]);
    //or
    console.log(keys[i], obj[keys[i]]); // harder to read, I think.
}
for(var i = 100; i < 300; i++){
    console.log(keys[i], data[i]);
}

ฉันไม่ได้ใช้Object.keys(obj)เพราะนั่นคือ IE 9+


3

-> ถ้าเราวนซ้ำวัตถุ JavaScript ที่ใช้และค้นหาคีย์ของอาร์เรย์ของวัตถุ

Object.keys(Array).forEach(key => {

 console.log('key',key)

})

1

หากคุณต้องการวนซ้ำวัตถุทั้งหมดในครั้งเดียวคุณสามารถใช้for inวนรอบ:

for (var i in obj) {
  ...
}

แต่ถ้าคุณต้องการแบ่งวัตถุออกเป็นส่วน ๆ ในความเป็นจริงคุณไม่สามารถทำได้ ไม่มีการรับประกันว่าคุณสมบัติในวัตถุนั้นอยู่ในลำดับที่ระบุไว้ ดังนั้นฉันคิดได้สองวิธี

ประการแรกคือ "ลบ" คุณสมบัติอ่านแล้ว:

var i = 0;
for (var key in obj) {
    console.log(obj[key]);
    delete obj[key];
    if ( ++i > 300) break;
}

อีกวิธีที่ฉันคิดได้คือใช้ Array of Arrays แทนอ็อบเจกต์:

var obj = [['key1', 'value1'], ['key2', 'value2']];

จากนั้นมาตรฐานforวงจะทำงาน


1

ในที่สุดฉันก็มาพร้อมกับฟังก์ชั่นยูทิลิตี้ที่มีประโยชน์พร้อมอินเทอร์เฟซแบบรวมเพื่อย้ำวัตถุ, Strings, Arrays, TypedArrays, Maps, Sets, (Iterables ใด ๆ )

const iterate = require('@a-z/iterate-it');
const obj = { a: 1, b: 2, c: 3 };

iterate(obj, (value, key) => console.log(key, value)); 
// a 1
// b 2
// c 3

https://github.com/alrik/iterate-javascript


1

คุณสามารถลองใช้lodash- ไลบรารียูทิลิตี้ JavaScript ที่ทันสมัยซึ่งมีโมดูลโมดูลประสิทธิภาพและอุปกรณ์เสริม js เพื่อย้ำวัตถุอย่างรวดเร็ว: -

var  users  =   {
    'fred':     { 
        'user':   'fred',
            'age':  40 
    },
    'pebbles':  { 
        'user':   'pebbles',
         'age':  1 
    }
}; 
_.mapValues(users,  function(o)  { 
    return  o.age; 
});
// => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed)
// The `_.property` iteratee shorthand.
console.log(_.mapValues(users,  'age')); // returns age property & value 
console.log(_.mapValues(users,  'user')); // returns user property & value 
console.log(_.mapValues(users)); // returns all objects 
// => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash-compat/3.10.2/lodash.js"></script>


1

สำหรับการวนซ้ำวัตถุเรามักจะใช้for..inวง โครงสร้างนี้จะวนซ้ำผ่านคุณสมบัติที่นับได้ทั้งหมดรวมถึงโครงสร้างที่สืบทอดผ่านแบบตัวอย่าง ตัวอย่างเช่น:

let obj = {
  prop1: '1',
  prop2: '2'
}

for(let el in obj) {
  console.log(el);
  console.log(obj[el]);
}

อย่างไรก็ตามfor..inจะวนซ้ำองค์ประกอบทั้งหมดและสิ่งนี้จะทำให้เราไม่สามารถแยกการวนซ้ำเป็นชิ้น ๆ ได้ เพื่อให้บรรลุถึงสิ่งนี้เราสามารถใช้Object.keys()ฟังก์ชันในตัวเพื่อดึงกุญแจทั้งหมดของวัตถุในอาร์เรย์ จากนั้นเราสามารถแบ่งการวนซ้ำเป็นหลาย ๆ ลูปและเข้าถึงคุณสมบัติโดยใช้คีย์อาร์เรย์ ตัวอย่างเช่น:

let obj = {
  prop1: '1',
  prop2: '2',
  prop3: '3',
  prop4: '4',
};

const keys = Object.keys(obj);
console.log(keys);


for (let i = 0; i < 2; i++) {
  console.log(obj[keys[i]]);
}


for (let i = 2; i < 4; i++) {
  console.log(obj[keys[i]]);
}


0
var Dictionary = {
  If: {
    you: {
      can: '',
      make: ''
    },
    sense: ''
  },
  of: {
    the: {
      sentence: {
        it: '',
        worked: ''
      }
    }
  }
};

function Iterate(obj) {
  for (prop in obj) {
    if (obj.hasOwnProperty(prop) && isNaN(prop)) {
      console.log(prop + ': ' + obj[prop]);
      Iterate(obj[prop]);
    }
  }
}
Iterate(Dictionary);

1
ไม่จริง นี่ก็หมายความว่าObjects อยู่ในลำดับ พวกเขาไม่. If you can make sense of the sentence it workedใช้งานได้เนื่องจากรายละเอียดการใช้งานเท่านั้น มันไม่รับประกันว่าจะทำงานเลย นอกจากนี้คุณไม่ควร TitleCase ฟังก์ชั่นและตัวแปรของคุณ นั่นสำหรับclasses
Florian Wendelborn

0

จริงๆแล้ว PITA นี่ไม่ใช่ส่วนหนึ่งของ Javascript มาตรฐาน

/**
 * Iterates the keys and values of an object.  Object.keys is used to extract the keys.
 * @param object The object to iterate
 * @param fn (value,key)=>{}
 */
function objectForEach(object, fn) {
    Object.keys(object).forEach(key => {
        fn(object[key],key, object)
    })
}

หมายเหตุ: ฉันเปลี่ยนพารามิเตอร์การเรียกกลับเป็น (ค่าคีย์) และเพิ่มวัตถุที่สามเพื่อให้ API สอดคล้องกับ API อื่น ๆ

ใช้มันแบบนี้

const o = {a:1, b:true};
objectForEach(o, (value, key, obj)=>{
    // do something
});

1
เพิ่มขึ้นเพียงสำหรับคำสั่งของคุณในประโยคแรก แม้ว่ามันจะดีกว่าถ้าค่าเป็นพารามิเตอร์แรกดัชนีหรือพารามิเตอร์คีย์ที่สองและพารามิเตอร์ที่สามของวัตถุเพื่อทำให้มันเป็นเหมือนอาร์เรย์สำหรับแต่ละ () ฉันแนะนำให้แนะนำ lodash ว่า
สัญญาบอกว่าฉันถูกที่

ฉันชอบความคิดของคำสั่ง (ค่า, คีย์) นั่นคือวิธีที่ไลบรารีเช่น Vue ทำเช่นกัน เนื่องจากวัตถุเป็นบริบทจึงคิดว่ามันเป็นของพารามิเตอร์แรก นั่นเป็นมาตรฐานที่ดีสำหรับการเขียนโปรแกรมใช้งาน
Steven Spungin

ฉันจะเห็นด้วยที่นี่ถ้าไม่ใช่สำหรับ ECMA-262 การกำหนดอาร์เรย์เป็นวัตถุที่มี forEach (), map (), ลด (), filter () ซึ่งทั้งหมดใช้การเรียกกลับที่ได้รับการสั่งซื้อ [มูลค่าดัชนีอาร์เรย์] . วัตถุใน JS สามารถเข้าใจได้ว่าเป็นเพียงคอลเล็กชันอื่น จากนั้นวิธีการเหล่านี้จะรวมเป็นหนึ่งเดียวในพารามิเตอร์ของ [value, key | index, context] (นี่คือสิ่งที่ lodash และขีดล่างกำลังทำอยู่) ในความคิดของฉันโปรโตคอล "การรวบรวมแบบรวม" นี้มีความแข็งแกร่งยิ่งขึ้น นอกจากนี้วัตถุไม่ใช่บริบท: คุณสามารถตั้งค่าthisเป็นสิ่งที่คุณต้องการสำหรับการโทรกลับเนื่องจากการโทรกลับมีบริบทของตัวเอง
สัญญาบอกว่าฉันถูก

บางทีฉันควรใช้ผู้รับงานแทนสิ่งนี้ อย่างไรก็ตามยังคงเป็น PITA; ฉันยินดีต้อนรับพารามิเตอร์ในลำดับใด ๆ
Steven Spungin

โอ้ฉันเห็นว่าเราอาจเข้าใจผิดกัน ฉันมักจะแสดงความคิดเห็นเกี่ยวกับพารามิเตอร์การโทรกลับและคำสั่งของพวกเขาไม่ใช่เกี่ยวกับobjectForEachฟังก์ชั่นที่เกิดขึ้นจริง ขออภัยหากเกิดความสับสน
สัญญาบอกว่าฉันถูกที่

0

ใช่. คุณสามารถวนลูปผ่านวัตถุที่ใช้สำหรับลูป นี่คือตัวอย่าง

var myObj = {
    abc: 'ABC',
    bca: 'BCA',
    zzz: 'ZZZ',
    xxx: 'XXX',
    ccc: 'CCC',
}

var k = Object.keys (myObj);
for (var i = 0; i < k.length; i++) {
    console.log (k[i] + ": " + myObj[k[i]]);
}

หมายเหตุ:ตัวอย่างที่กล่าวถึงข้างต้นจะทำงานใน IE9 + เท่านั้น ดูการสนับสนุนเบราว์เซอร์ Objec.keys ที่นี่


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.