Ukryte funkcje JavaScript? [Zamknięte]

312

Jak myślisz, jakie „ukryte funkcje” JavaScript powinien wiedzieć każdy programista?

Po obejrzeniu doskonałej jakości odpowiedzi na następujące pytania pomyślałem, że nadszedł czas, aby poprosić o JavaScript.

Mimo że JavaScript jest obecnie prawdopodobnie najważniejszym językiem po stronie klienta (wystarczy zapytać Google), zaskakujące jest to, jak mało twórców stron internetowych docenia jego moc.

Binoj Antony
źródło
1
Czy nie miałeś na myśli „Widząc opinie przedstawicieli i opinie, które przyciągnęły to inne pytanie, pomyślałem, że zadam prawie dokładnie to samo pytanie, aby podnieść moje własne”? ;-)
Bobby Jack
1
Jasne, pesymista. :) Zastanawiałem się nad tym, aby zadać to pytanie społeczności. Ponadto, po zdobyciu określonej liczby punktów wszystko maleje.
Allain Lalonde
1
W porządku - nie wygląda to tak, jakbyś „potrzebował” przedstawiciela! Wydaje mi się, że mam po prostu duży problem z C # one - nie wydaje mi się, że jest to rodzaj pytania, dla którego ta strona była przeznaczona.
Bobby Jack
3
Tak, może nie, ale wiedza znalazła się w odpowiedziach. Myślę, że trudno byłoby wystawić przeciętnego programistę C # na to wszystko w jednym miejscu, gdyby nie SO. Wymyślenie tej samej ciężko wygranej listy zajęłoby lata.
Allain Lalonde
7
JavaScript piszę profesjonalnie od 10 lat i nauczyłem się czegoś z tego wątku. Dzięki, Alan!
Andrew Hedges,

Odpowiedzi:

373

Nie musisz definiować żadnych parametrów dla funkcji. Możesz po prostu użyć argumentsobiektu podobnego do tablicy funkcji .

function sum() {
    var retval = 0;
    for (var i = 0, len = arguments.length; i < len; ++i) {
        retval += arguments[i];
    }
    return retval;
}

sum(1, 2, 3) // returns 6
Mark Cidade
źródło
117
Warto jednak zauważyć, że chociaż argumenty działają jak tablica, nie jest to prawdziwa tablica javascript - to tylko obiekt. Nie możesz więc łączyć (), pop (), push (), slice () i tak dalej. (Możesz przekonwertować go na prawdziwą tablicę, jeśli chcesz: "var argArray = Array.prototype.slice.call (arguments);")
Jacob Mattison
51
Warto również zauważyć, że dostęp do obiektu Arguments jest stosunkowo drogi - najlepsze przykłady są w nocnych przeglądarkach Safari, Firefox i Chrome, gdzie samo odwołanie do argumentsobiektu znacznie spowalnia wywoływanie funkcji - np. argumenty if (false); zaszkodzi perf.
olliej
48
W tym samym duchu argumenty mają właściwość „callee”, która jest samą bieżącą funkcją. Pozwala to na rekurencję z anonimowymi funkcjami, super!
Vincent Robert
4
@Nathan „f (x, y, z)” wygląda lepiej niż „f ([x, y, z])”.
Mark Cidade
16
@Vincent Robert: pamiętaj, że arguments.calleejest on przestarzały.
Ken
204

Mógłbym zacytować większość doskonałej książki Douglasa Crockforda JavaScript: The Good Parts .

Ale wezmę tylko jeden, zawsze używaj ===i !==zamiast ==i!=

alert('' == '0'); //false
alert(0 == ''); // true
alert(0 =='0'); // true

==nie jest przechodni. Jeśli ===go użyjesz , wartość false dla wszystkich tych oświadczeń będzie zgodna z oczekiwaniami.

Martin Clarke
źródło
29
Szkoda, że ​​tak wielu ludzi uważa, że ​​Crockford jest wszechwiedzący. To prawda, że ​​facet ma rację, gdy krytykuje większość, ale przestaję udzielać jego rzeczom ogólnego poparcia, tak jak robi to wielu deweloperów ...
Jason Bunting
21
Popieram ostrzeżenie Jasona. Książka sama w sobie jest bardzo ciekawe, a to daje dużo dobrych rad, ale DC jest zdecydowanie zbyt przekonany, że jego sposób robienia rzeczy jest to jedyny właściwy sposób, wszystko jest „wadliwy”. Jeśli chcesz przykłady, spójrz na jego odpowiedzi w JSLint Yahoo Group.
Zilk,
30
Użyj === zamiast == to dobra rada, jeśli nie rozumiesz dynamicznego pisania i po prostu chcesz, aby było „naprawdę” równe. Ci z nas, którzy rozumieją dynamiczne pisanie, mogą nadal używać == w sytuacjach, w których wiemy, że chcemy rzucać, jak w 0 == '' lub 0 == '0'.
thomasrutter
20
Cóż, == i === nie dotyczą dynamicznego pisania. == robi typowanie, które jest inną bestią. Jeśli wiesz, że chcesz rzutować na string / number / etc, to musisz to zrobić jawnie.
Rene Saarsoo
15
Myślę, że najbardziej przerażającą częścią ==jest '\n\t\r ' == 0=> true...: D
Shrikant Sharat
189

Funkcje są pierwszorzędnymi obywatelami w JavaScript:

var passFunAndApply = function (fn,x,y,z) { return fn(x,y,z); };

var sum = function(x,y,z) {
  return x+y+z;
};

alert( passFunAndApply(sum,3,4,5) ); // 12

Funkcjonalne techniki programowania można wykorzystać do pisania eleganckiego javascript .

W szczególności funkcje mogą być przekazywane jako parametry, np. Array.filter () akceptuje wywołanie zwrotne:

[1, 2, -1].filter(function(element, index, array) { return element > 0 });
// -> [1,2]

Możesz także zadeklarować funkcję „prywatną”, która istnieje tylko w zakresie określonej funkcji:

function PrintName() {
    var privateFunction = function() { return "Steve"; };
    return privateFunction();
}
Gulzar Nazim
źródło
3
Istnieją trzy sposoby tworzenia funkcji w javascript: funkcja sum (x, y, z) {return (x + y + z); } i var sum = nowa funkcja („x”, „y”, „z”, „return (x + y + z);”); są inne sposoby.
Marius
6
Pojęcie funkcji jako danych zdecydowanie zdobywa duże punkty w mojej książce.
Jason Bunting
Właśnie zaktualizowałem próbkę, aby pokazać, jak korzystać z funkcji „prywatnej”, która istnieje tylko w zakresie określonej funkcji.
Chris Pietschmann
new Function()jest tak samo zły jak eval. Nie używać.
Nicolás,
11
nie jestem pewien, czy jest to funkcja ukryta ... bardziej jak funkcja podstawowa.
Claudiu
162

