เหตุใดฉันจึงสามารถเพิ่มคุณสมบัติที่มีชื่อให้กับอาร์เรย์ราวกับว่ามันเป็นวัตถุ


105

ข้อมูลโค้ดสองรายการต่อไปนี้ดูเหมือนจะเทียบเท่ากับฉัน:

var myArray = Array();
myArray['A'] = "Athens";
myArray['B'] = "Berlin";

และ

var myObject = {'A': 'Athens', 'B':'Berlin'};

เพราะทั้งคู่มีพฤติกรรมเหมือนกันและtypeof(myArray) == typeof(myObjects)(ทั้งคู่ให้ผล 'วัตถุ')

มีความแตกต่างระหว่างตัวแปรเหล่านี้หรือไม่?

คำตอบ:


131

แทบทุกอย่างในจาวาสคริปต์เป็นวัตถุดังนั้นคุณสามารถ "ละเมิด" วัตถุArray ได้โดยตั้งค่าคุณสมบัติตามอำเภอใจ สิ่งนี้ควรถือว่าเป็นอันตรายแม้ว่า อาร์เรย์มีไว้สำหรับข้อมูลที่จัดทำดัชนีเป็นตัวเลข - สำหรับคีย์ที่ไม่ใช่ตัวเลขให้ใช้ Object

นี่คือตัวอย่างที่ชัดเจนมากขึ้นว่าทำไมคีย์ที่ไม่ใช่ตัวเลขจึงไม่ "พอดี" กับอาร์เรย์:

var myArray = Array();
myArray['A'] = "Athens";
myArray['B'] = "Berlin";

alert(myArray.length);

สิ่งนี้จะไม่แสดง '2' แต่เป็น '0' - อย่างมีประสิทธิภาพไม่มีการเพิ่มองค์ประกอบลงในอาร์เรย์มีเพียงคุณสมบัติใหม่บางอย่างที่เพิ่มลงในวัตถุอาร์เรย์


4
myArray.length ส่งคืนดัชนี / คีย์ตัวเลขขององค์ประกอบสุดท้ายในอาร์เรย์ แต่ไม่ใช่จำนวนองค์ประกอบที่แท้จริง คุณสมบัติของวัตถุ Array ไม่เหมือนกับค่าอาร์เรย์หรือไม่?
Dasha Salo

1
ฉันแค่พยายามแสดงให้เห็นถึงความหมายที่ตั้งใจไว้ของวัตถุ Array นั้นถูกใช้ในทางที่ผิดหากคุณปฏิบัติกับมันเหมือนวัตถุทั่วไป บทความที่เชื่อมโยงทำได้ดีกว่า :)
Paul Dixon

13
ครั้งต่อไปที่มีคนบอกว่า JavaScript เป็นภาษาที่ดีในการพัฒนาฉันจะแสดงตัวอย่างนี้ให้เขาดู ขอบคุณ.
Olivier Pons

@Olivier สิ่งที่คุณเรียกว่า "บั๊ก" อาจเป็น "ฟีเจอร์" ที่ยอดเยี่ยมได้เช่นกัน คุณสามารถเพิ่มการพูดและคำอธิบายให้กับอาร์เรย์โดยไม่มีผลต่อเนื้อหาหรือความยาวของพวกเขาและโดยไม่ต้องห่อไว้ในวัตถุที่มีtitle, descriptionและitemsคุณสมบัติ ทุกอย่างขึ้นอยู่กับว่าคุณรู้ภาษาและใช้อย่างไร
tao

การใช้คุณสมบัติแบบกำหนดเองบน Arrays นั้นไม่ผิดโดยเนื้อแท้ มีอะไรผิดปกติที่คาดหวังให้พวกเขาทำหน้าที่เป็นสมาชิกอาร์เรย์เมื่อคุณทำ เป็นคุณสมบัติของอาร์เรย์ไม่ใช่สมาชิกดังนั้นจึงไม่ได้รับผลกระทบจากวิธีอาร์เรย์ นี่เป็นคำกล่าวของผู้เขียนบทความที่เชื่อมโยงข้างต้นในความคิดเห็น ในความเป็นธรรมฉันขอแนะนำให้ปฏิบัติเช่นนี้เนื่องจากอาจทำให้ผู้คนที่ใช้รหัสของคุณสับสน หรือหากพวกเขาเพิ่งเริ่มต้นมันจะทำให้พวกเขาอยู่บนเส้นทางที่อันตรายโดยอำนาจของตัวอย่าง แต่ฉันจะไม่บอกว่า JavaScript ไม่ดีเพราะมันช่วยให้สิ่งต่างๆส่วนใหญ่ไม่ได้รับอนุญาต
tao

14

ในอาร์เรย์ JS เป็นอ็อบเจ็กต์ซึ่งมีการปรับเปลี่ยนเพียงเล็กน้อย (พร้อมฟังก์ชันอื่น ๆ อีกเล็กน้อย)

ฟังก์ชั่นเช่น:

