Javascript foreach loop trên đối tượng mảng kết hợp


181

Tại sao vòng lặp for-every của tôi không lặp lại đối tượng mảng kết hợp JavaScript của tôi?

// defining an array
var array = [];

// assigning values to corresponding keys
array["Main"] = "Main page";
array["Guide"] = "Guide page";
array["Articles"] = "Articles page";
array["Forum"] = "Forum board";

// expected: loop over every item,
// yet it logs only "last" assigned value - "Forum"
for (var i = 0; i < array.length; i++) {
    console.log(array[i]);
}

EDIT: jQuery each()có thể hữu ích: https://api.jquery.com/jQuery.each/


1
Bạn tạo một mảng nhưng sau đó sử dụng nó như một bản đồ. Có vẻ như bạn muốn một đối tượng đơn giản thay thế.
Jon

4
Không có những thứ như associative arraystrong JS: đó là Mảng đơn giản hoặc Đối tượng. Không có gì ngăn cản việc thêm các thuộc tính không phải là số Array, nhưng điều đó không làm cho nó associative- đặc biệt, thuộc lengthtính sẽ không tự động đếm các thuộc tính này.
raina77ow

3
re: Không có những thứ như mảng kết hợp trong JS. - diễn đạt theo một cách khác: JavaScript sử dụng tên "Object" thay vì tên "mảng kết hợp". Nhưng nó không có thuộc tính ".length".
Jesse Chisholm

Câu trả lời:


313

Các .lengthbất động sản chỉ theo dõi các thuộc tính với chỉ số số (phím). Bạn đang sử dụng chuỗi cho các phím.

Bạn có thể làm được việc này:

var arr_jq_TabContents = {}; // no need for an array

arr_jq_TabContents["Main"] = jq_TabContents_Main;
arr_jq_TabContents["Guide"] = jq_TabContents_Guide;
arr_jq_TabContents["Articles"] = jq_TabContents_Articles;
arr_jq_TabContents["Forum"] = jq_TabContents_Forum;

for (var key in arr_jq_TabContents) {
    console.log(arr_jq_TabContents[key]);
}

Để an toàn, đó là một ý tưởng tốt trong các vòng lặp như vậy để đảm bảo rằng không có thuộc tính nào là kết quả thừa kế bất ngờ:

for (var key in arr_jq_TabContents) {
  if (arr_jq_TabContents.hasOwnProperty(key))
    console.log(arr_jq_TabContents[key]);
}

chỉnh sửa - bây giờ có lẽ là một ý tưởng tốt để lưu ý rằng Object.keys()chức năng này có sẵn trên các trình duyệt hiện đại và trong Node, v.v. Hàm đó trả về các khóa "riêng" của một đối tượng, dưới dạng một mảng:

Object.keys(arr_jq_TabContents).forEach(function(key, index) {
  console.log(this[key]);
}, arr_jq_TabContents);

Hàm gọi lại được truyền đến .forEach()được gọi với mỗi khóa và chỉ mục của khóa trong mảng được trả về bởi Object.keys(). Nó cũng chuyển qua mảng mà hàm đang lặp, nhưng mảng đó không thực sự hữu ích với chúng ta; chúng ta cần đối tượng ban đầu . Điều đó có thể được truy cập trực tiếp bằng tên, nhưng (theo tôi) sẽ tốt hơn một chút để vượt qua nó một cách rõ ràng, được thực hiện bằng cách chuyển một đối số thứ hai đến .forEach()- đối tượng ban đầu - sẽ bị ràng buộc như thisbên trong cuộc gọi lại. (Chỉ thấy rằng điều này đã được ghi chú trong một bình luận dưới đây.)


Whats này var arr_jq_TabContents = {};? Ý tôi là {}
Szymon Toda

1
@Ultra nó là một đối tượng trống rỗng theo nghĩa đen. Nó chỉ có nghĩa là biến được khởi tạo với một tham chiếu đến một đối tượng trống mới.
Mũi nhọn

@Ultra bạn không cần một cá thể Array vì trong mã đó bạn không sử dụng nó như một mảng JavaScript. JavaScript không có "mảng kết hợp" như một số ngôn ngữ khác.
Mũi nhọn