Możesz użyć w operatora , aby sprawdzić, czy w obiekcie istnieje klucz:

var x = 1;
var y = 3;
var list = {0:0, 1:0, 2:0};
x in list; //true
y in list; //false
1 in list; //true
y in {3:0, 4:0, 5:0}; //true

Jeśli okaże się, że literały obiektów są zbyt brzydkie, możesz połączyć je z bezparametrową wskazówką funkcji:

function list()
 { var x = {};
   for(var i=0; i < arguments.length; ++i) x[arguments[i]] = 0;
   return x
 }

 5 in list(1,2,3,4,5) //true
Mark Cidade
źródło
22
Nie tak sprytny, że sprawdza, czy klucz jest obecny, a nie, czy wartość jest. x na liście; działa tylko dlatego, że x [1]! = null, a nie dlatego, że istnieje wartość 1.
Armin Ronacher
1
Nie korzystałem z tej techniki ina, więc zapomniałem, że faktycznie używałem literałów obiektowych wcześniej. Dziękuję za poprawienie mnie.
Mark Cidade
34
Bądź też ostrożny: operator in testuje również łańcuch prototypowy! Jeśli ktoś umieścił właściwość o nazwie „5” na Object.prototype, drugi przykład zwróciłby prawdę, nawet jeśli nazwiesz „5 na liście (1, 2, 3, 4)” ... Lepiej użyj hasOwnProperty Metoda: list (1, 2, 3, 4). hasOwnProperty (5) zwróci false, nawet jeśli Object.prototype ma właściwość „5”.
Martijn
3
W przypadku najbardziej ogólnego rozwiązania, które może przetestować, czy obiekt ma własną właściwość, nawet jeśli ma nazwę „hasOwnProperty”, musisz przejść do: Object.prototype.hasOwnProperty.call (obiekt, nazwa) ;
Kris Kowal
1
@Kris, chyba że ktoś nadpisze Object.prototype.hasOwnProperty;)
Nick
153

Przypisywanie wartości domyślnych do zmiennych

Możesz użyć logicznego lub operatora ||w wyrażeniu przypisania, aby podać wartość domyślną:

var a = b || c;

aZmienna będzie wartość ctylko wtedy, gdy bjest falsy (jeśli jest null, false, undefined, 0, empty string, lub NaN), w przeciwnym razie abędzie uzyskać wartość b.

Jest to często przydatne w funkcjach, gdy chcesz nadać argumentowi domyślną wartość, jeśli nie zostanie podany:

function example(arg1) {
  arg1 || (arg1 = 'default value');
}

Przykład powrotu do IE w procedurach obsługi zdarzeń:

function onClick(e) {
    e || (e = window.event);
}

Następujące funkcje językowe są z nami od dawna, wszystkie implementacje JavaScript obsługują je, ale nie były częścią specyfikacji, dopóki ECMAScript 5. edycja :

debuggeroświadczenie

Opisane w: § 12.15 Oświadczenie debuggera

Ta instrukcja pozwala programowo wstawiać punkty przerwania w kodzie tylko przez:

// ...
debugger;
// ...

Jeśli debugger jest obecny lub aktywny, spowoduje to jego natychmiastowe przerwanie, bezpośrednio na tej linii.

W przeciwnym razie, jeśli debugger nie jest obecny lub aktywny, to instrukcja nie ma zauważalnego wpływu.

Wieloliniowe literały łańcuchowe

Opisane w: § 7.8.4 Literałów ciągowych

var str = "This is a \
really, really \
long line!";

Musisz być ostrożny, ponieważ znak obok znaku \ musi być zakończeniem linii, jeśli \na przykład po spacji masz kod, kod będzie wyglądał dokładnie tak samo, ale podniesie go SyntaxError.

CMS
źródło
28
Nie, jeśli ma wartość zero, jeśli jest uważane za fałszywe. a = 0 || 42; da ci 42. Jest to porównywalne z Pythona, a nie C #? operator. Jeśli chcesz zachowanie C #, czy a = (b === null)? c: b;
Armin Ronacher
Działa również w Visual Studio, jeśli tworzysz na ASP.NET :)
chakrit
2
Chciałbym, żeby było właściwe || tylko dla nieokreślonego. Ugryzło mnie to dzisiaj za 0, ponieważ chciałem stworzyć emulację przeciążonej metody, tak aby ostatni argument był opcjonalny i zamiast tego użyto wartości domyślnej.
egaga
+1 tej sztuczki jest używany przez domyślny fragment kodu Google Analytics. `var _gaq = _gaq || []; `; zapobiega nadmiernemu nadpisywaniu własnej pracy przez nadgorliwych użytkowników.
Yahel
2
Nie wiedziałem o dosłownej technice wieloliniowej. To fantastycznie, dzięki.
Charlie Flowers
145

JavaScript nie ma zasięgu blokowego (ale ma zamknięcie, więc nazwijmy go nawet?).

