javascript - شرح - كيف أقوم بتكرار أو عد كائن جافا سكريبت؟




شرح جافا سكريبت (20)

لدي كائن جافا سكريبت كما يلي:

var p = {
    "p1": "value1",
    "p2": "value2",
    "p3": "value3"
};

الآن أريد أن حلقة من خلال جميع عناصر p ( p1 ، p2 ، p3 ...) والحصول على مفاتيحها والقيم. كيف أقوم بذلك؟

يمكنني تعديل كائن JavaScript إذا لزم الأمر. هدفي النهائي هو التكرار من خلال بعض أزواج القيم الرئيسية ، وإذا كان ذلك ممكنا أريد تجنب استخدام eval .


Object.keys (obj): صفيف

يسترد جميع مفاتيح القيم - القيمة لجميع الخصائص الخاصة التي لا حصر لها (غير الموروثة).

لذلك فإنه يعطي نفس قائمة المفاتيح التي تنوي باختبار كل مفتاح الكائن مع hasOwnProperty. أنت لا تحتاج إلى أن عملية اختبار إضافية من و Object.keys( obj ).forEach(function( key ){}) يفترض أن يكون أسرع. دعونا اثبات ذلك:

var uniqid = function(){
			var text = "",
					i = 0,
					possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
			for( ; i < 32; i++ ) {
					text += possible.charAt( Math.floor( Math.random() * possible.length ) );
			}
			return text;
		}, 
		CYCLES = 100000,
		obj = {}, 
		p1,
		p2,
		p3,
		key;

// Populate object with random properties
Array.apply( null, Array( CYCLES ) ).forEach(function(){
	obj[ uniqid() ] = new Date()
});

// Approach #1
p1 = performance.now();
Object.keys( obj ).forEach(function( key ){
	var waste = obj[ key ];
});

p2 = performance.now();
console.log( "Object.keys approach took " + (p2 - p1) + " milliseconds.");

// Approach #2
for( key in obj ) {
	if ( obj.hasOwnProperty( key ) ) {
		var waste = obj[ key ];
	}
}

p3 = performance.now();
console.log( "for...in/hasOwnProperty approach took " + (p3 - p2) + " milliseconds.");

في بلدي فايرفوكس لدي النتائج التالية

  • استغرق أسلوب Object.keys 40.21101451665163 ميلي ثانية.
  • for ... in / hasOwProProperty approach took 98.26163508463651 milliseconds.

PS. على كروم الفرق أكبر http://codepen.io/dsheiko/pen/JdrqXa

PS2: في ES6 (EcmaScript 2015) يمكنك تكرار iterable كائن أجمل:

let map = new Map().set('a', 1).set('b', 2);
for (let pair of map) {
    console.log(pair);
}

// OR 
let map = new Map([
    [false, 'no'],
    [true,  'yes'],
]);
map.forEach((value, key) => {
    console.log(key, value);
});


إرجاع الأسلوب Object.keys() صفيف خصائص enumerable الخاصة كائن محدد. قراءة المزيد حول هذا الموضوع Object.keys()

var p = {
    "p1": "value1",
    "p2": "value2",
    "p3": "value3"
};

Object.keys(p).map((key)=> console.log(key + "->" + p[key]))


بعد الاطلاع على جميع الإجابات هنا ، ليس من الضروري استخدام "onOwenProperty" للاستخدام الخاص بي لأن كائن json الخاص بي نظيف. لا يوجد أي معنى في إضافة أي معالجة جافا سكريبت إضافية. هذا هو كل ما أستخدمه:

for (var key in p) {
    console.log(key + ' => ' + p[key]);
    // key is key
    // value is p[key]
}

بما أن es2015 أصبح أكثر وأكثر شعبية ، فإنني أقوم بنشر هذه الإجابة التي تتضمن استخدام المولد والمكرر لتكرار العمل بشكل سلس من خلال أزواج [key, value] . كما هو ممكن في لغات أخرى على سبيل المثال روبي.

طيب هنا هو كود:

const MyObject = {
  'a': 'Hello',
  'b': 'it\'s',
  'c': 'me',
  'd': 'you',
  'e': 'looking',
  'f': 'for',
  [Symbol.iterator]: function* () {
    for (const i of Object.keys(this)) {
      yield [i, this[i]];
    }
  }
};

