2013-05-31 16 views
8

Filtrowałem tablicę i znalazłem tutaj wyrażenie regularne. Próbuję to zrozumieć:Czy ktoś może wytłumaczyć to filtrowanie wyrażeń regularnych z tablicy

filterArray.filter(/./.test.bind(new RegExp(key, 'g'))) 

Ale ja nie rozumiem, jak to testy array cenią przeciwko regex lub dlaczego trzeba zacząć /./ zamiast tylko pisać regex. A jak działa bind w tym przypadku?

EDYCJA: Klucz jest po prostu ciągiem, który chcę dopasować, "cześć" lub "pies" lub "cokolwiek naprawdę".

+2

Jeśli dasz nam zmienną 'key' to tak. –

+0

@DavidStarkey Proszę zobaczyć moją edycję. – ptf

+0

Zobacz https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind –

Odpowiedz

14

Metoda zwróci funkcję, która została przekazana jako pierwszy argument związany jako wartość this.

Od dzwonisz .bind() z .test(), dostajesz metodę .test() z this związany new RegExp(key, 'g').

W tym przypadku oznaczenie /./ jest nieistotne. To tylko krótki sposób na uzyskanie metody RegExp.prototype.test.

Rezultatem jest to, że będziesz efektywnie robić:

var regexp = new RegExp(key, 'g'); 

filterArray.filter(function(val) { 
    return regexp.test(val); 
}); 

Należy pamiętać, że jest to trochę niebezpieczne, ponieważ obiekt regex z modyfikatorem g jest stanowe. Oznacza to, że zawsze rozpoczyna nowe wyszukiwanie, w którym poprzednie zostało przerwane.

Biorąc pod uwagę ten scenariusz filtrowania, g nie wydaje się być konieczne i może tylko powodować problemy.

Oto przykład o niebezpieczeństwie za pomocą g tutaj:

var re = /./.test.bind(new RegExp("foo", 'g')); 
var str = "foobar"; 

console.log(re(str)); // true 
console.log(re(str)); // false 

Więc wywołanie samego regex na ten sam ciąg produkuje dwa różne wyniki. Gdybyśmy zadzwonili ponownie, znów byłoby true.


Więc biorąc pod uwagę zastosowanie jako .filter() zwrotnego, powiedzmy key jest "foo", to powiedzmy, że jeden val jest "foobar". Będzie dozwolone przez filtr.

Ale powiedzmy, że następny val to "foobaz". Wyszukiwanie zostanie wznowione na czwartym znaku, zamiast zaczynać od pierwszego, więc "foo" nie zostanie znaleziony.


Oto konkretny przykład, który pokazuje problem w działaniu:

DEMO:http://jsfiddle.net/s9PzL/

var filterArray = [ 
    "foobar", 
    "foobaz", 
    "foobuz", 
    "foobix" 
]; 

var result = filterArray.filter(/./.test.bind(new RegExp("foo", 'g'))); 

Wszystkie struny mają "foo", więc wszyscy powinni dotrzeć. Ale wynik pokazuje, że tak się nie dzieje.

document.body.textContent = result.join(", "); // foobar, foobuz 
+0

Dzięki za informacje o tym, jak zrobić to globalnie. A rezultat tego, co skutecznie robiłem, pomógł. – ptf

+0

Nie ma za co. –

+0

Kiedy powiesz, że wyszukiwanie wznawia się na 4 znaku, masz na myśli 4. znak następnego elementu w tablicy, prawda? – ptf

6

Myślę, że powodem tego jest to, ponieważ chcesz wykonać metodę testową na każdym elemencie w tablicy. Samo podanie metody testowej do filtrowania spowoduje (prawdopodobnie) zepsucie wiązania metody.

Dlatego w swojej przykład:

/./ 

Generuje pusty regex

/./.test 

jest metoda badania na tym regex

/./.test.bind(new Regex(..)) 

wiąże metoda do żądanej metody, i zwraca nową metodę, która wykonuje test gdzie this jest dostarczonym regex na podstawie key.

Wydaje się, że może to zostały napisane dużo bardziej jasne:

RegExp.prototype.test.bind(new RegExp(key, 'g')) 
+0

Mogę tylko zgadywać, że autor jest zbyt sprytny, aby wpisać 13 dodatkowych znaków. – deerchao

+0

Rzeczywiście jest :) –

Powiązane problemy