var x = 1;
{
   var x = 2;
}
alert(x); // outputs 2
Eugene Yokota
źródło
3
To jest dobre. To naprawdę ważna różnica od większości języków podobnych do C.
Martin Clarke,
9
Zawsze możesz zrobić „var tmp = function () {/ * block scope * /} ();”. Składnia jest brzydka, ale działa.
Joeri Sebrechts
3
Możesz też użyć „let”, jeśli jest to tylko Firefox: stackoverflow.com/questions/61088/…
Eugene Yokota
10
lub po prostu: (function () {var x = 2;}) (); alert (typeof x); // niezdefiniowany
Pim Jager
@Pim: JSLint mówi: „Przenieś wywołanie do parens zawierających funkcję.”. Wraz z „Oczekiwano dokładnie jednej spacji między„ funkcją ”a„ („.”.
Hello71,
144

Możesz uzyskać dostęp do właściwości obiektu za pomocą []zamiast.

Pozwala to wyszukać właściwość pasującą do zmiennej.

obj = {a:"test"};
var propname = "a";
var b = obj[propname];  // "test"

Można go również użyć do uzyskania / ustawienia właściwości obiektu, których nazwa nie jest prawnym identyfikatorem.

obj["class"] = "test";  // class is a reserved word; obj.class would be illegal.
obj["two words"] = "test2"; // using dot operator not possible with the space.

Niektórzy nie wiedzą o tym i używają eval () w ten sposób, co jest naprawdę złym pomysłem :

var propname = "a";
var a = eval("obj." + propname);

Jest to trudniejsze do odczytania, trudniejsze do znalezienia błędów (nie można użyć jslinta), wolniejsze do wykonania i może prowadzić do exploitów XSS.

Patrick
źródło
eval jest zły, choć rzadko konieczny
Doug Domeny
Nigdy nie używam eval i pamiętam, kiedy to odkryłem. Bardzo mnie to ucieszyło.
Podsumowując, do właściwości obiektu można uzyskać dostęp zarówno poprzez zapis kropkowy, jak i indeks dolny
Russ Cam
9
Warto zauważyć, że odnośniki kropkowe to tak naprawdę cukier składniowy dla brackref. foo.bar, zgodnie ze specyfikacją zachowuje się tak samo foo["bar"]. zauważ również, że wszystko jest właściwością łańcucha. nawet gdy masz dostęp do tablicy, array[4]4 jest konwertowane na ciąg znaków (ponownie, przynajmniej zgodnie ze specyfikacją ECMAScript v3)
Claudiu
Chyba każdy programista JS powinien to wiedzieć.
Cem Kalyoncu,
144

Jeśli korzystasz z Googling w poszukiwaniu porządnego odwołania do JavaScript w danym temacie, dołącz słowo kluczowe „mdc” do zapytania, a pierwsze wyniki będą pochodzić z Centrum deweloperów Mozilla. Nie noszę ze sobą żadnych odniesień ani książek offline. Zawsze używam sztuczki „mdc”, aby bezpośrednio dostać się do tego, czego szukam. Na przykład:

Google: javascript array sort mdc
(w większości przypadków możesz pominąć „javascript”)

Aktualizacja: Mozilla Developer Center została przemianowana na Mozilla Developer Network . Sztuczka słów kluczowych „mdc” nadal działa, ale wkrótce będziemy musieli zacząć korzystać z „mdn” .

Ates Goral
źródło
50
Wow, świetny zasób. Natychmiast lepszy niż gówniana w3schools ...
DisgruntledGoat
11
Nie musisz go nawet Google, jeśli używasz przeglądarki Firefox: po prostu wpisz „array mdc” w pasku adresu i naciśnij Enter.
Sasha Chedygov
2
najlepsze jest to, że pytanie o przepełnienie stosu znajduje się na pierwszej stronie wyników :)
Jiaaro
5
Propo to: promotejs.com , oddolna inicjatywa SEO, która ma na celu zwiększenie wyników MDC w wynikach wyszukiwania Google.
Yahel,
3
Teraz jest centrum dokumentacji MDN, więc słowo kluczowe „mdc” jest nadal aktualne :)
Aleadam
143

Może to trochę oczywiste dla niektórych ...

Zainstaluj Firebug i użyj console.log („cześć”). O wiele lepsze niż używanie random alert ();, które pamiętam wiele lat temu.

qui
źródło
12
Po prostu nie zapomnij usunąć instrukcji konsoli przed udostępnieniem kodu innym osobom, które mogą nie mieć zainstalowanego Firebuga.
Chris Noe,
161
log funkcji (msg) {if (console) console.log (msg) else alert (msg)}
Josh
4
Jeszcze lepiej, poprzedzaj instrukcje dziennika znakiem „;;;” a następnie minify dba o to za Ciebie. (Przynajmniej moduł Perla, którego używam, ma tę funkcję i twierdzi, że jest powszechny.)
Kev,
10
Josh: To nie zadziała, ponieważ konsola nie jest zdefiniowana. Możesz sprawdzić typeof console! == "undefined" lub window.console.
Eli Gray,
23
Zawsze dołączaj: if (typeof ('console') == 'undefined') {console = {log: function () {}}; }, możesz nadal korzystać z pliku console.log i nic nie robi.
gregmac
120

Metody prywatne

Obiekt może mieć metody prywatne.

function Person(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;

    // A private method only visible from within this constructor
    function calcFullName() {
       return firstName + " " + lastName;    
    }

    // A public method available to everyone
    this.sayHello = function () {
        alert(calcFullName());
    }
}

//Usage:
var person1 = new Person("Bob", "Loblaw");
person1.sayHello();

// This fails since the method is not visible from this scope
alert(person1.calcFullName());
Allain Lalonde
źródło
16
To nie jest tak naprawdę funkcja prywatna - jest to raczej zmienna funkcyjna w zasięgu lokalnym.
Keith,
6
To prawda, ale według wszystkich definicji operacyjnych mogę wymyślić, że jest to metoda. Jest to blok kodu o nazwie, która ma dostęp do stanu instancji i jest widoczna tylko dla tej instancji. Jaka jest twoja definicja metody prywatnej?
Allain Lalonde,
14
@Zach, dokładnie! Po latach pracy z klasowymi językami OO łatwo jest zapomnieć, że są one tylko jedną implementacją koncepcji OO. Oczywiście różne biblioteki, które próbują
wtłoczyć
5
Zastanawiam się, czy osoba1 ma blog prawniczy? ;-)
travis
4
+1 za odniesienie do aresztowanego rozwoju
Domenic
99

Wspomniany również w „Javascript: The Good Parts” Crockforda:

parseInt()jest niebezpieczny. Jeśli przekażesz ciąg bez informowania go o właściwej podstawie, może zwrócić nieoczekiwane liczby. Na przykład parseInt('010')zwraca 8, a nie 10. Przekazywanie bazy do analizy składni powoduje, że działa ona poprawnie:

parseInt('010') // returns 8! (in FF3)
parseInt('010', 10); // returns 10 because we've informed it which base to work with.
bluefish101
źródło
13
Podczas przeglądania kodu zawsze szukaj tego. Pomijanie „10” jest częstym błędem, który pozostaje niezauważony w większości testów.
Doug Domeny,
Wiele lat temu spaliło mnie zagadnienie radix i nigdy nie zapomniałem czegoś tak sprzecznego z intuicją. Świetna rzecz do zwrócenia uwagi, ponieważ sprawi, że będziesz się zastanawiać przez chwilę.
JamesEggers
4
Dlaczego nie użyć Math.floorlub Number? 10 === Math.floor("010"); 10 === Number("010");unosi się:42 === Math.floor("42.69"); 42.69 === Number("42.69");
tylko ktoś
1
@Infinity Jeśli nie masz jeszcze odpowiedzi, powinieneś. Nie miałem pojęcia, że ​​tak proste jest zastąpienie działania wbudowanej funkcji. Oczywiście powinno to sprawić, że przyjrzymy się bliżej wszelkim pakietom kodu, które pożyczają z innych stron. Tę nieszkodliwą parseIntfunkcję można łatwo zrobić, aby zrobić coś nie tak nieszkodliwego.
bob-the-Niszczyciel
6
@Infinity: co powiesz na przedefiniowanie fn, aby podkreślić „błąd kodowania”? __parseInt = parseInt; parseInt = function (str, base) { if (!base) throw new Error(69, "All your base belong to us"); return __parseInt(str, base); }
JBRWilkinson
97