for (const [k, v] of MyObject) {
  console.log(`Here is key ${k} and here is value ${v}`);
}

جميع المعلومات حول كيف يمكنك أن تفعل المكرر والمولد يمكنك العثور على صفحة المطور موزيلا.

آمل أنها ساعدت شخص ما.

تصحيح:

سيشتمل ES2017 على Object.entries الذي سيجعل التكرار أكثر من أزواج [key, value] في الكائنات أكثر سهولة. ومن المعروف الآن أنه سيكون جزءا من معيار وفقا ts39 المرحلة ts39 .

أعتقد أن الوقت قد حان لتحديث جوابي ليصبح أكثر طعمًا مما هو عليه الآن.

const MyObject = {
  'a': 'Hello',
  'b': 'it\'s',
  'c': 'me',
  'd': 'you',
  'e': 'looking',
  'f': 'for',
};

for (const [k, v] of Object.entries(MyObject)) {
  console.log(`Here is key ${k} and here is value ${v}`);
}

يمكنك العثور على المزيد حول الاستخدام على صفحة MDN


شفرة JavaScript فقط دون تبعيات:

var p = {"p1": "value1", "p2": "value2", "p3": "value3"};
keys = Object.keys(p);   // ["p1", "p2", "p3"]

for(i = 0; i < keys.length; i++){
  console.log(keys[i] + "=" + p[keys[i]]);   // p1=value1, p2=value2, p3=value3
}

عبر النموذج الأولي forEach () الذي يجب أن يتخطى خصائص سلسلة النموذج الأولي :

Object.prototype.each = function(f) {
    var obj = this
    Object.keys(obj).forEach( function(key) { 
        f( key , obj[key] ) 
    });
}


//print all keys and values
var obj = {a:1,b:2,c:3}
obj.each(function(key,value) { console.log(key + " " + value) });
// a 1
// b 2
// c 3

لقد لمس Object.keys() للاهتمام في هذه الإجابات كلاً من Object.keys() ، ولكنهم لم Object.keys() أبدًا:

var map = {well:'hello', there:'!'};
for (let key of Object.keys(map))
    console.log(key + ':' + map[key]);

لا يمكنك فقط for...of Object لأنه ليس مكررًا ، ومن for...index أو .forEach() ing يكون Object.keys() قبيح / غير فعال.
أنا سعيد لأن معظم الناس يمتنعون for...in (مع أو من دون التحقق. .hasOwnProperty() ) حيث أن هذا أيضا فوضوي بعض الشيء ، حتى غير إجابتي أعلاه ، أنا هنا لأقول ...

يمكنك جعل جمعيات الكائنات العادية تكرار! تتصرف تماما مثل Map s مع الاستخدام المباشر للخيال for...of
DEMO يعمل في Chrome و FF (أفترض ES6 فقط)

var ordinaryObject = {well:'hello', there:'!'};
for (let pair of ordinaryObject)
    //key:value
    console.log(pair[0] + ':' + pair[1]);

//or
for (let [key, value] of ordinaryObject)
    console.log(key + ':' + value);

طالما قمت بتضمين بلدي الرقائق أدناه:

//makes all objects iterable just like Maps!!! YAY
//iterates over Object.keys() (which already ignores prototype chain for us)
Object.prototype[Symbol.iterator] = function() {
    var keys = Object.keys(this)[Symbol.iterator]();
    var obj = this;
    var output;
    return {next:function() {
        if (!(output = keys.next()).done)
            output.value = [output.value, obj[output.value]];
        return output;
    }};
};

دون الحاجة إلى إنشاء كائن خريطة حقيقية لا تحتوي على السكر النحوي لطيف.

var trueMap = new Map([['well', 'hello'], ['there', '!']]);
for (let pair of trueMap)
    console.log(pair[0] + ':' + pair[1]);

في الواقع ، مع هذا الرقاقة ، إذا كنت لا تزال ترغب في الاستفادة من وظائف أخرى في الخريطة (دون إزعاجها كلها) ولكنها لا تزال تريد استخدام تدوين الكائن الأنيق ، لأن الكائنات الآن قابلة للتكرار يمكنك الآن إنشاء خريطة منه!

