Tại sao tôi có thể thêm các thuộc tính đã đặt tên vào một mảng như thể nó là một đối tượng?


105

Hai đoạn mã khác nhau sau đây có vẻ tương đương với tôi:

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

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

bởi vì cả hai đều hoạt động giống nhau, và cũng typeof(myArray) == typeof(myObjects)(cả hai đều mang lại 'đối tượng').

Có sự khác biệt nào giữa các biến thể này không?

Câu trả lời:


131

Hầu như mọi thứ trong javascript đều là một đối tượng, vì vậy bạn có thể "lạm dụng" một đối tượng Array bằng cách đặt các thuộc tính tùy ý trên đó. Mặc dù vậy, điều này nên được coi là có hại . Mảng dành cho dữ liệu được lập chỉ mục số - đối với các khóa không phải số, hãy sử dụng Đối tượng.

Dưới đây là một ví dụ cụ thể hơn tại sao các phím không phải số không "vừa" với Mảng:

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

alert(myArray.length);

Điều này sẽ không hiển thị '2', mà là '0' - một cách hiệu quả, không có phần tử nào được thêm vào mảng, chỉ một số thuộc tính mới được thêm vào đối tượng mảng.


4
myArray.length trả về chỉ số / khóa số của phần tử cuối cùng trong mảng nhưng không phải là số phần tử thực tế. Các thuộc tính của đối tượng Array không giống với các giá trị của mảng?
Dasha Salo

1
Tôi chỉ đang cố gắng minh họa ngữ nghĩa dự định của đối tượng Array bị lạm dụng nếu bạn chỉ coi nó như một đối tượng thông thường. Mặc dù vậy, bài báo được liên kết thực hiện công việc tốt hơn :)
Paul Dixon

13
Lần tới khi ai đó nói JavaScript là một ngôn ngữ tốt để phát triển, tôi sẽ cho anh ta xem mẫu này. Cảm ơn bạn.
Olivier Pons

@Olivier, cái bạn gọi là "lỗi" cũng có thể là một "tính năng" tuyệt vời. Bạn có thể thêm một tittle và mô tả cho mảng mà không ảnh hưởng nội dung hoặc chiều dài của họ và mà không cần phải bọc chúng trong đối tượng với title, descriptionitemstài sản. Tất cả phụ thuộc vào mức độ bạn biết ngôn ngữ và cách bạn sử dụng ngôn ngữ đó.
tao

Sử dụng thuộc tính tùy chỉnh trên Mảng vốn dĩ không sai. Có gì sai khi mong đợi họ đóng vai trò là thành viên mảng một khi bạn làm vậy. Chúng là thuộc tính mảng, không phải là thành viên, do đó không bị ảnh hưởng bởi các phương thức mảng. Điều này thực sự được nói bởi tác giả của bài báo được liên kết ở trên, trong các bình luận. Bây giờ, công bằng mà nói, tôi khuyên bạn không nên sử dụng nó như một thông lệ, vì nó có thể sẽ gây nhầm lẫn cho những người sử dụng mã của bạn. Hoặc, nếu họ chỉ mới bắt đầu, nó sẽ đưa họ vào con đường nguy hiểm, chẳng hạn như sức mạnh. Nhưng tôi sẽ không nói JavaScript là xấu vì nó cho phép những thứ mà hầu hết không mong đợi được phép.
tao

14

Trong mảng JS là các đối tượng, chỉ cần sửa đổi một chút (với một vài chức năng nữa).

Các chức năng như:

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

Mặc dù tôi không nghĩ rằng tất cả các hàm được liệt kê đều được tích hợp sẵn trong mỗi lần triển khai JS, nhưng bạn đã hiểu rõ. Sự khác biệt khác sẽ là nguyên mẫu khác (được ngụ ý bởi các chức năng bổ sung đó).
Rashack

6

Tôi nghĩ, tôi quá ẩn dụ và khó hiểu với câu trả lời trước. Làm rõ sau đây.

Một thể hiện của Array, Boolean, Date, Function, Number, RegExp, String là một Object nhưng được tăng cường với các phương thức và thuộc tính cụ thể cho từng loại. Ví dụ: một mảng có thuộc tính được xác định trước lengthtrong khi các đối tượng chung thì không.

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

màn hình

0
chưa xác định

Về cơ bản, trình thông dịch FF Gecko cũng phân biệt giữa Mảng và Đối tượng chung với sự khác biệt rõ ràng đánh giá cấu trúc ngôn ngữ.

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);

trưng bày

một hai ba

[đối tượng Đối tượng]

["một hai ba"]

4 .toSource () quên tôi! 

3 và chiều dài của tôi! 

({0: "một", 1: "hai", 2: "ba", a: 4})

0 1 2 a0 1 2 a .

Về tuyên bố rằng tất cả các đối tượng là các hàm:

Nó không phải là cú pháp hay ngữ nghĩa chính xác để sử dụng một trường hợp đối tượng tùy ý như là một chức năng như 123()hoặc "abc"()hoặc []()hoặc {}()hoặc obj()nơi objlà bất kỳ loại nào khác hơn Function, vì vậy một đối tượng INSTANCE tùy ý không phải là một Function. Tuy nhiên, với một đối tượng objvà nó thuộc loại như Array, Boolean, Date, ...thế nào, làm thế nào objđể trở thành một đối tượng Array, Boolean, Date, ...? An là Array, Boolean, Date, ...gì?

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