Funkcje są obiektami i dlatego mogą mieć właściwości.

fn = funkcja (x) {
   // ...
}

fn.foo = 1;

fn.next = funkcja (y) {
  //
}
VolkerK
źródło
13
To bardzo przydatna wskazówka. Na przykład można ustawić wartości domyślne jako właściwość funkcji. Na przykład: myfunc.delay = 100; Następnie użytkownicy mogą zmienić wartość domyślną, a wszystkie wywołania funkcji będą używać nowej wartości domyślnej. Na przykład: myfunc.delay = 200; myfunc ();
BarelyFitz
Przydatne ... i niebezpieczne!
palswim
Wygląda niechlujnie, dlaczego warto używać tego zamiast zmiennej?
instantsetsuna
1
@instantsetsuna: Dlaczego inna osobna zmienna? Jak zwykle sprowadza się to do „użycia, gdy jest to właściwe / przydatne” ;-)
VolkerK
91

Musiałbym powiedzieć, że funkcje wykonujące się same.

(function() { alert("hi there");})();

Ponieważ JavaScript nie ma zasięgu blokowego , możesz użyć funkcji samowykonywającej się, jeśli chcesz zdefiniować zmienne lokalne:

(function() {
  var myvar = 2;
  alert(myvar);
})();

W tym przypadku myvarnie zakłóca ani nie zanieczyszcza zasięgu globalnego i znika po zakończeniu funkcji.

thomasrutter
źródło
2
Do czego to jest przydatne? Takie same wyniki uzyskuje się, umieszczając alert poza funkcją.
PotatoEngineer
7
Nie chodzi o alert, chodzi o zdefiniowanie i wykonanie funkcji jednocześnie. Może się zdarzyć, że ta samoczynnie wykonująca się funkcja zwróci wartość i przekaże funkcję jako parametr do innej funkcji.
ScottKoon,
5
@Paul jest dobry do enkapsulacji.
Mike Robinson
22
Jest również dobry do określania zakresu bloków.
Jim Hunziker
24
Tak, zamykam wszystkie moje .jspliki w anonimową, samoczynnie wykonującą się funkcję i dołączam do obiektu wszystko, co chcę globalnie dostępne window. Zapobiega globalnym zanieczyszczeniom przestrzeni nazw.
cdmckay
83

Dowiedz się, ile parametrów oczekuje funkcja

function add_nums(num1, num2, num3 ){
    return num1 + num2 + num3;
}
add_nums.length // 3 is the number of parameters expected.

Dowiedz się, ile parametrów odbiera funkcja

function add_many_nums(){
    return arguments.length;
}    
add_many_nums(2,1,122,12,21,89); //returns 6
rev pramodc84
źródło
23
Nigdy nie wiedziałem o pierwszej części. Miły!
mcjabberz
1
Podobnie możesz dowiedzieć się, z iloma argumentami oczekuje funkcja function.length.
Xavi
6
@Xavi, który jest pierwszą częścią odpowiedzi
pramodc84,
79

Oto kilka interesujących rzeczy:

  • Porównując NaNz niczego (nawet NaN) jest zawsze fałszywe, który zawiera ==, <i >.
  • NaN Oznacza nie liczbę, ale jeśli poprosisz o typ, faktycznie zwraca liczbę.
  • Array.sort może przyjmować funkcję komparatora i jest wywoływany przez sterownik podobny do szybkiego (zależy od implementacji).
  • Wyrażenia regularne „stałe” mogą utrzymywać stan, podobnie jak ostatnia pasująca rzecz.
  • Niektóre wersje JavaScript pozwalają na dostęp $0, $1, $2członkowie na regex.
  • nulljest niepodobne do niczego innego. Nie jest to ani obiekt, wartość logiczna, liczba, ciąg znaków ani undefined. To trochę jak „alternatywny” undefined. (Uwaga:typeof null == "object" )
  • W najbardziej oddalonym kontekście this zwraca obiekt [Global] którego w przeciwnym razie nie można nazwać.
  • Deklarowanie zmiennej za pomocą var , zamiast polegać tylko na automatycznej deklaracji zmiennej, daje środowisku wykonawczemu realną szansę na zoptymalizowanie dostępu do tej zmiennej
  • The withKonstrukt zniszczy takie optimzations
  • Nazwy zmiennych mogą zawierać znaki Unicode.
  • Wyrażenia regularne JavaScript nie są w rzeczywistości regularne. Opierają się one na wyrażeniach regularnych Perla i możliwe jest konstruowanie wyrażeń z wyprzedzeniem, których ocena zajmuje bardzo, bardzo dużo czasu.
  • Bloki można oznaczyć i wykorzystać jako cele break. Pętle mogą być oznaczone i używane jako cel continue.
  • Tablice nie są rzadkie. Ustawienie 1000-tego elementu pustej tablicy powinno być wypełnione undefined. (zależy od implementacji)
  • if (new Boolean(false)) {...} wykona {...}blok
  • Mechanizmy wyrażeń regularnych JavaScript są specyficzne dla implementacji: np. Możliwe jest pisanie „nieprzenośnych” wyrażeń regularnych.

[zaktualizowano trochę w odpowiedzi na dobre komentarze; zobacz komentarze]

David Leonard
źródło
5
null jest w rzeczywistości (specjalnym) obiektem. typeof nullzwraca „obiekt”.
Ates Goral
4
Możesz również uzyskać obiekt [Global] z dowolnego miejsca takiego: var glb = function () {return this; } ();
Zilk,
2
Obiektem globalnym w javascript w przeglądarce jest obiekt okna. Podczas wykonywania w zakresie globalnym: window.a == a;
Pim Jager
8
„Tablice nie są rzadkie” zależy od implementacji. Jeśli ustawisz wartość [1000] i spojrzysz na [999], to tak undefined, ale jest to tylko wartość domyślna, którą otrzymasz, gdy szukasz indeksu, który nie istnieje. Jeśli zaznaczyłeś [2000], to też byłoby undefined, ale to nie znaczy, że jeszcze na to przydzieliłeś pamięć. W IE8 niektóre tablice są gęste, a niektóre rzadkie, w zależności od tego, jak czuł się wówczas silnik JScript. Przeczytaj więcej tutaj: blogs.msdn.com/jscript/archive/2008/04/08/…
Chris Nielsen
2
@Ates i @SF: typeof zwraca „obiekt” dla szeregu różnych typów. Ale kiedy już wiesz, jak to działa i jakie typy identyfikują jako „obiekt”, jest co najmniej niezawodny i konsekwentny w realizacji.
thomasrutter
77