1
Sự khác biệt giữa gán []và là {}gì? Chỉ có các nguyên mẫu khác nhau?
Sớm

8
Thay vì sử dụng hasOwnProperty, tất cả các trình duyệt web hiện đại đều có thể lặp lại các khóa của một đối tượng bằng cách sử dụng: Object.keys(arr_jq_TabContents).forEach( function(key) { ... } );
Gregory Bell

79

Đây là cách tiếp cận rất đơn giản. Ưu điểm là bạn cũng có thể nhận được các khóa:

for (var key in array) {
    var value = array[key];
    console.log(key, value);
}

Đối với ES6:

array.forEach(value => {
  console.log(value)
})  

Đối với ES6: (Nếu bạn muốn giá trị, chỉ mục và chính mảng)

array.forEach((value, index, self) => {
  console.log(value, index, self)
})  

12
Đừng sử dụng vartrong các vòng lặp gợi ý phạm vi không tồn tại. Sử dụng varở phía trước của vòng lặp hoặc lettrong vòng lặp.
ceving

2
@ceving, bạn có thể giải thích thêm về lý do tại sao không sử dụng var trong các vòng lặp? Tôi đến từ nền tảng C ++ / PHP và tôi không hiểu điều này. phạm vi tồn tại trong vòng lặp, nhưng tạm thời, vì vậy tôi không chắc ý của bạn là gì.
Dennis

6
@Dennis Trong hầu hết các ngôn ngữ, một khai báo biến trong một forvòng lặp tạo ra một phạm vi giới hạn trong phần thân của forvòng lặp. Nhưng trong JavaScript, một biến được khai báo bởi varluôn luôn có chức năng toàn cầu ngay cả khi bạn viết nó trong một forvòng lặp. Xem tại đây: davidwalsh.name/for-and-against-let
ceving

1
không bị rò rỉ bộ nhớ mỗi se, nhưng chắc chắn là "tràn bộ nhớ". vartrong Javascript tạo các biến trong bộ nhớ ngay cả sau khi vòng lặp được thực hiện.
ahnbizcad

Tôi nghĩ rằng quan điểm của những bình luận này liên quan đến việc sử dụng "var" là bây giờ sử dụng "let" nói chung nhưng cụ thể trong một vòng lặp. Những lý do được giải thích ở trên nhưng tóm lại là do phạm vi, "var" tạo ra phạm vi toàn cầu.
DeeZone

6

Đã có một số ví dụ đơn giản, nhưng tôi nhận thấy từ cách bạn đặt câu hỏi cho bạn rằng bạn có thể đến từ nền tảng PHP và bạn đang mong đợi JavaScript hoạt động theo cách tương tự - không. Một PHP arrayrất khác với JavaScript Array.

Trong PHP, một mảng kết hợp có thể thực hiện hầu hết những gì một mảng được lập chỉ mục số có thể (các array_*hàm hoạt động, bạn có thể count(), v.v.) Bạn chỉ cần tạo một mảng và bắt đầu gán cho các chỉ mục chuỗi thay vì số.

Trong JavaScript, mọi thứ đều là một đối tượng (ngoại trừ các nguyên hàm: chuỗi, số, boolean) và mảng là một triển khai nhất định cho phép bạn có các chỉ mục số. Bất cứ điều gì đẩy lên một mảng sẽ ảnh hưởng đến mình length, và có thể được lặp qua sử dụng phương pháp Array ( map, forEach,reduce , filter, find, vv) Tuy nhiên, bởi vì tất cả mọi thứ là một đối tượng, bạn sẽ luôn tự do chỉ đơn giản là tính assign, bởi vì đó là một cái gì đó bạn làm gì để bất kỳ đối tượng. Ký hiệu dấu ngoặc vuông đơn giản là một cách khác để truy cập vào một thuộc tính, vì vậy trong trường hợp của bạn:

array['Main'] = 'Main Page';

thực sự tương đương với:

array.Main = 'Main Page';

