Tôi sẽ thử cái này. Lưu ý rằng tôi không liên kết với ECMA và không có khả năng hiển thị quá trình ra quyết định của họ, vì vậy tôi không thể nói dứt khoát tại sao họ làm hoặc không làm gì cả. Tuy nhiên, tôi sẽ nêu các giả định của mình và chụp ảnh tốt nhất.
1. Tại sao phải thêm một for...of
cấu trúc ở vị trí đầu tiên?
JavaScript đã bao gồm một for...in
cấu trúc có thể được sử dụng để lặp lại các thuộc tính của một đối tượng. Tuy nhiên, nó không thực sự là một vòng lặp forEach , vì nó liệt kê tất cả các thuộc tính trên một đối tượng và có xu hướng chỉ hoạt động có thể đoán trước được trong những trường hợp đơn giản.
Nó bị hỏng trong các trường hợp phức tạp hơn (bao gồm cả với mảng, trong đó việc sử dụng nó có xu hướng không được khuyến khích hoặc bị xáo trộn hoàn toàn bởi các biện pháp bảo vệ cần thiết để sử dụng for...in
với một mảng một cách chính xác ). Bạn có thể giải quyết vấn đề đó bằng cách sử dụng hasOwnProperty
(trong số những thứ khác), nhưng điều đó hơi rườm rà và không phù hợp.
Vì vậy, do đó giả định của tôi là for...of
cấu trúc đang được thêm vào để giải quyết những khiếm khuyết liên quan đến for...in
cấu trúc và cung cấp tiện ích và tính linh hoạt cao hơn khi lặp lại mọi thứ. Mọi người có xu hướng coi for...in
như một forEach
vòng lặp có thể được áp dụng chung cho bất kỳ bộ sưu tập nào và tạo ra kết quả lành mạnh trong bất kỳ bối cảnh nào có thể, nhưng đó không phải là điều xảy ra. Các for...of
sửa lỗi vòng lặp đó.
Tôi cũng giả định rằng điều quan trọng đối với mã ES5 hiện có để chạy trong ES6 và tạo ra kết quả giống như nó đã làm trong ES5, vì vậy không thể thực hiện các thay đổi vi phạm, ví dụ, đối với hành vi của for...in
cấu trúc.
2. Làm thế nào để for...of
hoạt động?
Tài liệu tham khảo rất hữu ích cho phần này. Cụ thể, một đối tượng được xem xét iterable
nếu nó xác định thuộc Symbol.iterator
tính.
Định nghĩa thuộc tính phải là một hàm trả về các mục trong bộ sưu tập, từng mục một và đặt cờ cho biết có hay không có nhiều mục để tìm nạp. Các triển khai xác định trước được cung cấp cho một số kiểu đối tượng và tương đối rõ ràng là for...of
chỉ sử dụng đại biểu cho hàm trình vòng lặp.
Cách tiếp cận này rất hữu ích, vì nó giúp bạn cung cấp các trình vòng lặp của riêng bạn rất dễ dàng. Tôi có thể nói rằng cách tiếp cận có thể đã trình bày các vấn đề thực tế do nó phụ thuộc vào việc xác định một thuộc tính mà trước đây không có, ngoại trừ những gì tôi có thể nói rằng đó không phải là trường hợp vì thuộc tính mới về cơ bản bị bỏ qua trừ khi bạn cố tình tìm kiếm nó (tức là nó sẽ không hiển thị trong for...in
các vòng lặp dưới dạng khóa, v.v.). Vì vậy, không phải như vậy.
Bỏ qua các vấn đề không thực tế, có thể đã bị coi là gây tranh cãi về mặt khái niệm khi bắt đầu tất cả các đối tượng bằng một thuộc tính mới được xác định trước, hoặc ngầm hiểu rằng "mọi đối tượng là một tập hợp".
3. Tại sao các đối tượng không iterable
sử dụng for...of
theo mặc định?
Tôi đoán rằng đây là sự kết hợp của:
- Việc tạo tất cả các đối tượng
iterable
theo mặc định có thể được coi là không thể chấp nhận được vì nó thêm một thuộc tính mà trước đây không có hoặc vì một đối tượng không (nhất thiết) là một bộ sưu tập. Như Felix lưu ý, "việc lặp qua một hàm hoặc một đối tượng biểu thức chính quy" có nghĩa là gì?
- Các đối tượng đơn giản đã có thể được lặp lại bằng cách sử dụng
for...in
và không rõ việc triển khai trình lặp tích hợp có thể làm gì khác / tốt hơn for...in
hành vi hiện có . Vì vậy, ngay cả khi số 1 là sai và việc thêm thuộc tính được chấp nhận, nó có thể không được xem là hữu ích .
- Người dùng muốn tạo đối tượng của họ
iterable
có thể dễ dàng làm như vậy, bằng cách xác định thuộc Symbol.iterator
tính.
- Các ES6 đặc tả cũng cung cấp một đồ loại, mà là
iterable
theo mặc định và có một số ưu điểm nhỏ khác trên sử dụng một đối tượng đơn giản như một Map
.
Thậm chí còn có một ví dụ được cung cấp cho # 3 trong tài liệu tham khảo:
var myIterable = {};
myIterable[Symbol.iterator] = function* () {
yield 1;
yield 2;
yield 3;
};
for (var value of myIterable) {
console.log(value);
}
Cho rằng các đối tượng có thể dễ dàng được tạo ra iterable
, chúng đã có thể được lặp lại bằng cách sử dụng for...in
và có khả năng không có thỏa thuận rõ ràng về những gì một trình lặp đối tượng mặc định phải làm (nếu những gì nó làm có nghĩa là khác với những gì for...in
hiện có), có vẻ hợp lý đủ để các đối tượng không được tạo iterable
theo mặc định.
Lưu ý rằng mã mẫu của bạn có thể được viết lại bằng cách sử dụng for...in
:
for (let levelOneKey in object) {
console.log(levelOneKey);
console.log(object[levelOneKey]);
var levelTwoObj = object[levelOneKey];
for (let levelTwoKey in levelTwoObj ) {
console.log(levelTwoKey);
console.log(levelTwoObj[levelTwoKey]);
}
}
... hoặc bạn cũng có thể tạo đối tượng của mình iterable
theo cách bạn muốn bằng cách làm như sau (hoặc bạn có thể tạo tất cả các đối tượng iterable
bằng cách gán cho Object.prototype[Symbol.iterator]
):
obj = {
a: '1',
b: { something: 'else' },
c: 4,
d: { nested: { nestedAgain: true }}
};
obj[Symbol.iterator] = function() {
var keys = [];
var ref = this;
for (var key in this) {
keys.push(key);
}
return {
next: function() {
if (this._keys && this._obj && this._index < this._keys.length) {
var key = this._keys[this._index];
this._index++;
return { key: key, value: this._obj[key], done: false };
} else {
return { done: true };
}
},
_index: 0,
_keys: keys,
_obj: ref
};
};
Bạn có thể chơi với nó tại đây (trong Chrome, cho thuê): http://jsfiddle.net/rncr3ppz/5/
Biên tập
Và để trả lời cho câu hỏi đã cập nhật của bạn, vâng, có thể chuyển đổi một iterable
thành một mảng, sử dụng toán tử spread trong ES6.
Tuy nhiên, điều này dường như chưa hoạt động trong Chrome hoặc ít nhất là tôi không thể làm cho nó hoạt động trong jsFiddle của mình. Về lý thuyết, nó phải đơn giản như sau:
var array = [...myIterable];
Symbol.iterator
tính là có thể lặp lại. Vì vậy, bạn chỉ cần triển khai thuộc tính đó. Một giải thích khả thi cho lý do tại sao các đối tượng không thể lặp lại có thể là điều này ngụ ý rằng mọi thứ đều có thể lặp lại, vì mọi thứ đều là một đối tượng (tất nhiên là ngoại trừ nguyên thủy). Tuy nhiên, việc lặp qua một hàm hoặc một đối tượng biểu thức chính quy có nghĩa là gì?