//shown in demo
var realMap = new Map({well:'hello', there:'!'});

بالنسبة لأولئك الذين لا يحبون الرقاقة ، أو الفوضى مع prototype بشكل عام ، لا تتردد في جعل وظيفة على النافذة بدلا من ذلك ، واصفا ذلك بشيء مثل getObjIterator() ثم ؛

//no prototype manipulation
function getObjIterator(obj) {
    //create a dummy object instead of adding functionality to all objects
    var iterator = new Object();

    //give it what the shim does but as its own local property
    iterator[Symbol.iterator] = function() {
        var keys = Object.keys(obj)[Symbol.iterator]();
        var output;

        return {next:function() {
            if (!(output = keys.next()).done)
                output.value = [output.value, obj[output.value]];
            return output;
        }};
    };

    return iterator;
}

الآن يمكنك أن تسميها كوظيفة عادية ، ولا يتأثر أي شيء آخر

var realMap = new Map(getObjIterator({well:'hello', there:'!'}))

أو

for (let pair of getObjIterator(ordinaryObject))

لا يوجد سبب لعدم نجاح ذلك.

مرحبا بكم في المستقبل.


لن يكتمل السؤال إذا لم نذكر عن طرق بديلة للتكرار من خلال الكائنات.

في الوقت الحاضر ، توفر العديد من مكتبات جافا سكريبت المعروفة طرقها الخاصة للتكرار على المجموعات ، أي عبر المصفوفات ، والأشياء ، والكائنات المشابهة للمصفوفة . هذه الطرق ملائمة للاستخدام ومتوافقة تمامًا مع أي متصفح.

  1. إذا كنت تعمل مع jQuery ، فيمكنك استخدام طريقة jQuery.each() . يمكن استخدامه للتكرار بسلاسة على كل من الكائنات والمصفوفات:

    $.each(obj, function(key, value) {
        console.log(key, value);
    });
    
  2. في Underscore.js يمكنك العثور على الطريقة _.each() ، والتي تتكرر عبر قائمة من العناصر ، مما يعطي كل دور بدوره إلى وظيفة مقدمة (انتبه إلى ترتيب الحجج في وظيفة التكرار !):

    _.each(obj, function(value, key) {
        console.log(key, value);
    });
    
  3. يوفر Lo-Dash عدة أساليب لتكرار خصائص الكائن. Basic _.forEach() (أو الاسم المستعار _.each() ) مفيد _.each() خلال كل من الكائنات _.each() ، ومع ذلك ، تعامل الكائنات (!) مع خاصية length مثل المصفوفات ، ولتجنب هذا السلوك يقترح استخدام _.forIn() و _.forOwn() (هذه أيضاً تحتوي على وسيطة value قادمة أولاً):

    _.forIn(obj, function(value, key) {
        console.log(key, value);
    });
    

    _.forIn() يتكرر عبر الخصائص الخاصة _.forOwn() الموروثة لكائن ، بينما يقوم _.forOwn() بالتكرار فقط على الخصائص الخاصة للكائن (بشكل أساسي hasOwnProperty وظيفة hasOwnProperty ). للكائنات البسيطة والحروف كائن سوف تعمل أي من هذه الأساليب بشكل جيد.

بشكل عام ، تحتوي جميع الطرق الموضحة على نفس السلوك مع أي كائنات تم توفيرها. إلى جانب استخدام for..in أصلية في حلقة .. فإن عادة تكون أسرع من أي تجريد ، مثل jQuery.each() ، هذه الأساليب أسهل بكثير في الاستخدام ، تتطلب أقل ترميز وتوفر معالجة أفضل للخطأ.


يجب عليك استخدام حلقة for-in

ولكن كن حذرا جدا عند استخدام هذا النوع من الحلقات ، لأن هذا سيؤدي إلى تكرار جميع الخصائص على طول سلسلة النموذج الأولي .

لذلك ، عند استخدام الحلقات for-in ، استخدم دائمًا طريقة hasOwnProperty لتحديد ما إذا كانت الخاصية الحالية في التكرار هي بالفعل خاصية للكائن الذي تقوم بفحصه:

