cách phá vỡ hàm _.each trong underscore.js


200

Tôi đang tìm cách để ngăn chặn các lần lặp của _.each()phương thức underscore.js , nhưng không thể tìm ra giải pháp. jQuery .each()có thể phá vỡ nếu bạn làm return false.

Có cách nào để dừng dấu gạch dưới mỗi () không?

_([1,2,3]).each(function(v){
    if (v==2) return /*what?*/;
})

4
Tôi không nghĩ rằng nó có thể, bởi vì forEachchức năng gốc cũng không cung cấp tính năng này.
Felix Kling

8
Thông thường khi sử dụng eachvới bao đóng (trong hầu hết các ngôn ngữ), bạn muốn lọc danh sách của mình trước. Bằng cách đó, bạn không phải lo lắng về việc phá vỡ nó. Nói chung, nếu bạn cần nghỉ sớm từ một lần lặp, có lẽ có một cách khác mà bạn có thể làm.
Rob Hruska

Dưới đây là một vài câu hỏi liên quan đến Groovy, trong đó hành vi (không có khả năng thoát khỏi sự eachđóng cửa một cách thuận tiện ) tương tự như JavaScript.
Rob Hruska

@Dmitry_F, như những người khác đã lưu ý, bạn không thể thực hiện chính xác những gì bạn yêu cầu. Nhưng như tôi đã chứng minh, bạn có thể sử dụng Array.everyđể mô phỏng hành vi bạn muốn.
aeskr

@Rob. Chúc mừng. Nhận xét đầu tiên thực sự hữu ích. Quả thực có một cách khác tôi có thể làm được.
net.uk.sweet

Câu trả lời:


267

Bạn không thể thoát khỏi eachphương thức mà nó mô phỏng forEachhành vi của phương thức gốc và bản địa forEachkhông cung cấp để thoát khỏi vòng lặp (ngoại trừ việc ném một ngoại lệ).

Tuy nhiên, tất cả hy vọng không bị mất! Bạn có thể sử dụng Array.everyphương pháp. :)

Từ liên kết đó:

everythực thi callbackhàm được cung cấp một lần cho mỗi phần tử có trong mảng cho đến khi tìm thấy một phần tử callbacktrả về giá trị sai. Nếu một phần tử như vậy được tìm thấy, everyphương thức ngay lập tức trả về false.

Nói cách khác, bạn có thể làm một cái gì đó phức tạp như thế này ( liên kết đến JSFiddle ):

[1, 2, 3, 4].every(function(n) {
    alert(n);
    return n !== 3;
});

Điều này sẽ cảnh báo 1thông qua 3, và sau đó "thoát" khỏi vòng lặp.

Bạn đang sử dụng underscore.js, vì vậy bạn sẽ được hài lòng khi biết rằng nó không cung cấp một everyphương pháp-họ gọi nó every, nhưng khi liên kết đề cập đến, họ cũng cung cấp một bí danh gọi all.


2
Underscore.js có cung cấp triển khai cho việc này không?
Felix Kling

1
@FelixKling, đúng vậy. Tôi đã thêm nó vào câu trả lời của tôi.
aeskr

2
ngay bây giờ (05/2013), không có _.every()một _.all()phương thức nào cho các mảng trong gạch dưới - vì vậy hãy bám vào Array.every().
pkyeck

3
Điều này sẽ hoạt động, nhưng đó là một lý do thông thường để sử dụng every. Vì vậy, xem ra cho dễ đọc.
evanrmurphy

3
Các tài liệu gạch dưới _.each()có một lưu ý cụ thể về thực tế là bạn không thể thoát ra khỏi vòng lặp và khuyên bạn nên sử dụng _.find()thay thế. http://underscorejs.org/#each
blatt

70

Cập nhật:

_.find sẽ tốt hơn khi nó thoát ra khỏi vòng lặp khi tìm thấy phần tử:

var searchArr = [{id:1,text:"foo"},{id:2,text:"bar"}];
var count = 0;
var filteredEl = _.find(searchArr,function(arrEl){ 
              count = count +1;
              if(arrEl.id === 1 ){
                  return arrEl;
              }
            });

console.log(filteredEl);
//since we are searching the first element in the array, the count will be one
console.log(count);
//output: filteredEl : {id:1,text:"foo"} , count: 1