concat
every   
filer
forEach
join
indexOf
lastIndexOf
map
pop
push
reverse
shift
slice
some
sort
splice
toSource
toString
unshift
valueOf 

แม้ว่าฉันไม่คิดว่าฟังก์ชั่นทั้งหมดที่ระบุไว้นั้นมีอยู่แล้วในการใช้งาน JS ทุกครั้ง ความแตกต่างอื่น ๆ ก็คือต้นแบบที่แตกต่างกัน (ซึ่งโดยนัยของฟังก์ชันพิเศษเหล่านั้น)
Rashack

6

ฉันคิดว่าฉันเปรียบเทียบและคลุมเครือเกินไปกับคำตอบก่อนหน้านี้ ชี้แจงดังนี้

อินสแตนซ์ของ Array, Boolean, Date, Function, Number, RegExp, String เป็น Object แต่ได้รับการปรับปรุงด้วยวิธีการและคุณสมบัติเฉพาะสำหรับแต่ละประเภท ตัวอย่างเช่นอาร์เรย์มีlengthคุณสมบัติที่กำหนดไว้ล่วงหน้าในขณะที่วัตถุทั่วไปไม่มี

javascript:alert([].length+'\n'+{}.length)

แสดง

0
ไม่ได้กำหนด

โดยภายในตัวแปล FF Gecko ยังแยกความแตกต่างระหว่าง Arrays และ Objects ทั่วไปด้วยความแตกต่างที่แตกต่างกันในการประเมินโครงสร้างภาษา

javascript:
  ra=[  "one",   "two",   "three"]; ra.a=4;
  ob={0:"one", 1:"two", 2:"three"}; ob.a=4;
  alert(
    ra            +"\n\n"+
    ob            +"\n\n"+
    ra.toSource() +"\n\n"+
    ra.a          +"\t .toSource() forgot me! \n\n"+
    ra.length     +"\t and my length! \n\n"+
    ob.toSource());
  ps=""; for(i in ra)ps+=i+" "; alert(ps);  /* NB .length is missing! */
  ps=""; for(i in ob)ps+=i+" "; alert(ps);

การแสดง

หนึ่งสองสาม

[วัตถุวัตถุ]

["หนึ่งสองสาม"]

4. toSource () ลืมฉัน! 

3 และความยาวของฉัน! 

({0: "หนึ่ง", 1: "สอง", 2: "สาม", ก: 4})

และ0 1 2 aและ0 1 2 a.

เกี่ยวกับคำสั่งที่ว่าวัตถุทั้งหมดเป็นฟังก์ชัน:

มันเป็นค่าไวยากรณ์ที่ถูกต้องหรือความหมายที่จะใช้วัตถุเช่นพลเป็นหน้าที่เหมือน123()หรือ"abc"()หรือ[]()หรือ{}()หรือobj()ที่objถูกกว่าชนิดอื่น ๆดังนั้นตัวอย่างวัตถุโดยพลการไม่ได้เป็นFunction Functionอย่างไรก็ตามให้วัตถุobjและประเภทเป็นArray, Boolean, Date, ...อย่างไรobjมาเป็นArray, Boolean, Date, ...อย่างไร? คืออะไรArray, Boolean, Date, ...?

javascript:
    alert([Array, Boolean, Date, Function, 
              Number, Object, RegExp, String] . join('\n\n') );

แสดง

function Array() {
    [native code]
}

function Boolean() {
    [native code]
}

function Date() {
    [native code]
}

function Function() {
    [native code]
}

function Number() {
    [native code]
}

function Object() {
    [native code]
}

function RegExp() {
    [native code]
}

function String() {
    [native code]
}

ในทุกกรณีหากไม่มีการเทียบเคียงประเภทวัตถุจะปรากฏเป็นfunctionคำจำกัดความดังนั้นคำสั่งว่าวัตถุทั้งหมดเป็นฟังก์ชัน! (ลิ้นในแก้มคือฉันตั้งใจบดบังและเบลอความแตกต่างของอินสแตนซ์วัตถุด้วยประเภทของมัน! แต่ยังแสดงให้เห็นว่า "คุณไม่สามารถมีได้หากไม่มีอีก", Object และ Function! การใช้ตัวพิมพ์ใหญ่เน้น type เป็น ตรงข้ามกับอินสแตนซ์)

ทั้งการทำงานและวัตถุกระบวนทัศน์ดูเหมือนจะเป็นพื้นฐานในการเขียนโปรแกรมและการดำเนินการของ JS ล่ามระดับต่ำในตัวพื้นฐานเช่นMathและและJSONtrue

 javascript:alert([Math, JSON, true.toSource()].join("\n\n"));

แสดง

[object Math]

[object JSON]

(new Boolean(true))

