Object.getOwnPropertyNames vs Object.keys


214

ความแตกต่างระหว่างObject.getOwnPropertyNamesและObject.keysในจาวาสคริปต์คืออะไร? นอกจากนี้ยังมีตัวอย่างที่น่าชื่นชม


3
ตัดสินจากบทความ MDN ทั้งสองข้อแตกต่างคือว่ารายการที่ส่งคืนมีคุณสมบัติที่Object.keys()ไม่สามารถนับได้หรือไม่: จะไม่ส่งคืนในขณะที่Object.getOwnPropertyNames()ทำอยู่
Sirko

คำตอบ:


289

มีความแตกต่างเล็กน้อย Object.getOwnPropertyNames(a)ผลตอบแทนที่ได้ทุกaคุณสมบัติของตัวเองของวัตถุ Object.keys(a)ส่งคืนคุณสมบัติทั้งหมดที่นับได้ หมายความว่าหากคุณกำหนดคุณสมบัติวัตถุของคุณโดยไม่ทำให้enumerable: falseทั้งสองวิธีนี้จะให้ผลลัพธ์ที่เหมือนกัน

ทดสอบง่าย:

var a = {};
Object.defineProperties(a, {
    one: {enumerable: true, value: 'one'},
    two: {enumerable: false, value: 'two'},
});
Object.keys(a); // ["one"]
Object.getOwnPropertyNames(a); // ["one", "two"]

หากคุณกำหนดคุณสมบัติโดยไม่ระบุตัวบอกคุณสมบัติของคุณสมบัติ (หมายถึงคุณไม่ได้ใช้Object.defineProperties) ตัวอย่างเช่น:

a.test = 21;

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


26
โดยเฉพาะอย่างยิ่งคุณสมบัติของวัตถุอาร์เรย์ไม่นับดังนั้นจึงไม่ปรากฏขึ้นในlength Object.keys
Barmar

6
@Barmar lengthคุณสมบัติของออบเจกต์อยู่บนต้นแบบไม่ใช่ตัวของมันเองดังนั้นจะไม่มีObject.keysและObject.getOwnPropertyNamesจะไม่แสดงรายการ
The Qodesmith

9
@TheQodes พร้อมผลการObject.getOwnPropertyNames(anyArray)รวมlength
หนาม

6
ฉันยืนแก้ไข! Object.getOwnPropertyNames(anyArray)รวมlengthอยู่ในอาร์เรย์ที่ส่งคืนแล้ว!
The Qodesmith

