سؤال

هذا السؤال لديه بالفعل إجابة هنا:

كيف يمكنني تعداد خصائص كائن JavaScript؟

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

هل كانت مفيدة؟

المحلول

بسيطا بما فيه الكفاية:

for(var propertyName in myObject) {
   // propertyName is what you want
   // you can get the value like this: myObject[propertyName]
}

الآن، لن تحصل على المتغيرات الخاصة بهذه الطريقة لأنها غير متوفرة.


يحرر: @bitwiseplatypus صحيح أنه إلا إذا كنت تستخدم hasOwnProperty() الطريقة، سوف تحصل على خصائص موروثة - ومع ذلك، لا أعرف لماذا يتوقع أي شخص مطلع على البرمجة الشيئية أي شيء أقل!عادةً ما يتعرض الشخص الذي يطرح هذا الأمر لتحذيرات دوجلاس كروكفورد بشأن هذا الأمر، الأمر الذي لا يزال يربكني قليلاً.مرة أخرى، يعد الوراثة جزءًا طبيعيًا من لغات OO وبالتالي فهو جزء من JavaScript، على الرغم من كونه نموذجًا أوليًا.

الآن، قال ذلك، hasOwnProperty() يكون مفيد للتصفية، ولكننا لا نحتاج إلى إصدار تحذير كما لو كان هناك شيء خطير في الحصول على الممتلكات الموروثة.

تحرير 2: @bitwiseplatypus يعرض الموقف الذي قد يحدث إذا قام شخص ما بإضافة خصائص/طرق إلى كائناتك في وقت لاحق من الوقت الذي كتبت فيه كائناتك في الأصل (عبر النموذج الأولي الخاص به) - في حين أنه من الصحيح أن هذا قد يسبب سلوكًا غير متوقع، فأنا شخصيًا لا أفعل ذلك لا أرى أن مشكلتي تماما.مجرد مسألة رأي.علاوة على ذلك، ماذا لو قمت بتصميم الأشياء بطريقة أستخدم فيها النماذج الأولية أثناء إنشاء الكائنات الخاصة بي ومع ذلك يكون لدي رمز يتكرر على خصائص الكائن وأريد جميع الخصائص الموروثة؟لن أستخدم hasOwnProperty().بعد ذلك، لنفترض أن شخصًا ما يضيف خصائص جديدة لاحقًا.هل هذا خطأي إذا كانت الأمور تتصرف بشكل سيء في تلك المرحلة؟أنا لا أعتقد ذلك.أعتقد أن هذا هو السبب وراء تحديد jQuery، على سبيل المثال، طرقًا لتوسيع كيفية عمله (عبر jQuery.extend و jQuery.fn.extend).

نصائح أخرى

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

var myObject = {foo: 'bar'};

for (var name in myObject) {
  alert(name);
}

// results in a single alert of 'foo'

Object.prototype.baz = 'quux';

for (var name in myObject) {
  alert(name);
}

// results in two alerts, one for 'foo' and one for 'baz'

لتجنب تضمين الخصائص الموروثة في التعداد الخاص بك، تحقق hasOwnProperty():

for (var name in myObject) {
  if (myObject.hasOwnProperty(name)) {
    alert(name);
  }
}

يحرر: أنا لا أتفق مع عبارة JasonBunting بأننا لا نحتاج إلى القلق بشأن تعداد الخصائص الموروثة.هناك يكون هناك خطر في تعداد الخصائص الموروثة التي لا تتوقعها، لأنها يمكن أن تغير سلوك التعليمات البرمجية الخاصة بك.

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

ولهذا السبب توفر جافا سكريبت hasOwnProperty(), ولهذا السبب يجب عليك استخدامه للتأكد من أن كود الطرف الثالث (أو أي كود آخر قد يعدل النموذج الأولي) لا يكسر كودك.وبصرف النظر عن إضافة بضعة بايتات إضافية من التعليمات البرمجية، ليس هناك أي جانب سلبي للاستخدام hasOwnProperty().

الطريقة القياسية، والتي تم اقتراحها بالفعل عدة مرات هي:

for (var name in myObject) {
  alert(name);
}

ومع ذلك، فإن Internet Explorer 6 و7 و8 بها خطأ في مترجم JavaScript، مما يؤدي إلى عدم تعداد بعض المفاتيح.إذا قمت بتشغيل هذا الكود:

var obj = { toString: 12};
for (var name in obj) {
  alert(name);
}

إذا سيتم تنبيه "12" في جميع المتصفحات باستثناء IE.سوف يتجاهل IE هذا المفتاح ببساطة.القيم الأساسية المتأثرة هي:

  • isPrototypeOf
  • hasOwnProperty
  • toLocaleString
  • toString
  • valueOf

لكي تكون آمنًا حقًا في IE، عليك استخدام شيء مثل:

for (var key in myObject) {
  alert(key);
}

var shadowedKeys = [
  "isPrototypeOf",
  "hasOwnProperty",
  "toLocaleString",
  "toString",
  "valueOf"
];
for (var i=0, a=shadowedKeys, l=a.length; i<l; i++) {
  if map.hasOwnProperty(a[i])) {
    alert(a[i]);
  }
}