for (var prop in p) {
    if (!p.hasOwnProperty(prop)) {
        //The current property is not a direct property of p
        continue;
    }
    //Do your logic with the property here
}

يمكن أن تكون الحلقات مثيرة للاهتمام عند استخدام جافا سكريبت الخالص. يبدو أن ECMA6 فقط (مواصفات جافا سكريبت 2015 الجديدة) حصلت على الحلقات تحت السيطرة. لسوء الحظ وأنا أكتب هذا ، لا يزال كل من المتصفحات وبيئة التطوير المتكاملة الشائعة (IDE) تناضل من أجل دعم الأجراس والصفارات الجديدة تمامًا.

في نظرة سريعة هنا ، تبدو حلقة كائن جافا سكريبت قبل ECMA6:

for (var key in object) {
  if (p.hasOwnProperty(key)) {
    var value = object[key];
    console.log(key); // This is the key;
    console.log(value); // This is the value;
  }
}

أيضا ، أنا أعرف أن هذا خارج النطاق مع هذا السؤال ولكن في عام 2011 ، أضاف ECMAScript 5.1 طريقة forEach فقط والتي خلقت أساسا طريقة محسنة جديدة للحلقة من خلال المصفوفات بينما لا تزال تترك أشياء غير متكررة مع المطول القديم ومربكة للحلقة . لكن الجزء الغريب هو أن طريقة forEach الجديدة هذه لا تدعم break الذي أدى إلى كل أنواع المشاكل الأخرى.

بشكل أساسي في عام 2011 ، لا توجد طريقة صلبة للحل في JavaScript بخلاف ما قررت العديد من المكتبات الشائعة (jQuery و Underscore وما إلى ذلك) إعادة التنفيذ.

اعتبارًا من عام 2015 ، أصبح لدينا الآن طريقة أفضل من أي شكل لحلقة (وكسر) أي نوع كائن (بما في ذلك المصفوفات والسلاسل). إليك ما ستبدو عليه حلقة في جافا سكريبت في النهاية عندما تصبح التوصية عامة:

for (let [key, value] of Object.entries(object)) {
    console.log(key); // This is the key;
    console.log(value); // This is the value;
}

لاحظ أن معظم المتصفحات لن تدعم الشفرة المذكورة أعلاه اعتبارًا من 18 حزيران 2016. حتى في Chrome ، يجب تمكين هذه العلامة الخاصة حتى تعمل: chrome://flags/#enable-javascript-harmony

وإلى أن يصبح هذا هو المعيار الجديد ، لا يزال من الممكن استخدام الطريقة القديمة ولكن هناك أيضًا بدائل في المكتبات الشائعة أو حتى بدائل خفيفة الوزن لأولئك الذين لا يستخدمون أيًا من هذه المكتبات.


يمكنك استخدام حلقة for-in كما هو موضح بواسطة الآخرين. ومع ذلك ، يجب عليك أيضًا التأكد من أن المفتاح الذي تحصل عليه هو خاصية فعلية لأحد الكائنات ، ولا يأتي من النموذج الأولي.

هذا هو المقتطف:

var p = {
    "p1": "value1",
    "p2": "value2",
    "p3": "value3"
};

for (var key in p) {
    if (p.hasOwnProperty(key)) {
        console.log(key + " -> " + p[key]);
    }
}


يمكنك فقط التكرار أكثر من ذلك مثل:

for (var key in p) {
  alert(p[key]);
}

لاحظ أن key لن يأخذ قيمة العقار ، إنه مجرد قيمة فهرس.


في ES6 لدينا رموز معروفة لكشف بعض الطرق الداخلية سابقًا ، يمكنك استخدامها لتحديد كيفية عمل المكررات لهذا الكائن:

var p = {
    "p1": "value1",
    "p2": "value2",
    "p3": "value3",
    *[Symbol.iterator]() {
        yield *Object.keys(this);
    }
};

[...p] //["p1", "p2", "p3"]

هذا سيعطي نفس النتيجة كما تستخدم ل ... في حلقة es6.

for(var key in p) {
    console.log(key);
}

ولكن من المهم معرفة القدرات التي تستخدمها الآن في es6!