màn hình

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]
}

Trong mọi trường hợp, không có ký hiệu tương đương, kiểu đối tượng biểu hiện dưới dạng function định nghĩa, do đó phát biểu rằng tất cả các đối tượng đều là hàm! (Điều khó hiểu là tôi đã cố tình che khuất và làm mờ sự phân biệt của một đối tượng đối tượng với đối tượng cùng loại! Tuy nhiên, điều này cho thấy "bạn không thể có cái này mà không có cái kia", Đối tượng và Hàm! Viết hoa nhấn mạnh kiểu là trái ngược với ví dụ.)

Cả mô hình chức năng và đối tượng dường như là nền tảng cho việc lập trình và triển khai các nguyên thủy tích hợp sẵn của trình thông dịch JS cấp thấp, chẳng hạn như MathJSONtrue.

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

màn hình

[object Math]

[object JSON]

(new Boolean(true))

Vào thời điểm phát triển của Javascript, một phong cách lập trình lấy đối tượng làm trung tâm (OOP's - Object Oriented Programming style - "'s" là cách chơi chữ của riêng tôi!) Đã thịnh hành và trình thông dịch cũng được đặt tên tương tự với Java để mang lại độ tin cậy cao hơn cho nó. . Các kỹ thuật lập trình chức năng đã được xếp hạng cho các kỳ thi trừu tượng hơn và bí truyền hơn nghiên cứu các lý thuyết về Automata, Hàm đệ quy, Ngôn ngữ chính thức, v.v. và những thứ đó không dễ hiểu. Tuy nhiên, điểm mạnh của những cân nhắc chính thức này được thể hiện rõ ràng trong Javascript, đặc biệt khi được triển khai trong engine Gecko của FF (ví dụ .toSource():).


Định nghĩa Đối tượng cho Hàm đặc biệt thỏa mãn vì nó được định nghĩa như một quan hệ lặp lại! được định nghĩa bằng cách sử dụng định nghĩa riêng của nó!

function Function() { [native code] }
và vì một chức năng là một Đối tượng nên tình cảm giống nhau
function Object() { [native code] }.

Hầu hết các định nghĩa khác đều tuân theo giá trị đầu cuối tĩnh. Tuy nhiên, eval()là một nguyên thủy đặc biệt mạnh mẽ và vì vậy một Chuỗi cũng có thể nhúng chức năng tùy ý.

Lưu ý một lần nữa, ngôn ngữ bản ngữ được sử dụng ở trên che khuất sự phân biệt kiểu đối tượng và đối tượng.


5

Mọi thứ trong JavaScript là một đối tượng bên cạnh các kiểu nguyên thủy.

Mật mã

var myArray = Array();

tạo một thể hiện của đối tượng Array trong khi

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

tạo một thể hiện của đối tượng Object.

Hãy thử mã sau

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

Vì vậy, bạn sẽ thấy sự khác biệt là ở loại phương thức tạo đối tượng.

Thể hiện của đối tượng Array sẽ chứa tất cả các thuộc tính và phương thức của nguyên mẫu Array.


2

Sự khác biệt giữa các mảng và các đối tượng khác trong JavaScript. Mặc dù mảng có thuộc tính độ dài cập nhật một cách kỳ diệu, nhưng đối với các đối tượng khác ngoài mảng thì không có cách nào để triển khai thuộc tính đó.

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

Mảng được sử dụng để lưu trữ những thứ có chỉ mục thứ tự - sử dụng nó giống như một mảng, ngăn xếp hoặc hàng đợi truyền thống. Một đối tượng là một hàm băm - sử dụng nó cho dữ liệu có một khóa riêng biệt.


2

Bạn có thể thêm các thuộc tính đã đặt tên vào hầu hết mọi thứ trong javascript nhưng điều đó không có nghĩa là bạn nên làm như vậy. Arraytrong javascript nên được sử dụng dưới dạng danh sách, nếu bạn muốn sử dụng mảng kết hợpObject .

Hãy lưu ý rằng nếu bạn thực sự muốn sử dụng một Arraythuộc tính có tên thay vì Objectcác thuộc tính đó sẽ không thể truy cập được trong for...ofvòng lặp và bạn cũng có thể nhận được kết quả không mong muốn khi mã hóa JSON để chuyển nó xung quanh. Xem ví dụ bên dưới, nơi tất cả các chỉ mục không phải số đều bị bỏ qua:

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

Các {}-notation là đường chỉ cú pháp để làm cho đẹp hơn đang ;-)

JavaScript có nhiều cấu trúc tương tự như cấu trúc của các hàm, trong đó hàm () chỉ là một từ đồng nghĩa với

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

3
Hàm tạo hàm KHÔNG phải là từ đồng nghĩa với nghĩa đen của hàm. Nghĩa đen là phạm vi từ vựng trong khi hàm tạo là toàn cục. {}là ký hiệu đối tượng theo nghĩa đen, []là mảng theo nghĩa đen, tôi không chắc câu trả lời của bạn là gì.
Juan Mendes

Ngoài ra, các hàm đã khai báo có sẵn trước khi bất kỳ mã nào được thực thi, các phép gán sử dụng hàm tạo Hàm sẽ không khả dụng cho đến khi mã tạo chúng thực thi.
RobG
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.