والخبر السار هو أن EcmaScript 5 يحدد Object.keys(myObject) وظيفة، والتي تقوم بإرجاع مفاتيح كائن كمصفوفة وبعض المتصفحات (على سبيل المثال.Safari 4) قام بتنفيذه بالفعل.

في المتصفحات الحديثة (ECMAScript 5) للحصول على كافة الخصائص التي لا تعد ولا تحصى، يمكنك القيام بما يلي:

مفاتيح الكائن(obj)(راجع الرابط للحصول على مقتطف للتوافق مع الإصدارات السابقة على المتصفحات الأقدم)

أو للحصول أيضًا على خصائص غير قابلة للإحصاء:

Object.getOwnPropertyNames(obj)

تحقق من جدول توافق ECMAScript 5

معلومات إضافية:ما هي السمة لا تعد ولا تحصى؟

أعتقد أن أحد الأمثلة على الحالة التي فاجأتني ذات صلة:

var myObject = { name: "Cody", status: "Surprised" };
for (var propertyName in myObject) {
  document.writeln( propertyName + " : " + myObject[propertyName] );
}

ولكن لدهشتي، كان الإخراج

name : Cody
status : Surprised
forEach : function (obj, callback) {
    for (prop in obj) {
        if (obj.hasOwnProperty(prop) && typeof obj[prop] !== "function") {
            callback(prop);
        }
    }
}

لماذا؟قام برنامج نصي آخر على الصفحة بتوسيع النموذج الأولي للكائن:

Object.prototype.forEach = function (obj, callback) {
  for ( prop in obj ) {
    if ( obj.hasOwnProperty( prop ) && typeof obj[prop] !== "function" ) {
      callback( prop );
    }
  }
};
for (prop in obj) {
    alert(prop + ' = ' + obj[prop]);
}

كود جافا سكريبت بسيط:

for(var propertyName in myObject) {
   // propertyName is what you want.
   // You can get the value like this: myObject[propertyName]
}

مسج:

jQuery.each(obj, function(key, value) {
   // key is what you want.
   // The value is in: value
});

وجدته... for (property in object) { // do stuff } سيتم سرد جميع الخصائص، وبالتالي جميع المتغيرات المعلنة عالميًا على كائن النافذة..

فيما يلي كيفية تعداد خصائص الكائن:

var params = { name: 'myname', age: 'myage' }

for (var key in params) {
  alert(key + "=" + params[key]);
}

إذا كنت تستخدم تسطير أسفل السطر.js المكتبة، يمكنك استخدام الوظيفة مفاتيح:

_.keys({one : 1, two : 2, three : 3});
=> ["one", "two", "three"]

يمكنك استخدام ال for من الحلقة.

إذا كنت تريد استخدام مجموعة:

Object.keys(object1)

المرجع. مفاتيح الكائن ()

يحتوي إملاء بايثون على طريقة "مفاتيح"، وهذا مفيد حقًا.أعتقد أنه في JavaScript يمكننا الحصول على شيء ما:

function keys(){
    var k = [];
    for(var p in this) {
        if(this.hasOwnProperty(p))
            k.push(p);
    }
    return k;
}
Object.defineProperty(Object.prototype, "keys", { value : keys, enumerable:false });

يحرر:لكن إجابة @carlos-ruana تعمل بشكل جيد للغاية.لقد اختبرت Object.keys(window)، وكانت النتيجة هي ما كنت أتوقعه.

التعديل بعد 5 سنوات:انها ليست فكرة جيدة للتمديد Object, لأنه قد يتعارض مع المكتبات الأخرى التي قد ترغب في استخدامها keys على كائناتهم وسوف يؤدي إلى سلوك غير متوقع في مشروعك.إجابة @carlos-ruana هي الطريقة الصحيحة للحصول على مفاتيح الكائن.

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

أسلوب آخر مفيد هو استخدام Object.toJSON() الخاص بالنموذج الأولي لإجراء تسلسل للكائن إلى JSON، والذي سيُظهر لك أسماء الخصائص وقيمها.

var data = {name: 'Violet', occupation: 'character', age: 25, pets: ['frog', 'rabbit']};
Object.toJSON(data);
//-> '{"name": "Violet", "occupation": "character", "age": 25, "pets": ["frog","rabbit"]}'

http://www.prototypejs.org/api/object/tojson

ما زلت مبتدئًا في JavaScript، لكنني كتبت دالة صغيرة لطباعة جميع خصائص الكائن وأبنائه بشكل متكرر:

getDescription(object, tabs) {
  var str = "{\n";
  for (var x in object) {
      str += Array(tabs + 2).join("\t") + x + ": ";
      if (typeof object[x] === 'object' && object[x]) {
        str += this.getDescription(object[x], tabs + 1);
      } else {
        str += object[x];
      }
      str += "\n";
  }
  str += Array(tabs + 1).join("\t") + "}";
  return str;
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top