Mam tablicę utworzoną za pomocą tego kodu:
var widthRange = new Array();
widthRange[46] = { min:0, max:52 };
widthRange[66] = { min:52, max:70 };
widthRange[90] = { min:70, max:94 };
Chcę uzyskać każdą z wartości 46, 66, 90 w pętli. Próbowałem, for (var key in widthRange)
ale to daje mi całą masę dodatkowych właściwości (zakładam, że są to funkcje na obiekcie). Nie mogę użyć zwykłej pętli for, ponieważ wartości nie są sekwencyjne.
javascript
arrays
key
Niezadowolony Kozioł
źródło
źródło
Array.prototype.forEach
. WywołanieObject.keys
tablicy nie działa, ponieważ przeglądarki nie optymalizują jej pod kątem.for(var key in array)
jest zły, ponieważ przechodzi przez prototyp i określa łańcuchy każdego napotkanego klucza liczbowego (konwersja podwójnych liczb do base10 jest bardzo powolna).forEach
jednak został zaprojektowany dokładnie w celu iteracji rzadkich tablic i zapewni Twojemu kodowi doskonałą wydajność w porównaniu z innymi rozwiązaniamiOdpowiedzi:
Musisz wywołać
hasOwnProperty
funkcję, aby sprawdzić, czy właściwość jest faktycznie zdefiniowana na samym obiekcie (w przeciwieństwie do jego prototypu), na przykład:for (var key in widthRange) { if (key === 'length' || !widthRange.hasOwnProperty(key)) continue; var value = widthRange[key]; }
Pamiętaj, że potrzebujesz osobnego czeku na
length
.Jednak w ogóle nie powinieneś używać tutaj tablicy; powinieneś użyć zwykłego przedmiotu. Wszystkie obiekty JavaScript działają jako tablice asocjacyjne.
Na przykład:
var widthRange = { }; //Or new Object() widthRange[46] = { sel:46, min:0, max:52 }; widthRange[66] = { sel:66, min:52, max:70 }; widthRange[90] = { sel:90, min:70, max:94 };
źródło
length
? Czy nie jest zaznaczone tak, jak[[DontEnum]]
we wszystkich przeglądarkach?Można zapytać o klucze strunowe
Object.keys(array)
.źródło
array.keys()
nic nie zwróciło.Jeśli wykonujesz jakąkolwiek operację lub kontrolę tablicy / kolekcji, bardzo polecam użycie Underscore.js . Jest mały, dobrze przetestowany i pozwoli Ci zaoszczędzić dni / tygodnie / lata bólu głowy w języku JavaScript. Oto jego funkcja klawiszy:
Klucze
Pobierz wszystkie nazwy właściwości obiektu.
_.keys({one : 1, two : 2, three : 3}); => ["one", "two", "three"]
źródło
Powiedz, że twoja tablica wygląda jak
arr = [ { a: 1, b: 2, c: 3 }, { a: 4, b: 5, c: 6 }, { a: 7, b: 8, c: 9 } ]
(lub prawdopodobnie inne klucze), które możesz zrobićarr.map((o) => { return Object.keys(o) }).reduce((prev, curr) => { return prev.concat(curr) }).filter((col, i, array) => { return array.indexOf(col) === i });
["a", "b", "c"]
źródło
for (var i = 0; i < widthRange.length; ++i) { if (widthRange[i] != null) { // do something } }
Tak naprawdę nie możesz uzyskać tylko ustawionych kluczy, ponieważ nie tak działa tablica. Po ustawieniu elementu 46 masz również ustawione od 0 do 45 (chociaż są one zerowe).Zawsze możesz mieć dwie tablice:
var widthRange = [], widths = [], newVal = function(n) { widths.push(n); return n; }; widthRange[newVal(26)] = { whatever: "hello there" }; for (var i = 0; i < widths.length; ++i) { doSomething(widthRange[widths[i]]); }
edytuj dobrze, może być tak, że jestem tu cała mokra
źródło
widthRange.map(function(_, i) { return i });
lub
widthRange.map((_, i) => i);
źródło
Twój oryginalny przykład działa dobrze dla mnie:
<html> <head> </head> <body> <script> var widthRange = new Array(); widthRange[46] = { sel:46, min:0, max:52 }; widthRange[66] = { sel:66, min:52, max:70 }; widthRange[90] = { sel:90, min:70, max:94 }; var i = 1; for (var key in widthRange) { document.write("Key #" + i + " = " + key + "; min/max = " + widthRange[key].min + "/" + widthRange[key].max + "<br />"); i++; } </script> </html>
Wyniki w przeglądarce (Firefox 3.6.2 w systemie Windows XP):
Key #1 = 46; min/max = 0/52 Key #2 = 66; min/max = 52/70 Key #3 = 90; min/max = 70/94
źródło
Myślę, że powinieneś użyć Object (
{}
), a nie tablicy ([]
).Z każdym kluczem powiązany jest zestaw danych. Krzyczy za użycie przedmiotu. Zrobić:
var obj = {}; obj[46] = { sel:46, min:0, max:52 }; obj[666] = { whatever:true }; // This is what for..in is for for (var prop in obj) { console.log(obj[prop]); }
Może takie narzędzia mogą pomóc:
window.WidthRange = (function () { var obj = {}; return { getObj: function () {return obj;} , add: function (key, data) { obj[key] = data; return this; // enabling chaining } } })(); // Usage (using chaining calls): WidthRange.add(66, {foo: true}) .add(67, {bar: false}) .add(69, {baz: 'maybe', bork:'absolutely'}); var obj = WidthRange.getObj(); for (var prop in obj) { console.log(obj[prop]); }
źródło
Wydaje się działać.
var widthRange = new Array(); widthRange[46] = { sel:46, min:0, max:52 }; widthRange[66] = { sel:66, min:52, max:70 }; widthRange[90] = { sel:90, min:70, max:94 }; for (var key in widthRange) { document.write(widthRange[key].sel + "<br />"); document.write(widthRange[key].min + "<br />"); document.write(widthRange[key].max + "<br />"); }
źródło
Napisałem funkcję, która działa dobrze z każdą instancją obiektów (to są tablice).
Object.prototype.toArray = function() { if(!this) { return null; } var c = []; for (var key in this) { if ( ( this instanceof Array && this.constructor === Array && key === 'length' ) || !this.hasOwnProperty(key) ) { continue; } c.push(this[key]); } return c; };
Stosowanie:
var a = [ 1, 2, 3 ]; a[11] = 4; a["js"] = 5; console.log(a.toArray()); var b = { one: 1, two: 2, three: 3, f: function() { return 4; }, five: 5 }; b[7] = 7; console.log(b.toArray());
Wynik:
> [ 1, 2, 3, 4, 5 ] > [ 7, 1, 2, 3, function () { return 4; }, 5 ]
Może się przydać każdemu.
źródło
... ????
Alternatywnie, jeśli masz listę przedmiotów, których chcesz użyć ...
var range = [46, 66, 90] , widthRange=[] , write=[]; widthRange[46] = { min:0, max:52 }; widthRange[66] = { min:52, max:70 }; widthRange[90] = { min:70, max:94 }; for(var x=0; x<range.length; x++){var key, wr; key = range[x]; wr = widthRange[key] || false; if(wr===false){continue;} write.push(['key: #',key, ', min: ', wr.min, 'max:', wr.max].join('')); }
źródło
Twoje dane wejściowe:
let widthRange = new Array() widthRange[46] = { min:0, max:52 } widthRange[61] = { min:52, max:70 } widthRange[62] = { min:52, max:70 } widthRange[63] = { min:52, max:70 } widthRange[66] = { min:52, max:70 } widthRange[90] = { min:70, max:94 }
Podejście deklaratywne:
const relevantKeys = [46,66,90] const relevantValues = Object.keys(widthRange) .filter(index => relevantKeys.includes(parseInt(index))) .map(relevantIndex => widthRange[relevantIndex])
Object.keys
aby zdobyć klucze, używając,parseInt
aby rzucić je jako liczby.filter
dostać tylko te, które chcesz.map
aby zbudować tablicę z oryginalnego obiektu tylko indeksów, których szukasz, ponieważObject.keys
traci wartości obiektu.Odpluskwić:
console.log(widthRange) console.log(relevantKeys) console.log(relevantValues)
źródło
Pytanie jest dość stare, ale obecnie możesz użyć forEach, który jest wydajny i zachowuje klucze jako liczby:
let keys = widthRange.map((v,k) => k).filter(i=>i!==undefined))
Ta pętla przechodzi przez widthRange i tworzy nową tablicę z wartościami kluczy, a następnie odfiltrowuje wszystkie rzadkie szczeliny, biorąc tylko wartości, które są zdefiniowane.
(Zły pomysł, ale ze względu na wytrzymałość: jeśli slot 0 był zawsze pusty, można to skrócić do
filter(i=>i)
lubfilter(Boolean)
I może być mniej wydajne, ale liczby można rzucać za pomocą
let keys = Object.keys(array).map(i=>i*1)
źródło