** Cũ **

Nếu bạn muốn thoát ra khỏi vòng lặp một cách có điều kiện, hãy sử dụng api _.filter thay vì _.each. Đây là một đoạn mã

var searchArr = [{id:1,text:"foo"},{id:2,text:"bar"}];
var filteredEl = _.filter(searchArr,function(arrEl){ 
                  if(arrEl.id === 1 ){
                      return arrEl;
                  }
                });
console.log(filteredEl);
//output: {id:1,text:"foo"}

1
Điều này không phá vỡ vòng lặp - nó chỉ lọc các mảng. hãy tưởng tượng bạn không có 2 nhưng 20.000 mục trong mảng. bạn đăng nhập sẽ chỉ xuất ra ví dụ bạn đã đăng nhưng vòng lặp sẽ chạy 20.000 lần :(
pkyeck

@pkyeck bạn là đúng, có thể _.find là tốt hơn so với _.filter như nó phá vỡ sau khi elemnt được tìm thấy, đây là fiddle: jsfiddle.net/niki4810/9K3EV
Nikhil

2
Tôi nghĩ rằng câu trả lời này nên được đánh dấu là đúng. _.findthực hiện chính xác những gì được yêu cầu: lặp qua danh sách cho đến khi gọi lại true.
Fabien Quatravaux

Bỏ phiếu cho câu trả lời này vì câu trả lời được chấp nhận (Array.every) sẽ không hoạt động trên các đối tượng, nhưng _.find () sẽ.
matt

Và đó là những gì được khuyến nghị trong các tài liệu: Thật tốt khi lưu ý rằng mỗi vòng lặp không thể bị phá vỡ - để phá vỡ, hãy sử dụng _.find thay thế.
shaharsol

15

Bạn có thể có một cái nhìn để _.somethay vì _.each. _.somedừng duyệt qua danh sách một khi vị ngữ là đúng. Kết quả có thể được lưu trữ trong một biến ngoài.

_.some([1, 2, 3], function(v) {
    if (v == 2) return true;
})

Xem http://underscorejs.org/#some



3

Có thể bạn muốn Underscore bất kỳ () hoặc find (), sẽ dừng xử lý khi một điều kiện được đáp ứng.



3

Bạn không thể phá vỡ forEachdấu gạch dưới, vì nó mô phỏng hành vi gốc EcmaScript 5.


2

Tôi tin rằng nếu mảng của bạn thực sự là một đối tượng bạn có thể trả về bằng cách sử dụng một đối tượng trống.

_.({1,2,3,4,5}).each(function(v){  
  if(v===3) return {}; 
});

Điều đó chỉ xảy ra với EcmaScript v <5 vì sự so sánh mà gạch dưới thực hiện để kiểm tra xem bạn có trả lại đối tượng trống trong giải pháp thay thế được cung cấp cho forEach chỉ được thực hiện khi không có sẵn bản gốc.
Alfonso de la Osa


1

Cập nhật:

Bạn thực sự có thể "phá vỡ" bằng cách ném một lỗi bên trong và bắt nó bên ngoài: một cái gì đó như thế này:

try{
  _([1,2,3]).each(function(v){
    if (v==2) throw new Error('break');
  });
}catch(e){
  if(e.message === 'break'){
    //break successful
  }
}

Điều này rõ ràng có một số hàm ý liên quan đến bất kỳ trường hợp ngoại lệ nào khác mà mã của bạn kích hoạt trong vòng lặp, vì vậy hãy thận trọng khi sử dụng!


Yêu làm thế nào tôi nhận được rất nhiều phiếu bầu cho điều này và anh chàng này nhận được toàn bộ số lượt tải lên cho stackoverflow.com/a/2641374/674720
bm_i

1
Tôi đến bữa tiệc muộn nhưng lưu ý rằng anh chàng không chỉ nói những gì bạn đề nghị, mà còn đưa ra hai lựa chọn khác (và phù hợp hơn). Việc duy nhất cung cấp "hack" trong trường hợp người dùng bằng mọi cách muốn nó. Thay vào đó bạn chỉ cung cấp các hack xấu xí.
Areks

0

làm việc trong trường hợp của tôi

var arr2 = _.filter(arr, function(item){
    if ( item == 3 ) return item;
});
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.