في أحدث نص برمجي ، يمكنك القيام بشيء كالتالي:

Object.entries(p);

واجهت مشكلة مماثلة عند استخدام Angular ، وهنا الحل الذي وجدته.

الخطوة 1. الحصول على جميع مفاتيح الكائن. باستخدام Object.keys. هذا الأسلوب بإرجاع صفيف الخصائص الخاصة enumerable الخاصة الكائن.

الخطوة 2. إنشاء مجموعة فارغة. هذا هو المكان الذي ستعيش فيه جميع الخصائص ، لأن حلقة ngFor الجديدة ستشير إلى هذه المصفوفة ، يجب أن نلتقطها جميعًا. الخطوة 3. قم بتكرار كل المفاتيح ، وادفع كل واحدة في المصفوفة التي أنشأتها. هنا كيف يبدو ذلك في التعليمات البرمجية.

    // Evil response in a variable. Here are all my vehicles.
let evilResponse = { 
  "car" : 
    { 
       "color" : "red",
       "model" : "2013"
    },
   "motorcycle": 
    { 
       "color" : "red",
       "model" : "2016"
    },
   "bicycle": 
    { 
       "color" : "red",
       "model" : "2011"
    }
}
// Step 1. Get all the object keys.
let evilResponseProps = Object.keys(evilResponse);
// Step 2. Create an empty array.
let goodResponse = [];
// Step 3. Iterate throw all keys.
for (prop of evilResponseProps) { 
    goodResponse.push(evilResponseProps[prop]);
}

هنا رابط للنشر الأصلي. https://medium.com/@papaponmx/looping-over-object-properties-with-ngfor-in-angular-869cd7b2ddcc


يصبح كائن مكرر عندما يقوم بتنفيذ أسلوب .next ()

const james = {
name: 'James',
height: `5'10"`,
weight: 185,

[Symbol.iterator]() {
let properties = []
for (let key of Object.keys(james)){
     properties.push(key);
 }

index = 0;
return {
        next: () => {
            let key = properties[index];
            let value = this[key];
            let done = index >= properties.length - 1 ;
            index++;
            return { key, value, done };
        }
    };
  }

};


const iterator = james[Symbol.iterator]();

console.log(iterator.next().value); // 'James'
console.log(iterator.next().value); // `5'10`
console.log(iterator.next().value); // 185

var p = {
    "p1": "value1",
    "p2": "value2",
    "p3": "value3"
};

for (var key in p) {
    if (p.hasOwnProperty(key)) {
        console.log(key + " = " + p[key]);
    }
}
<p>
  Output:<br>
  p1 = values1<br>
  p2 = values2<br>
  p3 = values3
</p>


إذا كان أي شخص يحتاج إلى حلقة من خلال arrayObjects مع شرط :

var arrayObjects = [{"building":"A", "status":"good"},{"building":"B","status":"horrible"}];

for (var i=0; i< arrayObjects.length; i++) {
  console.log(arrayObjects[i]);
  
  for(key in arrayObjects[i]) {      
    
      if (key == "status" && arrayObjects[i][key] == "good") {
        
          console.log(key + "->" + arrayObjects[i][key]);
      }else{
          console.log("nothing found");
      }
   }
}


إذا كنت تريد التكرار فقط على الخصائص ، فاستخدم أحد الإجابات المذكورة أعلاه ، ولكن إذا كنت تريد التكرار أكثر من كل شيء بما في ذلك الوظائف ، فقد ترغب في استخدام Object.getOwnPropertyNames(obj)

for (let o of Object.getOwnPropertyNames(Math)) {
  console.log(o);
}

أنا في بعض الأحيان استخدام هذا لاختبار سريع جميع الوظائف على الأشياء مع المدخلات والمخرجات البسيطة.


سأفعل هذا بدلاً من التحقق من obj.hasOwnerPropertyكل for ... inحلقة.

var obj = {a : 1};
for(var key in obj){
    //obj.hasOwnProperty(key) is not needed.
    console.log(key);
}
//then check if anybody has messed the native object. Put this code at the end of the page.
for(var key in Object){
    throw new Error("Please don't extend the native object");
}






each