ใช่ แต่ Array.prototype ก็มีเช่นกัน เป็นเรื่องแปลกที่เราสามารถปรับเปลี่ยน Array.prototype เหมือนอาร์เรย์ปกติ (เช่น Array.prototype.push ('ก็ตาม') แต่ดูเหมือนว่าจะไม่มีผลกับอินสแตนซ์ Array ที่สร้างขึ้นใหม่ stackoverflow.com/questions/48020958/…
trollkotze

21

แตกต่างก็คือในกรณีของอาร์เรย์วิธีการจะกลับคุณสมบัติพิเศษที่เป็นObject.getOwnPropertyNameslength

var x = ["a", "b", "c", "d"];
Object.keys(x);  //[ '0', '1', '2', '3' ]
Object.getOwnPropertyNames(x);  //[ '0', '1', '2', '3', 'length' ]

1

สัญกรณ์ตัวอักษร vs ตัวสร้างเมื่อสร้างวัตถุ นี่คือสิ่งที่ทำให้ฉัน

const cat1 = {
    eat() {},
    sleep() {},
    talk() {}
};

// here the methods will be part of the Cat Prototype
class Cat {
    eat() {}
    sleep() {}
    talk() {}
}

const cat2 = new Cat()

Object.keys(cat1) // ["eat", "sleep", "talk"]
Object.keys(Object.getPrototypeOf(cat2)) // []

Object.getOwnPropertyNames(cat1) // ["eat", "sleep", "talk"]
Object.getOwnPropertyNames(Object.getPrototypeOf(cat2)) // ["eat", "sleep", "talk"]

cat1 // {eat: function, sleep: function, talk: function}
cat2 // Cat {}

// a partial of a function that is used to do some magic redeclaration of props
function foo(Obj) {
    var propNames = Object.keys(Obj);

    // I was missing this if
    // if (propNames.length === 0) {
    //     propNames = Object.getOwnPropertyNames(Obj);
    // }

    for (var prop in propNames) {
        var propName = propNames[prop];

        APIObject[propName] = "reasign/redefine or sth";
    }
}

ดังนั้นในกรณีของฉันfooฟังก์ชั่นไม่ทำงานถ้าฉันให้วัตถุประเภท cat2

มีวิธีอื่นในการสร้างวัตถุดังนั้นอาจมีจุดบกพร่องอื่น ๆ ในนั้นเช่นกัน


Object.getOwnPropertyNamesจะกลับมาชื่อคุณสมบัติสำหรับการและไม่ได้cat1 cat2สองวิธีในการสร้างวัตถุที่ไม่ก่อให้เกิดความแตกต่างระหว่างและObject.getOwnPropertyNames Object.keys
Boric

1
@ บอริกใช่คุณถูกต้อง ฉันควรใช้ Object.getPrototypeOf (cat2) กับทั้งสองวิธีแทน cat2 ฉันไม่สามารถแน่ใจได้เพราะฉันจำไม่ได้และไม่มีรหัส ฉันจะแก้ไขมันในคำตอบ
h3dkandi

0

ตามที่ได้อธิบายไปแล้ว.keysจะไม่ส่งคืนคุณสมบัติที่นับได้

เกี่ยวกับตัวอย่างหนึ่งในกรณีหลุมพรางคือErrorวัตถุ: คุณสมบัติบางอย่างของมันนับได้
ดังนั้นในขณะที่console.log(Object.keys(new Error('some msg')))อัตราผลตอบแทน[], console.log(Object.getOwnPropertyNames(new Error('some msg')))อัตราผลตอบแทน["stack", "message"]

console.log(Object.keys(new Error('some msg')));
console.log(Object.getOwnPropertyNames(new Error('some msg')));


-5

ข้อแตกต่างอีกอย่างคือ (อย่างน้อยกับ nodejs) ฟังก์ชั่น "getOwnPropertyNames" ไม่รับประกันการสั่งซื้อกุญแจนั่นคือสาเหตุที่ฉันมักจะใช้ฟังก์ชั่น "keys":

    Object.keys(o).forEach(function(k) {
      if (!o.propertyIsEnumerable(k)) return;
      // do something...
    });

1
นี่เป็นกรณีของ Node.js ในปัจจุบันหรือไม่และหากเป็นเช่นนั้นคุณทราบตัวอย่างใดบ้างที่getOwnPropertyNamesไม่เป็นไปตามลำดับหรือไม่ เนื่องจาก ES2015 ระบุคำสั่งซื้อObect.getOwnPropertyNamesในขณะที่คำสั่งซื้อสำหรับObect.keysยังคงขึ้นอยู่กับการใช้งาน
szupie

7
ฉันคิดเสมอว่าไม่มีคำสั่งของคีย์วัตถุ JS และคุณไม่ควรเชื่อถือแม้ว่าการใช้งานจะรักษาลำดับไว้หรือไม่
Juan Mendes

1
อืมฉันคิดว่ามันเป็นอีกทางหนึ่ง คำสั่งสำหรับ getOwnPropertyNames ถูกกำหนดไว้ในข้อมูลจำเพาะ Object.keys นั้นขึ้นอยู่กับการใช้งาน
tjvr

1
ทั้งหมดต่อไปนี้มีคำสั่งที่ไม่ระบุ: for-in loop, และObject.keys Object.getOwnPropertyNamesที่กล่าวว่าทั้งสามจะระบุในลำดับที่สอดคล้องกันด้วยความเคารพซึ่งกันและกัน
Thomas Eding
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.