ในช่วงเวลาของการพัฒนา Javascript รูปแบบการเขียนโปรแกรมที่เน้นวัตถุเป็นศูนย์กลาง (OOP's - Object Oriented Programming style - "s" is my own pun!) อยู่ในสมัยและล่ามได้รับการตั้งชื่อในทำนองเดียวกันกับ Java เพื่อให้มีความน่าเชื่อถือมากขึ้น . เทคนิคการเขียนโปรแกรมเชิงฟังก์ชันถูกลดทอนไปสู่การตรวจสอบที่เป็นนามธรรมและลึกลับมากขึ้นซึ่งศึกษาทฤษฎีของ Automata, ฟังก์ชันเรียกซ้ำ, ภาษาที่เป็นทางการ ฯลฯ และไม่เป็นที่พอใจ อย่างไรก็ตามจุดแข็งของการพิจารณาอย่างเป็นทางการเหล่านี้ปรากฏให้เห็นอย่างชัดเจนใน Javascript โดยเฉพาะอย่างยิ่งเมื่อนำไปใช้ในเอ็นจิ้น Gecko ของ FF (กล่าวคือ.toSource())


นิยามวัตถุสำหรับฟังก์ชันเป็นที่น่าพึงพอใจอย่างยิ่งเนื่องจากถูกกำหนดให้เป็นความสัมพันธ์ที่เกิดซ้ำ! กำหนดโดยใช้นิยามของมันเอง!

function Function() { [native code] }

function Object() { [native code] }และตั้งแต่ฟังก์ชั่นเป็นวัตถุเดียวกันถือเป็นความเชื่อมั่นสำหรับ

คำจำกัดความอื่น ๆ ส่วนใหญ่เป็นไปตามค่าเทอร์มินัลคงที่ อย่างไรก็ตามeval()เป็นแบบดั้งเดิมที่ทรงพลังเป็นพิเศษดังนั้น String จึงสามารถฝังฟังก์ชันการทำงานได้ตามอำเภอใจ

โปรดสังเกตอีกครั้งภาษาที่ใช้ด้านบนปิดบังประเภทวัตถุและความแตกต่างของอินสแตนซ์


5

ทุกอย่างใน JavaScript เป็นวัตถุนอกเหนือจากประเภทดั้งเดิม

รหัส

var myArray = Array();

สร้างอินสแตนซ์ของวัตถุ Array ในขณะที่

var myObject = {'A': 'Athens', 'B':'Berlin'};

สร้างอินสแตนซ์ของวัตถุ Object

ลองใช้รหัสต่อไปนี้

alert(myArray.constructor)
alert(myObject.constructor)

ดังนั้นคุณจะเห็นความแตกต่างอยู่ในประเภทของตัวสร้างวัตถุ

อินสแตนซ์ของวัตถุ Array จะมีคุณสมบัติและวิธีการทั้งหมดของ Array ต้นแบบ


2

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

var arrName = [];
arrName[5] = "test";
arrName.length; // <- 6

อาร์เรย์ใช้เพื่อจัดเก็บสิ่งต่างๆด้วยดัชนีลำดับ - ใช้เหมือนอาร์เรย์สแต็กหรือคิวแบบดั้งเดิม ออบเจ็กต์คือแฮช - ใช้สำหรับข้อมูลที่มีคีย์เฉพาะ


2

คุณสามารถเพิ่มคุณสมบัติที่มีชื่อให้กับเกือบทุกอย่างในจาวาสคริปต์ แต่ไม่ได้หมายความว่าคุณควร Arrayใน javascript ควรใช้เป็นรายการหากคุณต้องการให้ใช้อาร์เรย์ที่เชื่อมโยงObjectแทน

ระวังว่าหากคุณต้องการใช้Arrayคุณสมบัติที่มีชื่อแทนคุณสมบัติObjectเหล่านั้นจะไม่สามารถเข้าถึงได้แบบfor...ofวนซ้ำและคุณอาจได้รับผลลัพธ์ที่ไม่คาดคิดเมื่อ JSON เข้ารหัสเพื่อส่งผ่าน ดูตัวอย่างด้านล่างซึ่งดัชนีที่ไม่ใช่ตัวเลขทั้งหมดถูกละเว้น:

let arr = [];
let obj = {};

arr['name'] = 'John';
obj['name'] = 'John';

console.log(arr);    // will output [name: "John"]
console.log(obj);    // will output {name: "John"}

JSON.stringify(arr); // will return [] <- not what you expected
JSON.stringify(obj); // will return {"name":"John"}

-1

- {}หมายเหตุเป็นเพียงน้ำตาลสังเคราะห์เพื่อทำให้รหัสดีขึ้น ;-)

JavaScript มีโครงสร้างที่คล้ายกันหลายอย่างเช่นการสร้างฟังก์ชันโดยที่ function () เป็นเพียงคำพ้องความหมายของ

var Func = new Function("<params>", "<code>");

3
ตัวสร้างฟังก์ชันไม่ใช่คำพ้องความหมายของฟังก์ชันลิเทอรัล ลิเทอรัลถูกกำหนดขอบเขตคำศัพท์ในขณะที่ตัวสร้างเป็นโกลบอล {}คือสัญกรณ์ออบเจ็กต์ตามตัวอักษร[]เป็นอาร์เรย์ตัวอักษรฉันไม่แน่ใจว่าอะไรคือจุดที่คุณตอบ
Juan Mendes

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