Từ mô tả của bạn, tôi đoán là bạn muốn có một 'mảng kết hợp', nhưng đối với JavaScript, đây là một trường hợp đơn giản sử dụng một đối tượng làm hashmap. Ngoài ra, tôi biết đó là một ví dụ, nhưng tránh các tên không có ý nghĩa chỉ mô tả loại biến (ví dụ array) và tên dựa trên những gì nó nên chứa (ví dụ pages). Các đối tượng đơn giản không có nhiều cách trực tiếp tốt để lặp lại, vì vậy thường chúng ta sẽ chuyển thành mảng trước bằng cách sử dụng Objectcác phương thức ( Object.keystrong trường hợp này - cũng có entriesvaluesđược thêm vào một số trình duyệt ngay bây giờ) mà chúng ta có thể lặp.

// assigning values to corresponding keys
const pages = {
  Main: 'Main page',
  Guide: 'Guide page',
  Articles: 'Articles page',
  Forum: 'Forum board',
};

Object.keys(pages).forEach((page) => console.log(page));

4

arr_jq_TabContents[key] xem mảng dưới dạng 0-index.


4

Đây là một cách đơn giản để sử dụng một mảng kết hợp làm kiểu Object chung:

Object.prototype.forEach = function(cb){
   if(this instanceof Array) return this.forEach(cb);
   let self = this;
   Object.getOwnPropertyNames(this).forEach(
      (k)=>{ cb.call(self, self[k], k); }
   );
};

Object({a:1,b:2,c:3}).forEach((value, key)=>{ 
    console.log(`key/value pair: ${key}/${value}`);
});



1

Điều này (về cơ bản) không chính xác trong hầu hết các trường hợp:

var array = [];
array["Main"] = "Main page";

Điều đó tạo ra một thuộc tính không thành phần trên mảng với tên Main. Mặc dù mảng là các đối tượng, thông thường bạn không muốn tạo các thuộc tính không phải thành phần trên chúng.

Nếu bạn muốn lập chỉ mục arraytheo các tên đó, thông thường bạn sẽ sử dụng một Maphoặc một đối tượng đơn giản, không phải là một mảng.

Với Map(ES2015 +), tôi sẽ gọi mapvì tôi sáng tạo:

let map = new Map();
map.set("Main", "Main page");

sau đó bạn lặp lại nó bằng cách sử dụng các trình vòng lặp từ , hoặc các phương thức của nó values, ví dụ:keysentries

for (const value of map.values()) {
    // Here, `value` will be `"Main page"`, etc.
}

Sử dụng một đối tượng đơn giản, mà tôi sẽ gọi một cách sáng tạo obj:

let obj = Object.create(null); // Creates an object with no prototype
obj.Main = "Main page"; // Or: `obj["Main"] = "Main page";`

sau đó bạn muốn lặp nội dung của nó sử dụng Object.keys, Object.valueshoặc Object.entries, ví dụ:

for (const value of Object.values(proches_X)) {
    // Here, `value` will be `"Main page"`, etc.
}

0

var obj = {
  no: ["no", 32],
  nt: ["no", 32],
  nf: ["no", 32, 90]
};

count = -1; // which must be static value
for (i in obj) {
  count++;
  if (obj.hasOwnProperty(i)) {
    console.log(obj[i][count])
  };
};

trong mã này tôi đã sử dụng phương thức ngoặc cho các giá trị cuộc gọi trong mảng vì nó chứa mảng, tuy nhiên, ý tưởng ngắn gọn là một biến i có khóa thuộc tính và với một vòng lặp gọi là cả hai giá trị của mảng liên kết

Phương pháp hoàn hảo, nếu bạn quan tâm, nhấn like


Bạn không lặp đi lặp lại một mảng, bạn đang lặp qua một đối tượng có mảng trong các khóa của nó .. Vui lòng đọc câu hỏi và xem ví dụ.
Pedro Joaquín

0

Bạn có thể làm được việc này

var array = [];

// assigning values to corresponding keys
array[0] = "Main page";
array[1] = "Guide page";
array[2] = "Articles page";
array[3] = "Forum board";


array.forEach(value => {
    console.log(value)
})
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.