Wiem, że jestem spóźniony na imprezę, ale nie mogę uwierzyć +, że użyteczność operatora nie została wspomniana poza „konwersją czegokolwiek na liczbę”. Może tak dobrze ukryta jest funkcja?

// Quick hex to dec conversion:
+"0xFF";              // -> 255

// Get a timestamp for now, the equivalent of `new Date().getTime()`:
+new Date();

// Safer parsing than parseFloat()/parseInt()
parseInt("1,000");    // -> 1, not 1000
+"1,000";             // -> NaN, much better for testing user input
parseInt("010");      // -> 8, because of the octal literal prefix
+"010";               // -> 10, `Number()` doesn't parse octal literals 

// A use case for this would be rare, but still useful in cases
// for shortening something like if (someVar === null) someVar = 0;
+null;                // -> 0;

// Boolean to integer
+true;                // -> 1;
+false;               // -> 0;

// Other useful tidbits:
+"1e10";              // -> 10000000000
+"1e-4";              // -> 0.0001
+"-12";               // -> -12

Oczywiście możesz to wszystko zrobić za pomocą Number(), ale+ operator jest o wiele ładniejszy!

Możesz także zdefiniować numeryczną wartość zwracaną dla obiektu, zastępując valueOf()metodę prototypu . Żadna konwersja liczb wykonana na tym obiekcie nie spowoduje NaN, ale zwróci wartość valueOf()metody:

var rnd = {
    "valueOf": function () { return Math.floor(Math.random()*1000); }
};
+rnd;               // -> 442;
+rnd;               // -> 727;
+rnd;               // -> 718;
Andy E.
źródło
Możesz to zrobić po prostu 0xFFitp., Bez potrzeby +"0xFF".
nyuszika7h
9
@ Nyuszika7H: trochę brakuje ci punktu, który zmusza inne prymitywy i obiekty do liczb. Oczywiście możesz po prostu pisać 0xFF, podobnie jak możesz pisać 1zamiast +true. Sugeruję, że możesz użyć +("0x"+somevar)jako alternatywy parseInt(somevar, 16), jeśli chcesz.
Andy E
75

Metody rozszerzeń w JavaScript ” za pośrednictwem właściwości prototype.

Array.prototype.contains = function(value) {  
    for (var i = 0; i < this.length; i++) {  
        if (this[i] == value) return true;  
    }  
    return false;  
}

Spowoduje to dodanie containsmetody do wszystkich Arrayobiektów. Możesz wywołać tę metodę za pomocą tej składni

var stringArray = ["foo", "bar", "foobar"];
stringArray.contains("foobar");
łyżka 16
źródło
18
Jest to ogólnie uważane za zły pomysł, ponieważ inny kod (nie twój) może przyjmować założenia dotyczące obiektu Array.
Chris Noe,
39
Przyjmowanie założeń dotyczących obiektu Array jest ogólnie uważane za zły pomysł. :(
powiek
Uhmmmm .. dodatki do javascript 1.6? indeks? dzwonisz jakieś dzwony?
Breton
2
@Breton: To nie jest coś specyficznego dla klasy Array, to tylko przykład. Używam tego, aby rozszerzyć nową Date (). ToString (); metoda pozwalająca na użycie ciągu maski. Każdy obiekt można rozszerzyć, a wszystkie jego instancje otrzymują nową metodę.
Esteban Küber
1
@Mathias: nie chodzi o DOM.
dolmen
60

Aby poprawnie usunąć właściwość z obiektu, powinieneś usunąć właściwość zamiast po prostu ustawić ją na niezdefiniowaną :

var obj = { prop1: 42, prop2: 43 };

obj.prop2 = undefined;

for (var key in obj) {
    ...

Właściwość prop2 nadal będzie częścią iteracji. Jeśli chcesz całkowicie pozbyć się prop2 , powinieneś zamiast tego:

delete obj.prop2;

Właściwość prop2 nie będzie się już pojawiać podczas iteracji po właściwościach.

Ates Goral
źródło
3
Zauważ, że instrukcja usuwania nie jest pozbawiona dziwactw specyficznych dla przeglądarki. Na przykład nie powiedzie się to z dużym błędem, jeśli spróbujesz go w IE, a obiekt nie jest rodzimym obiektem JS (nawet podczas usuwania właściwości, którą sam dodałeś). Nie jest również przeznaczony do usuwania zmiennej, jak w przypadku usuwania myvar; ale myślę, że to działa w niektórych przeglądarkach. Kod w powyższej odpowiedzi wydaje się jednak dość bezpieczny.
thomasrutter
Nawiasem mówiąc, niezdefiniowana może być również zmienna! Spróbuj var undefined = "coś"
Johann Philipp Strathausen
57

with.

Jest rzadko używany i, szczerze mówiąc, rzadko przydatny ... Ale w ograniczonych okolicznościach ma swoje zastosowania.

Na przykład: literały obiektów są bardzo przydatne do szybkiego ustawiania właściwości nowego obiektu. Ale co, jeśli musisz zmienić połowę właściwości istniejącego obiektu?

var user = 
{
   fname: 'Rocket', 
   mname: 'Aloysus',
   lname: 'Squirrel', 
   city: 'Fresno', 
   state: 'California'
};

// ...

with (user)
{
   mname = 'J';
   city = 'Frostbite Falls';
   state = 'Minnesota';
}

Alan Storm wskazuje, że może to być nieco niebezpieczne: jeśli obiekt użyty jako kontekst nie ma przypisanej jednej z właściwości, zostanie rozwiązany w zewnętrznym zakresie, prawdopodobnie tworząc lub nadpisując zmienną globalną. Jest to szczególnie niebezpieczne, jeśli jesteś przyzwyczajony do pisania kodu do pracy z obiektami, w których właściwości z wartościami domyślnymi lub pustymi pozostają niezdefiniowane:

var user = 
{
   fname: "John",
// mname definition skipped - no middle name
   lname: "Doe"
};

with (user)
{
   mname = "Q"; // creates / modifies global variable "mname"
}

Dlatego prawdopodobnie dobrym pomysłem jest uniknięcie użycia withinstrukcji do takiego przypisania.

Zobacz także: Czy istnieją uzasadnione zastosowania wyrażenia „with” JavaScript?

Shog9
źródło
29
Należy unikać konwencjonalnej mądrości ze stwierdzeniem. Jeśli obiekt użytkownika nie miałby jednej z wymienionych właściwości, zmienna poza pseudo-zasięgiem bloku zostałaby zmodyfikowana. W ten sposób kryją się błędy. Więcej informacji na stronie yuiblog.com/blog/2006/04/11/with-statement-consanted-harmful
Alan Storm
1
Shog, obiekcje nie dotyczą zmiennych z błędami pisowni, lecz patrzenia na blok kodu i jasnego powiedzenia, co robi jakaś konkretna linia w tym bloku. Ponieważ obiekty JavaScript są tak dynamiczne, nie można z całą pewnością stwierdzić, jakie właściwości / elementy mają w danym momencie.
Alan Storm
2
Amen - gdybym zobaczył zdanie „z” w dowolnym znalezionym JS, wyeliminowałbym je i zapytał autora, który to napisał, aby upewnić się, że wie, dlaczego nie jest dobrą rzeczą… używać ukrytej funkcji? Bardziej jak „odrażająca funkcja”.
Jason Bunting
1
rozważ bardziej złożony łańcuch abcd "z (abc) {d.foo = bar;} jest potężny i nie jest podatny na błędy. Kluczem jest ograniczenie katalogu głównego o jeden poziom w górę. I błędna pisownia nazwy zmiennej? Wprowadzasz błąd jeśli zrobisz to gdziekolwiek to zrobisz, bez względu na „z”
annakata,
4
Douglas Crockford powiedział ostatnio, że „with” to jedna z najgorszych części JavaScript w .NET Rocks! podcast.
rdzeń
51

Metody (lub funkcje) można wywoływać na obiektach, które nie są typu, z którym zostały zaprojektowane. Świetnie nadaje się do wywoływania metod rodzimych (szybkich) na obiektach niestandardowych.

var listNodes = document.getElementsByTagName('a');
listNodes.sort(function(a, b){ ... });

Ten kod ulega awarii, ponieważ listNodesnie jest toArray

Array.prototype.sort.apply(listNodes, [function(a, b){ ... }]);

Ten kod działa, ponieważ listNodesdefiniuje wystarczającą liczbę właściwości podobnych do tablicy (operator długości, []) do użycia przez sort().

Vincent Robert
źródło
43

Dziedziczenie prototypowe (spopularyzowane przez Douglasa Crockforda) całkowicie rewolucjonizuje sposób myślenia o mnóstwie rzeczy w JavaScript.

Object.beget = (function(Function){
    return function(Object){
        Function.prototype = Object;
        return new Function;
    }
})(function(){});

To zabójca! Szkoda, że ​​prawie nikt go nie używa.

Pozwala „spłodzić” nowe wystąpienia dowolnego obiektu, rozszerzyć je, zachowując (żywy) prototypowy link dziedziczący do innych właściwości. Przykład:

var A = {
  foo : 'greetings'
};  
var B = Object.beget(A);

alert(B.foo);     // 'greetings'

// changes and additionns to A are reflected in B
A.foo = 'hello';
alert(B.foo);     // 'hello'

A.bar = 'world';
alert(B.bar);     // 'world'


// ...but not the other way around
B.foo = 'wazzap';
alert(A.foo);     // 'hello'

B.bar = 'universe';
alert(A.bar);     // 'world'
Már Örlygsson
źródło
42

Niektórzy nazwaliby to kwestią gustu, ale:

aWizz = wizz || "default";
// same as: if (wizz) { aWizz = wizz; } else { aWizz = "default"; }

Operator trójnożny można powiązać, aby działał jak Scheme (cond ...):

(cond (predicate  (action  ...))
      (predicate2 (action2 ...))
      (#t         default ))

można zapisać jako ...

predicate  ? action( ... ) :
predicate2 ? action2( ... ) :
             default;

Jest to bardzo „funkcjonalne”, ponieważ rozgałęzia kod bez skutków ubocznych. Więc zamiast:

if (predicate) {
  foo = "one";
} else if (predicate2) {
  foo = "two";
} else {
  foo = "default";
}

Możesz pisać:

foo = predicate  ? "one" :
      predicate2 ? "two" :
                   "default";

Działa też dobrze z rekurencją :)

Andrey Fedorov
źródło
Podoba mi się podana przez ciebie składnia predykatów. Nigdy nie myślałem o takim łańcuchowaniu. schludny.
Allain Lalonde
2
Uh ... JavaScript ma instrukcję switch (). :-)
staticsan
Nie jestem wielkim fanem instrukcji switch - są artefaktem C, a nie programowaniem funkcjonalnym. W moim przykładzie instrukcja switch nadal potrzebowałaby trzech oddzielnych instrukcji, wszystkie zaczynające się od „foo =” - oczywiste niepotrzebne powtórzenie.
Andrey Fedorov
14
Z jednej strony witam operatora trójskładnikowego.
thomasrutter
8
Podczas ponownego czytania chciałbym zauważyć, że nie jest to „sprawienie, że kod wygląda jak inny język”, ale w rzeczywistości upraszcza semantyczne znaczenie kodu: kiedy próbujesz powiedzieć „ustaw foo na jeden z trzech rzeczy ”, to stwierdzenie powinno zaczynać się od„ foo = ... ”, a nie„ if ”.
Andriej Fiodorow
41

Liczby są również obiektami. Możesz więc robić fajne rzeczy, takie jak:

// convert to base 2
(5).toString(2) // returns "101"

// provide built in iteration
Number.prototype.times = function(funct){
  if(typeof funct === 'function') {
    for(var i = 0;i < Math.floor(this);i++) {
      funct(i);
    }
  }
  return this;
}


(5).times(function(i){
  string += i+" ";
});
// string now equals "0 1 2 3 4 "

var x = 1000;

x.times(function(i){
  document.body.innerHTML += '<p>paragraph #'+i+'</p>';
});
// adds 1000 parapraphs to the document
Zach
źródło
O MÓJ BOŻE! Nie wiedziałem o toString (radix) ...
Ates Goral
1
Ta implementacja timesnie jest wydajna: Math.floorjest wywoływana za każdym razem zamiast tylko raz.
dolmen
33

Co powiesz na zamknięcia w JavaScript (podobne do anonimowych metod w C # v2.0 +). Możesz utworzyć funkcję, która tworzy funkcję lub „wyrażenie”.

Przykład zamknięć :

//Takes a function that filters numbers and calls the function on 
//it to build up a list of numbers that satisfy the function.
function filter(filterFunction, numbers)
{
  var filteredNumbers = [];

  for (var index = 0; index < numbers.length; index++)
  {
    if (filterFunction(numbers[index]) == true)
    {
      filteredNumbers.push(numbers[index]);
    }
  }
  return filteredNumbers;
}

//Creates a function (closure) that will remember the value "lowerBound" 
//that gets passed in and keep a copy of it.
function buildGreaterThanFunction(lowerBound)
{
  return function (numberToCheck) {
    return (numberToCheck > lowerBound) ? true : false;
  };
}

var numbers = [1, 15, 20, 4, 11, 9, 77, 102, 6];

var greaterThan7 = buildGreaterThanFunction(7);
var greaterThan15 = buildGreaterThanFunction(15);

numbers = filter(greaterThan7, numbers);
alert('Greater Than 7: ' + numbers);

numbers = filter(greaterThan15, numbers);
alert('Greater Than 15: ' + numbers);
Tyler
źródło
1
nie jestem pewien, ale czy mogę zwrócić (numberToCheck> lowerBound)? prawda fałsz; po prostu zostań return (numberToCheck> lowerBound); tylko próbuję zwiększyć moje zrozumienie ...
davidsleeps
4
Powiedziałbym, że anonimowe funkcje w C # są równoważne zamknięciom, a nie odwrotnie :)
vava
11
Zamknięcia i funkcje anonimowe są odrębnymi, odrębnymi pojęciami. Funkcje, które można tworzyć bez nazwy, mają funkcje anonimowe. To, że zmienna w zakresie „tworzenia” jest powiązana z utworzoną funkcją, jest zamknięciem. Krótko mówiąc, zamknięcie przypomina bardziej ukrytą zmienną globalną.
slebetman
1
To prawda. Tylko wtedy, gdy anonimowe metody wykorzystują zmienną z zakresu tworzenia, jest to podobne do zamknięcia. Zaktualizowałem angielski w odpowiedzi. Wciąż pozostawia coś do życzenia, ale nie mam pojęcia o poprawnym angielskim.
Tyler
2
Nie sądzę, że jest to najlepszy lub najłatwiejszy do zrozumienia przykład tego, czym jest zamknięcie. Tylko mówię. Istotą zamknięcia jest to, że nawet jeśli wiązka zmiennych wydaje się „wykraczać poza zakres”, nadal może być dostępna dla funkcji, która została pierwotnie zdefiniowana w tym zakresie. W powyższym przykładzie oznacza to, że zmienna lowerBound jest nadal dostępna dla tej wewnętrznej, anonimowej funkcji, nawet gdy funkcja zewnętrzna, buildGreaterThanFunction, zakończy się.
thomasrutter
32

Możesz także rozszerzyć (odziedziczyć) klasy i przesłonić właściwości / metody za pomocą prototypowej łyżki łańcuchowej16, o której wspominano.

W poniższym przykładzie tworzymy klasę Pet i definiujemy niektóre właściwości. Zastępujemy również metodę .toString () odziedziczoną z Object.

Następnie tworzymy klasę Dog, która rozszerza Pet i zastępuje metodę .toString () ponownie zmieniając jej zachowanie (polimorfizm). Ponadto dodajemy inne właściwości do klasy potomnej.

Następnie sprawdzamy łańcuch dziedziczenia, aby pokazać, że pies jest nadal typu pies, typu zwierzę i typu obiekt.

// Defines a Pet class constructor 
function Pet(name) 
{
    this.getName = function() { return name; };
    this.setName = function(newName) { name = newName; };
}

// Adds the Pet.toString() function for all Pet objects
Pet.prototype.toString = function() 
{
    return 'This pets name is: ' + this.getName();
};
// end of class Pet

// Define Dog class constructor (Dog : Pet) 
function Dog(name, breed) 
{
    // think Dog : base(name) 
    Pet.call(this, name);
    this.getBreed = function() { return breed; };
}

// this makes Dog.prototype inherit from Pet.prototype
Dog.prototype = new Pet();

// Currently Pet.prototype.constructor
// points to Pet. We want our Dog instances'
// constructor to point to Dog.
Dog.prototype.constructor = Dog;

// Now we override Pet.prototype.toString
Dog.prototype.toString = function() 
{
    return 'This dogs name is: ' + this.getName() + 
        ', and its breed is: ' + this.getBreed();
};
// end of class Dog

var parrotty = new Pet('Parrotty the Parrot');
var dog = new Dog('Buddy', 'Great Dane');
// test the new toString()
alert(parrotty);
alert(dog);

// Testing instanceof (similar to the `is` operator)
alert('Is dog instance of Dog? ' + (dog instanceof Dog)); //true
alert('Is dog instance of Pet? ' + (dog instanceof Pet)); //true
alert('Is dog instance of Object? ' + (dog instanceof Object)); //true

Obie odpowiedzi na to pytanie były kodami zmodyfikowanymi ze świetnego artykułu MSDN autorstwa Raya Djajadinaty.

Tyler
źródło
31

Możesz wychwycić wyjątki w zależności od ich rodzaju. Cytat z MDC :

try {
   myroutine(); // may throw three exceptions
} catch (e if e instanceof TypeError) {
   // statements to handle TypeError exceptions
} catch (e if e instanceof RangeError) {
   // statements to handle RangeError exceptions
} catch (e if e instanceof EvalError) {
   // statements to handle EvalError exceptions
} catch (e) {
   // statements to handle any unspecified exceptions
   logMyErrors(e); // pass exception object to error handler
}

UWAGA: warunkowe klauzule catch są rozszerzeniem Netscape (a zatem Mozilla / Firefox), które nie jest częścią specyfikacji ECMAScript i dlatego nie można na nim polegać, z wyjątkiem określonych przeglądarek.

Ionuț G. Stan
źródło
29
Nic na to nie poradzę: złap (mnie, jeśli możesz)
Ates Goral
6
Przeczytaj notatkę z cytowanej strony MDC: warunkowe klauzule catch to rozszerzenie Netscape (a zatem Mozilla / Firefox), które nie jest częścią specyfikacji ECMAScript i dlatego nie można na nim polegać, z wyjątkiem określonych przeglądarek.
Jason S
31

Z czubka mojej głowy ...

Funkcje

arguments.callee odnosi się do funkcji, która obsługuje zmienną „arguments”, więc można jej użyć do rekurencji funkcji anonimowych:

var recurse = function() {
  if (condition) arguments.callee(); //calls recurse() again
}

Jest to przydatne, jeśli chcesz zrobić coś takiego:

//do something to all array items within an array recursively
myArray.forEach(function(item) {
  if (item instanceof Array) item.forEach(arguments.callee)
  else {/*...*/}
})

Obiekty

Ciekawa rzecz w elementach obiektu: mogą mieć dowolny ciąg znaków jako swoje nazwy:

//these are normal object members
var obj = {
  a : function() {},
  b : function() {}
}
//but we can do this too
var rules = {
  ".layout .widget" : function(element) {},
  "a[href]" : function(element) {}
}
/* 
this snippet searches the page for elements that
match the CSS selectors and applies the respective function to them:
*/
for (var item in rules) {
  var elements = document.querySelectorAll(rules[item]);
  for (var e, i = 0; e = elements[i++];) rules[item](e);
}

Smyczki

String.split może przyjmować wyrażenia regularne jako parametry:

"hello world   with  spaces".split(/\s+/g);
//returns an array: ["hello", "world", "with", "spaces"]

String.replace może przyjmować wyrażenie regularne jako parametr wyszukiwania i funkcję jako parametr zastępczy:

var i = 1;
"foo bar baz ".replace(/\s+/g, function() {return i++});
//returns "foo1bar2baz3"
Leo
źródło
Rzeczy, o których wspominasz ... Czy są zaimplementowane we wszystkich przeglądarkach?
cllpse
4
Nie. Jestem pewien, że Mosaic nie ma większości z nich.
jsight
2
Funkcje javascript, tak, są zaimplementowane we wszystkich głównych przeglądarkach (IE6 / 7, FF2 / 3, Opera 9+, Safari2 / 3 i Chrome). document.querySelectorAll nie jest jeszcze obsługiwany we wszystkich przeglądarkach (jest to wersja W3C JQuery's $ () i Prototype's $$ ())
Leo
6
arguments.calleejest przestarzały i będzie rzucał wyjątek w ECMAScript 5.
Hello71,
niezupełnie prawda. Klucz obiektu nie może (a raczej nie powinien) używać jako nazwy łańcucha „hasOwnProperty”, ponieważ zastąpiłoby to wbudowaną metodę obiektową.
Breton,
29

Przez większość czasu możesz używać obiektów zamiast przełączników.

function getInnerText(o){
    return o === null? null : {
        string: o,
        array: o.map(getInnerText).join(""),
        object:getInnerText(o["childNodes"])
    }[typeis(o)];
}

Aktualizacja: jeśli obawiasz się, że przypadki oceniania z wyprzedzeniem są nieefektywne (dlaczego martwisz się wydajnością już na wczesnym etapie projektowania programu?), Możesz zrobić coś takiego:

function getInnerText(o){
    return o === null? null : {
        string: function() { return o;},
        array: function() { return o.map(getInnerText).join(""); },
        object: function () { return getInnerText(o["childNodes"]; ) }
    }[typeis(o)]();
}

Jest to bardziej uciążliwe, aby pisać (lub czytać) niż przełącznik lub obiekt, ale zachowuje zalety korzystania z obiektu zamiast przełącznika, szczegółowo opisane w sekcji komentarzy poniżej. Ten styl ułatwia także przekształcenie go w odpowiednią „klasę”, gdy tylko dorośnie.

update2: staje się to dzięki proponowanym rozszerzeniom składni dla ES.next

let getInnerText = o -> ({
    string: o -> o,
    array: o -> o.map(getInnerText).join(""),
    object: o -> getInnerText(o["childNodes"])
}[ typeis o ] || (->null) )(o);
Breton
źródło
3
Tak radzi sobie Python bez instrukcji switch.
poza
2
Problem polega na tym, że zawsze ocenia wszystkie przypadki.
Kornel
@porneL to prawda, ale daje pewne korzyści: jest logicznie czystszy: przypadki są łańcuchami, które są wyszukiwane w tablicy mieszającej, a nie wyrażenia, które należy oceniać pod kątem równości, dopóki nie zwróci się wartości true. Tak więc podczas gdy więcej „wartości” jest ocenianych, mniej „kluczy” jest ocenianych. Obiekty mogą być generowane dynamicznie i modyfikowane w celu późniejszej skalowalności, odzwierciedlane do drukowania interfejsu użytkownika lub generowania dokumentów, a nawet zastępowane dynamiczną funkcją „wyszukiwania”, która jest lepsza niż posiadanie kopii / wklejonych przypadków. Nie ma wątpliwości co do przerw, upadków lub wartości domyślnych. Może być zserializowany JSON ...
Breton
@porneL o tak, i znowu, jeśli chodzi o kwestię skalowalności, obiekt można nawet łatwo przekształcić w zewnętrzną konfigurację lub plik danych, nieco prostszą zmianę niż w przypadku instrukcji switch - ale banalny, jeśli został zaprojektowany z myślą o obiekcie na początek z.
Breton
wiem, że jest to późny wpis, ale jeśli nie masz niestandardowej logiki sprawdzania typu, kiedy tablica kiedykolwiek będzie działać na twoim przykładzie? var arr = []; typeof arr; // object
keeganwatkins
25

Pamiętaj, aby użyć metody hasOwnProperty podczas iteracji po właściwościach obiektu:

for (p in anObject) {
    if (anObject.hasOwnProperty(p)) {
        //Do stuff with p here
    }
}

Odbywa się to, aby uzyskać dostęp tylko do bezpośrednich właściwości obiektu anObject , a nie korzystać z właściwości znajdujących się w dół łańcucha prototypów.

Andreas Grech
źródło
23

Zmienne prywatne z interfejsem publicznym

Używa schludnej sztuczki z definicją funkcji wywołującej. Wszystko w zwracanym obiekcie jest dostępne w interfejsie publicznym, a wszystko inne jest prywatne.

var test = function () {
    //private members
    var x = 1;
    var y = function () {
        return x * 2;
    };
    //public interface
    return {
        setx : function (newx) {
            x = newx;
        },
        gety : function () {
            return y();
        }
    }
}();

assert(undefined == test.x);
assert(undefined == test.y);
assert(2 == test.gety());
test.setx(5);
assert(10 == test.gety());
Chris MacDonald
źródło
1
nazywa się to wzorcem modułowym, jak to nazwał Eric Miraglia na yuiblog.com/blog/2007/06/12/module-pattern. Myślę, że nazwa wprowadza w błąd, powinna być nazwana Wzorcem Singletona lub coś w tym rodzaju. Mogę również dodać, że metody publiczne mogą również wywoływać inne metody publiczne za pomocą obiektu „this”. Cały czas używam tego wzorca w kodzie, aby utrzymać porządek i porządek.
mikeycgto