Versteckte Funktionen von JavaScript? [geschlossen]

312

Welche "versteckten Funktionen" von JavaScript sollte Ihrer Meinung nach jeder Programmierer kennen?

Nachdem ich die hervorragende Qualität der Antworten auf die folgenden Fragen gesehen hatte, dachte ich, es sei Zeit, sie nach JavaScript zu fragen.

Obwohl JavaScript derzeit wohl die wichtigste clientseitige Sprache ist (fragen Sie einfach Google), ist es überraschend, wie wenig die meisten Webentwickler schätzen, wie leistungsfähig es wirklich ist.

Binoj Antony
quelle
1
Meinten Sie nicht "Nachdem ich die Wiederholungspunkte und Ansichten gesehen hatte, die diese andere Frage anzog, dachte ich, ich würde fast genau die gleiche Frage stellen, um meine eigene zu verbessern"? ;-)
Bobby Jack
1
Sicher, Pessimist. :) Ich hatte überlegt, dies zu einer Community-Frage zu machen. Nachdem Sie eine bestimmte Anzahl von Punkten erhalten haben, verringert sich die Rendite.
Allain Lalonde
1
Fair genug - es sieht nicht so aus, als ob Sie den Repräsentanten "brauchen"! Ich glaube, ich habe gerade ein großes Problem mit dem C # 1 - scheint mir nicht genau die Art von Frage zu sein, für die diese Seite gedacht war.
Bobby Jack
3
Ja, vielleicht auch nicht, aber ich fand das Wissen in den Antworten großartig. Ich denke, es würde Ihnen schwer fallen, einen durchschnittlichen C # -Programmierer all dem an einem Ort auszusetzen, wenn nicht SO. Es würde Jahre dauern, damit zu spielen, um die gleiche hart erkämpfte Liste zu erstellen.
Allain Lalonde
7
Ich schreibe seit 10 Jahren professionell JavaScript und habe ein oder drei Dinge aus diesem Thread gelernt. Danke, Alan!
Andrew Hedges

Antworten:

373

Sie müssen keine Parameter für eine Funktion definieren. Sie können einfach das argumentsArray-ähnliche Objekt der Funktion verwenden .

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
quelle
117
Es ist jedoch erwähnenswert, dass Argumente zwar wie ein Array wirken, aber kein tatsächliches Javascript-Array sind - es ist nur ein Objekt. Sie können also nicht Join (), Pop (), Push (), Slice () usw. ausführen. (Sie können es in ein reales Array konvertieren, wenn Sie möchten: "var argArray = Array.prototype.slice.call (Argumente);")
Jacob Mattison
51
Es ist auch erwähnenswert, dass der Zugriff auf das Arguments-Objekt relativ teuer ist - die besten Beispiele sind Safari-, Firefox- und Chrome-Nightlies, bei denen das bloße Referenzieren des argumentsObjekts das Aufrufen einer Funktion viel langsamer macht - z. if (falsche) Argumente; wird perf weh tun.
olliej
48
In gleicher Weise haben Argumente eine "callee" -Eigenschaft, die die aktuelle Funktion selbst ist. Dies ermöglicht eine Rekursion mit anonymen Funktionen, cool!
Vincent Robert
4
@ Nathan "f (x, y, z)" sieht besser aus als "f ([x, y, z])".
Mark Cidade
16
@ Vincent Robert: Bitte beachten Sie, dass arguments.calleedies veraltet ist.
Ken
204

Ich könnte den größten Teil von Douglas Crockfords ausgezeichnetem Buch JavaScript: The Good Parts zitieren .

Aber ich nehme nur eine für dich, benutze immer ===und !==anstelle von ==und!=

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

==ist nicht transitiv. Wenn Sie es verwenden ===, würde es erwartungsgemäß für alle diese Aussagen false geben.

Martin Clarke
quelle
29
Es ist eine Schande, dass so viele Leute denken, Crockford sei allwissend. Zugegeben, der Typ ist mit den meisten seiner Kritikpunkte genau richtig, aber ich höre auf, seinen Sachen eine pauschale Bestätigung zu geben, wie es so viele Entwickler tun ...
Jason Bunting
21
Ich stimme Jasons Warnung zu. Das Buch an sich ist sehr interessant und gibt viele gute Ratschläge, aber DC ist viel zu überzeugt, dass seine Arbeitsweise die einzig richtige ist, alles andere ist "fehlerhaft". Wenn Sie einige Beispiele wünschen, sehen Sie sich seine Antworten in der JSLint Yahoo Group an.
Zilk
30
Die Verwendung von === anstelle von == ist ein guter Rat, wenn Sie durch dynamisches Tippen verwirrt sind und nur möchten, dass es "wirklich" gleich ist. Diejenigen von uns, die dynamisches Tippen verstehen, können == weiterhin für Situationen verwenden, in denen wir wissen, dass wir sie übertragen möchten, wie in 0 == '' oder 0 == '0'.
Thomasrutter
20
Bei == und === geht es nicht um dynamisches Tippen. == tippt Coersion, was ein anderes Tier ist. Wenn Sie wissen, dass Sie in string / number / etc umwandeln möchten, sollten Sie dies explizit tun.
Rene Saarsoo
15
Ich denke, der gruseligste Teil von ==ist '\n\t\r ' == 0=> true...: D
Shrikant Sharat
189

Funktionen sind erstklassige Bürger in 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

Funktionale Programmiertechniken können verwendet werden, um elegantes Javascript zu schreiben .

Insbesondere können Funktionen als Parameter übergeben werden, z. B. akzeptiert Array.filter () einen Rückruf:

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

Sie können auch eine "private" Funktion deklarieren, die nur im Rahmen einer bestimmten Funktion vorhanden ist:

function PrintName() {
    var privateFunction = function() { return "Steve"; };
    return privateFunction();
}
Gulzar Nazim
quelle
3
Es gibt drei Möglichkeiten, Funktionen in Javascript zu erstellen: Funktionssumme (x, y, z) {return (x + y + z); } und var sum = neue Funktion ("x", "y", "z", "return (x + y + z);"); sind die anderen Wege.
Marius
6
Das Konzept der Funktionen als Daten gewinnt definitiv große Punkte in meinem Buch.
Jason Bunting
Ich habe gerade das Beispiel aktualisiert, um zu zeigen, wie eine "private" Funktion verwendet wird, die nur im Rahmen einer bestimmten Funktion vorhanden ist.
Chris Pietschmann
new Function()ist so böse wie eval. Verwende nicht.
Nicolás
11
Ich bin mir nicht sicher, ob dies eine versteckte Funktion ist ... eher wie eine Kernfunktion.
Claudiu
162

Sie können die Verwendung in Bediener zu überprüfen , ob ein Schlüssel in einem Objekt vorhanden ist :

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

Wenn Sie die Objektliterale zu hässlich finden, können Sie sie mit dem parameterlosen Funktionstipp kombinieren:

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
quelle
22
Nicht so klug, das prüft, ob ein Schlüssel vorhanden ist, nicht ob ein Wert vorhanden ist. x in Liste; funktioniert nur, weil x [1]! = null ist, nicht weil der Wert 1 vorhanden ist.
Armin Ronacher
1
Ich habe die Technik in einer Weile nicht verwendet, also habe ich vergessen, dass ich vorher tatsächlich Objektliterale verwendet habe. Danke für die Korrektur.
Mark Cidade
34
Seien Sie auch vorsichtig: Der Bediener testet auch die Prototypenkette! Wenn jemand eine Eigenschaft mit dem Namen '5' in den Object.prototype eingefügt hat, würde das zweite Beispiel true zurückgeben, selbst wenn Sie '5 in list (1, 2, 3, 4)' aufgerufen haben ... Verwenden Sie besser die hasOwnProperty Methode: list (1, 2, 3, 4) .hasOwnProperty (5) gibt false zurück, auch wenn Object.prototype die Eigenschaft '5' hat.
Martijn
3
Für die allgemeinste Lösung, die testen kann, ob ein Objekt eine eigene Eigenschaft hat, selbst wenn es den Namen "hasOwnProperty" trägt, müssen Sie den gesamten Weg gehen zu: Object.prototype.hasOwnProperty.call (Objekt, Name) ;;
Kris Kowal
1
@Kris, nicht, wenn jemand Object.prototype.hasOwnProperty überschreibt;)
Nick
153

Variablen Standardwerte zuweisen

Sie können die Logik oder den Operator ||in einem Zuweisungsausdruck verwenden, um einen Standardwert anzugeben:

var a = b || c;

Die aVariable wird den Wert erhalten , cnur wenn bist falsy (wenn ist null, false, undefined, 0, empty string, oder NaN), andernfalls awird der Wert erhalten b.

Dies ist häufig in Funktionen hilfreich, wenn Sie einem Argument einen Standardwert zuweisen möchten, falls es nicht angegeben wird:

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

Beispiel für einen IE-Fallback in Ereignishandlern:

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

Die folgenden Sprachfunktionen sind seit langem bei uns, alle JavaScript-Implementierungen unterstützen sie, waren jedoch erst in ECMAScript 5th Edition Teil der Spezifikation :

Die debuggerAussage

Beschrieben in: § 12.15 Die Debugger-Anweisung

Mit dieser Anweisung können Sie Haltepunkte programmgesteuert in Ihren Code einfügen, indem Sie:

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

Wenn ein Debugger vorhanden oder aktiv ist, wird er sofort direkt in dieser Zeile unterbrochen.

Andernfalls hat diese Anweisung keine beobachtbare Auswirkung, wenn der Debugger nicht vorhanden oder aktiv ist.

Mehrzeilige String-Literale

Beschrieben in: § 7.8.4 String-Literale

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

Sie müssen vorsichtig sein , weil das Zeichen neben dem \ muss ein Leitungsabschluss sein, wenn Sie ein Leerzeichen nach dem haben \zum Beispiel, wird der Code aussehen genau das gleiche, aber es wird ein erhöhen SyntaxError.

CMS
quelle
28
Nicht wenn es null ist, wenn es als falsch angesehen wird. a = 0 || 42; gibt Ihnen 42. Dies ist vergleichbar mit Pythons oder nicht C #? Operator. Wenn Sie das C # -Verhalten wünschen, machen Sie a = (b === null)? c: b;
Armin Ronacher
Es funktioniert auch in Visual Studio, wenn Sie auf ASP.NET entwickeln :)
Chakrit
2
Ich wünschte, es wäre richtig || nur für undefinierte. Ich wurde heute für 0 davon gebissen, da ich eine Emulation einer überladenen Methode erstellen wollte, so dass das letzte Argument optional war und stattdessen ein Standardwert verwendet wurde.
Egaga
+1 Dieser Trick wird vom Standard-Google Analytics-Snippet verwendet. `var _gaq = _gaq || []; `; Es verhindert, dass übereifrige Benutzer ihre eigene Arbeit überschreiben.
Yahel
2
Ich wusste nichts über die mehrzeilige String-Literal-Technik. Das ist fantastisch, danke.
Charlie Flowers
145

JavaScript hat keinen Blockbereich (aber es hat einen Abschluss, also nennen wir es sogar?).

var x = 1;
{
   var x = 2;
}
alert(x); // outputs 2
Eugene Yokota
quelle
3
Das ist gut so. Es ist ein wirklich wichtiger Unterschied zu den meisten C-ähnlichen Sprachen.
Martin Clarke
9
Sie können immer "var tmp = function () {/ * block scope * /} ();" ausführen. Die Syntax ist hässlich, aber es funktioniert.
Joeri Sebrechts
3
Oder Sie können "let" verwenden, wenn es nur Firefox ist: stackoverflow.com/questions/61088/…
Eugene Yokota
10
oder einfach: (function () {var x = 2;}) (); Alarm (Typ von x); // undefined
Pim Jager
@Pim: JSLint sagt: "Verschieben Sie den Aufruf in die Parens, die die Funktion enthalten." Zusammen mit "Erwartet genau ein Leerzeichen zwischen 'Funktion' und '('.".
Hello71
144

Sie können mit []statt auf auf Objekteigenschaften zugreifen.

Auf diese Weise können Sie eine Eigenschaft nachschlagen, die einer Variablen entspricht.

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

Sie können dies auch verwenden, um Objekteigenschaften abzurufen / festzulegen, deren Name keine legale Kennung ist.

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.

Einige Leute wissen das nicht und verwenden eval () wie folgt, was eine wirklich schlechte Idee ist :

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

Dies ist schwerer zu lesen, schwerer zu finden (kann jslint nicht verwenden), langsamer auszuführen und kann zu XSS-Exploits führen.

Patrick
quelle
eval ist böse, obwohl selten notwendig
Doug Domeny
Ich benutze eval nie und erinnere mich, als ich das entdeckte. Es hat mich sehr glücklich gemacht.
Zusammenfassend kann auf Objekteigenschaften sowohl durch Punkt- als auch durch Indexnotation zugegriffen werden
Russ Cam
9
Es ist interessant festzustellen, dass Punktreferenzierung tatsächlich Syntaxzucker für die Klammerref ist. foo.barverhält sich laut spezifikation sowieso genauso foo["bar"]. Beachten Sie auch, dass alles eine Zeichenfolgeeigenschaft ist. Selbst wenn Sie Array-Zugriff ausführen, array[4]wird die 4 in eine Zeichenfolge konvertiert (wiederum zumindest gemäß ECMAScript v3-Spezifikation)
Claudiu
Ich denke, jeder JS-Programmierer sollte das wissen.
Cem Kalyoncu
144

Wenn Sie nach einer anständigen JavaScript-Referenz zu einem bestimmten Thema suchen, geben Sie das Schlüsselwort "mdc" in Ihre Abfrage ein. Ihre ersten Ergebnisse stammen aus dem Mozilla Developer Center. Ich habe keine Offline-Referenzen oder Bücher bei mir. Ich verwende immer den Schlüsselworttrick "mdc", um direkt zu dem zu gelangen, wonach ich suche. Zum Beispiel:

Google: Javascript-Array sortieren mdc
(in den meisten Fällen können Sie "Javascript" weglassen)

Update: Mozilla Developer Center wurde in Mozilla Developer Network umbenannt . Der Schlüsselworttrick "mdc" funktioniert immer noch, aber bald müssen wir möglicherweise stattdessen "mdn" verwenden .

Ates Goral
quelle
50
Wow, großartige Ressource. Sofort besser als crappy w3schools ...
DisgruntledGoat
11
Sie müssen es nicht einmal googeln, wenn Sie mit Firefox arbeiten: Geben Sie einfach "array mdc" in die Adressleiste ein und drücken Sie die Eingabetaste.
Sasha Chedygov
2
Das Beste daran ist, wie diese Frage zum Stapelüberlauf auf der ersten Ergebnisseite steht :)
Jiaaro
5
Ein Vorschlag dafür: fördern Sie js.com , eine Basis-SEO-Initiative, um MDC-Ergebnisse in den Google-Suchergebnissen weiter nach oben zu bringen.
Yahel
3
Jetzt ist das MDN Doc Center, also ist das Schlüsselwort 'mdc' immer noch gültig :)
Aleadam
143

Vielleicht ein bisschen offensichtlich für einige ...

Installieren Sie Firebug und verwenden Sie console.log ("Hallo"). So viel besser als die Verwendung von random alert (); 's, an die ich mich erinnere, dass ich vor ein paar Jahren viel getan habe.

qui
quelle
12
Vergessen Sie nicht, die Konsolenanweisungen zu entfernen, bevor Sie Ihren Code an andere weitergeben, auf denen Firebug möglicherweise nicht installiert ist.
Chris Noe
161
Funktionsprotokoll (msg) {if (Konsole) console.log (msg) else alert (msg)}
Josh
4
Noch besser, stellen Sie log-Anweisungen ';;;' voran. und dann kümmert sich minify darum. (Zumindest das Perl-Modul, das ich verwende, hat diese Funktion und behauptet, es sei alltäglich.)
Kev
10
Josh: Das wird nicht funktionieren, da die Konsole nicht definiert ist. Sie können den Konsolentyp überprüfen! == "undefined" oder window.console.
Eli Gray
23
Schließen Sie immer Folgendes ein: if (typeof ('console') == 'undefined') {console = {log: function () {}}; } Dann können Sie console.log weiter verwenden und es tut einfach nichts.
Gregmac
120

Private Methoden

Ein Objekt kann private Methoden haben.

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
quelle
16
Das ist nicht wirklich eine private Funktion - es ist eher eine Funktionsvariable in einem lokalen Bereich.
Keith
6
Richtig, aber nach allen operativen Definitionen kann ich mir vorstellen, dass dies eine Methode ist. Es ist ein Codeblock mit einem Namen, der Zugriff auf den Instanzstatus hat und nur von dieser Instanz gesehen werden kann. Was ist Ihre Definition einer privaten Methode?
Allain Lalonde
14
@ Zach, genau! Nach Jahren der Arbeit mit klassenbasierten OO-Sprachen kann man leicht vergessen, dass es sich lediglich um eine Implementierung von OO-Konzepten handelt. Natürlich helfen auch die verschiedenen Bibliotheken, die versuchen, quasi-klassenbasiertes OO in JS zu
packen,
5
Ich frage mich nur, hat person1 einen Law Blog? ;-)
Travis
4
+1 für die verhaftete Entwicklungsreferenz
Domenic
99

Auch in Crockfords "Javascript: The Good Parts" erwähnt:

parseInt()ist gefährlich. Wenn Sie ihm eine Zeichenfolge übergeben, ohne ihn über die richtige Basis zu informieren, werden möglicherweise unerwartete Zahlen zurückgegeben. Beispiel parseInt('010'): Gibt 8 statt 10 zurück. Wenn Sie eine Basis an parseInt übergeben, funktioniert sie ordnungsgemäß:

parseInt('010') // returns 8! (in FF3)
parseInt('010', 10); // returns 10 because we've informed it which base to work with.
bluefish101
quelle
13
Achten Sie bei Codeüberprüfungen immer auf diese. Das Weglassen der ", 10" ist ein häufiger Fehler, der bei den meisten Tests unbemerkt bleibt.
Doug Domeny
Ich habe mich vor Jahren von der Radix-Ausgabe verbrannt und noch nie etwas vergessen, das so kontraintuitiv ist. Eine großartige Sache, auf die Sie hinweisen sollten, da Sie sich eine Weile wundern werden.
JamesEggers
4
Warum nicht verwenden Math.flooroder Number? 10 === Math.floor("010"); 10 === Number("010");schwimmt:42 === Math.floor("42.69"); 42.69 === Number("42.69");
nur jemand
1
@Infinity Wenn noch keine Antwort veröffentlicht wurde, sollten Sie dies tun. Ich hatte keine Ahnung, dass es so einfach ist, das integrierte Funktionsverhalten zu überschreiben. Natürlich sollte man sich die Code-Pakete, die sie von anderen Websites ausleihen, etwas genauer ansehen. Diese harmlose parseIntFunktion könnte leicht dazu gebracht werden, etwas zu tun, das nicht so harmlos ist.
Bob-the-Zerstörer
6
@Infinity: Wie wäre es mit einer Neudefinition des fn, um den 'Codierungsfehler' hervorzuheben? __parseInt = parseInt; parseInt = function (str, base) { if (!base) throw new Error(69, "All your base belong to us"); return __parseInt(str, base); }
JBRWilkinson
97

Funktionen sind Objekte und können daher Eigenschaften haben.

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

fn.foo = 1;

fn.next = Funktion (y) {
  // //
}}
VolkerK
quelle
13
Dies ist ein sehr nützlicher Tipp. Beispielsweise können Sie Standardwerte als Eigenschaft der Funktion festlegen. Zum Beispiel: myfunc.delay = 100; Dann können Benutzer den Standardwert ändern und alle Funktionsaufrufe verwenden den neuen Standardwert. Zum Beispiel: myfunc.delay = 200; myfunc ();
BarelyFitz
Nützlich ... und gefährlich!
Palswim
Sieht schlampig aus. Warum dies anstelle einer Variablen verwenden?
Instantsetsuna
1
@instantsetsuna: Warum eine andere separate Variable? Wie üblich
läuft
91

Ich muss sagen, dass sich Funktionen selbst ausführen.

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

Da Javascript keinen Blockbereich hat , können Sie eine selbstausführende Funktion verwenden, wenn Sie lokale Variablen definieren möchten:

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

Hier myvarwird der globale Bereich nicht beeinträchtigt oder verschmutzt und verschwindet, wenn die Funktion beendet wird.

Thomasrutter
quelle
2
Wofür ist das nützlich? Sie erhalten die gleichen Ergebnisse, wenn Sie die Warnung außerhalb der Funktion platzieren.
PotatoEngineer
7
Es geht nicht um die Warnung, es geht darum, eine Funktion auf einmal zu definieren und auszuführen. Diese selbstausführende Funktion könnte einen Wert zurückgeben und die Funktion als Parameter an eine andere Funktion übergeben.
ScottKoon
5
@ Paul ist es gut für die Kapselung.
Mike Robinson
22
Es ist auch gut für Block Scoping.
Jim Hunziker
24
Ja, ich schließe alle meine .jsDateien in eine anonyme selbstausführende Funktion ein und hänge alles, worauf ich global zugreifen möchte, an das windowObjekt an. Verhindert die Verschmutzung des globalen Namespace.
CDMckay
83

Wissen, wie viele Parameter von einer Funktion erwartet werden

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

Wissen, wie viele Parameter von der Funktion empfangen werden

function add_many_nums(){
    return arguments.length;
}    
add_many_nums(2,1,122,12,21,89); //returns 6
pramodc84
quelle
23
Ich wusste nie über den ersten Teil Bescheid. Nett!
Mcjabberz
1
Ebenso können Sie herausfinden, mit wie vielen Argumenten eine Funktion erwartet function.length.
Xavi
6
@ Xavi, der 1. Teil der Antwort ist
pramodc84
79

Hier sind einige interessante Dinge:

  • Vergleicht man NaNmit etwas (noch NaN) ist immer falsch, das schließt ==, <und >.
  • NaN Steht für Not a Number, aber wenn Sie nach dem Typ fragen, wird tatsächlich eine Nummer zurückgegeben.
  • Array.sort kann eine Komparatorfunktion übernehmen und wird von einem Quicksort-ähnlichen Treiber aufgerufen (abhängig von der Implementierung).
  • Reguläre Ausdrücke "Konstanten" können den Zustand beibehalten, wie das letzte, was sie gefunden haben.
  • Einige Versionen von JavaScript können Sie für den Zugriff $0, $1, $2Mitglieder auf einem regulären Ausdruck.
  • nullist anders als alles andere. Es ist weder ein Objekt, ein Boolescher Wert, eine Zahl, eine Zeichenfolge noch undefined. Es ist ein bisschen wie eine "Alternative" undefined. (Hinweis: typeof null == "object")
  • Im äußersten Kontext thisergibt sich das ansonsten unbenennbare [globale] Objekt.
  • Wenn Sie eine Variable mit deklarieren var, anstatt sich nur auf die automatische Deklaration der Variablen zu verlassen, hat die Laufzeit eine echte Chance, den Zugriff auf diese Variable zu optimieren
  • Das withKonstrukt wird solche Optimierungen zerstören
  • Variablennamen können Unicode-Zeichen enthalten.
  • Reguläre JavaScript-Ausdrücke sind eigentlich nicht regulär. Sie basieren auf Perls regulären Ausdrücken, und es ist möglich, Ausdrücke mit Lookaheads zu erstellen, deren Auswertung sehr, sehr lange dauert.
  • Blöcke können beschriftet und als Ziele von verwendet werden break. Schleifen können beschriftet und als Ziel von verwendet werden continue.
  • Arrays sind nicht spärlich. Wenn Sie das 1000. Element eines ansonsten leeren Arrays festlegen, sollte es mit gefüllt werden undefined. (hängt von der Implementierung ab)
  • if (new Boolean(false)) {...} wird den {...}Block ausführen
  • Die regulären Ausdrucksmodule von Javascript sind implementierungsspezifisch: z. B. ist es möglich, "nicht tragbare" reguläre Ausdrücke zu schreiben.

[als Reaktion auf gute Kommentare ein wenig aktualisiert; siehe Kommentare]

David Leonard
quelle
5
null ist eigentlich ein (spezielles) Objekt. typeof nullgibt "Objekt" zurück.
Ates Goral
4
Sie können das [Global] -Objekt auch von einem beliebigen Ort abrufen: var glb = function () {return this; } ();
Zilk
2
Das globale Objekt in Javascript in einem Browser ist das Fensterobjekt. Wenn Sie im globalen Bereich Folgendes tun: window.a == a;
Pim Jäger
8
"Arrays sind nicht spärlich" hängt von der Implementierung ab. Wenn Sie den Wert von [1000] festlegen und einen [999] anzeigen, undefinedist dies der Fall, aber dies ist nur der Standardwert, den Sie erhalten, wenn Sie nach einem Index suchen, der nicht vorhanden ist. Wenn Sie ein [2000] aktiviert haben, ist dies auch der Fall undefined, aber das bedeutet nicht, dass Sie noch Speicher dafür zugewiesen haben. In IE8 sind einige Arrays dicht und andere spärlich, je nachdem, wie sich die JScript-Engine zu diesem Zeitpunkt anfühlte. Lesen Sie hier mehr: blogs.msdn.com/jscript/archive/2008/04/08/…
Chris Nielsen
2
@Ates und @SF: typeof gibt "object" für eine Reihe verschiedener Typen zurück. Sobald Sie jedoch wissen, wie es funktioniert und welche Typen als "Objekt" identifiziert werden, ist es zumindest zuverlässig und konsistent in seiner Implementierung.
Thomasrutter
77

Ich weiß, dass ich zu spät zur Party komme, aber ich kann einfach nicht glauben, dass die +Nützlichkeit des Betreibers nicht erwähnt wurde, außer "irgendetwas in eine Zahl umwandeln". Vielleicht ist das so gut versteckt?

// 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

Natürlich können Sie dies alles Number()stattdessen verwenden, aber der +Bediener ist so viel hübscher!

Sie können auch einen numerischen Rückgabewert für ein Objekt definieren, indem Sie die valueOf()Methode des Prototyps überschreiben . Eine für dieses Objekt durchgeführte Zahlenkonvertierung führt nicht NaNzum Rückgabewert der valueOf()Methode:

var rnd = {
    "valueOf": function () { return Math.floor(Math.random()*1000); }
};
+rnd;               // -> 442;
+rnd;               // -> 727;
+rnd;               // -> 718;
Andy E.
quelle
Sie können einfach 0xFFusw. tun , ohne dass dies erforderlich ist +"0xFF".
Nyuszika7h
9
@ Nyuszika7H: Du verpasst irgendwie den Punkt, der andere Grundelemente und Objekte zu Zahlen zwingt . Natürlich können Sie einfach schreiben 0xFF, ähnlich wie Sie 1stattdessen schreiben können +true. Ich schlage vor, dass Sie +("0x"+somevar)als Alternative zu verwenden können parseInt(somevar, 16), wenn Sie möchten.
Andy E
75

" Erweiterungsmethoden in JavaScript " über die Prototyp-Eigenschaft.

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

Dadurch wird containsallen ArrayObjekten eine Methode hinzugefügt . Sie können diese Methode mit dieser Syntax aufrufen

var stringArray = ["foo", "bar", "foobar"];
stringArray.contains("foobar");
Löffel16
quelle
18
Dies wird im Allgemeinen als schlechte Idee angesehen, da andere Codes (nicht Ihre) möglicherweise Annahmen über das Array-Objekt treffen.
Chris Noe
39
Es wird auch allgemein als schlechte Idee angesehen, Annahmen über das Array-Objekt zu treffen. :(
Augenlidlosigkeit
Uhmmmm .. Javascript 1.6 Array Extras? Index von? irgendwelche Glocken läuten?
Breton
2
@Breton: Es ist nicht spezifisch für die Array-Klasse, es ist nur ein Beispiel. Ich benutze dies, um das neue Date () zu erweitern. ToString (); Methode, die die Verwendung einer Maskenzeichenfolge ermöglicht. Jedes Objekt kann erweitert werden, und alle Instanzen erhalten die neue Methode.
Esteban Küber
1
@ Mathias: Hier geht es nicht um das DOM.
Dolmen
60

Um eine Eigenschaft ordnungsgemäß aus einem Objekt zu entfernen, sollten Sie die Eigenschaft löschen, anstatt sie nur auf undefiniert zu setzen :

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

obj.prop2 = undefined;

for (var key in obj) {
    ...

Die Eigenschaft prop2 wird weiterhin Teil der Iteration sein. Wenn Sie prop2 vollständig entfernen möchten , sollten Sie stattdessen Folgendes tun:

delete obj.prop2;

Die Eigenschaft prop2 wird nicht mehr angezeigt, wenn Sie die Eigenschaften durchlaufen.

Ates Goral
quelle
3
Beachten Sie, dass die delete-Anweisung nicht ohne browserspezifische Macken ist. Dies schlägt beispielsweise mit einem großen Fehler fehl, wenn Sie es im IE versuchen und das Objekt kein natives JS-Objekt ist (selbst wenn Sie eine Eigenschaft löschen, die Sie selbst hinzugefügt haben). Es ist auch nicht zum Löschen einer Variablen vorgesehen, wie beim Löschen von myvar. aber ich denke, das funktioniert in einigen Browsern. Der Code in der obigen Antwort scheint jedoch ziemlich sicher zu sein.
Thomasrutter
undefiniert kann übrigens auch eine Variable sein! Versuchen Sie var undefined = "etwas"
Johann Philipp Strathausen
57

with.

Es wird selten verwendet und ist ehrlich gesagt selten nützlich ... Aber unter bestimmten Umständen hat es seine Verwendung.

Zum Beispiel: Objektliterale sind sehr praktisch, um Eigenschaften für ein neues Objekt schnell einzurichten . Was aber, wenn Sie die Hälfte der Eigenschaften eines vorhandenen Objekts ändern müssen ?

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

// ...

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

Alan Sturm weist darauf hin , dass dies etwas gefährlich sein: Wenn das Objekt als Kontext verwendet wird , nicht hat eine der Eigenschaften wurde zugewiesen, wird es in dem äußeren Umfang gelöst werden, was möglicherweise zu schaffen oder eine globale Variable zu überschreiben. Dies ist besonders gefährlich, wenn Sie es gewohnt sind, Code für die Arbeit mit Objekten zu schreiben, bei denen Eigenschaften mit Standardwerten oder leeren Werten undefiniert bleiben:

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

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

Daher ist es wahrscheinlich eine gute Idee, die Verwendung der withAnweisung für eine solche Zuordnung zu vermeiden .

Siehe auch: Gibt es legitime Verwendungszwecke für die JavaScript-Anweisung "with"?

Shog9
quelle
29
Konventionelle Weisheit ist mit Aussage zu vermeiden. Wenn das Benutzerobjekt keine der von Ihnen genannten Eigenschaften hätte, würde die Variable außerhalb des Pseudobereichs des with-Blocks geändert. Auf diese Weise liegen Fehler. Weitere Informationen unter yuiblog.com/blog/2006/04/11/with-statement-considered-harmful
Alan Storm
1
Shog, bei den Einwänden geht es nicht um falsch geschriebene Variablen, sondern darum, einen Codeblock zu betrachten und mit Sicherheit sagen zu können, was eine bestimmte Zeile in diesem Block tut. Da Javascript-Objekte so dynamisch sind, können Sie zu keinem Zeitpunkt mit Sicherheit sagen, über welche Eigenschaften / Elemente sie verfügen.
Alan Storm
2
Amen - wenn ich die "with" -Anweisung in einem von mir gefundenen JS sehen würde, würde ich sie entfernen und den Entwickler, der sie geschrieben hat, befragen, um sicherzustellen, dass er weiß, warum es nicht gut ist, sie zu verwenden ... "versteckte Funktion?" Eher wie "abscheuliche Funktion".
Jason Bunting
1
Betrachten Sie eine komplexere Kette abcd "mit (abc) {d.foo = bar;} ist leistungsstark und nicht von Natur aus fehleranfällig. Der Schlüssel besteht darin, die Wurzel eine Ebene höher zu kürzen. Und einen Variablennamen falsch zu schreiben? Sie führen einen Fehler ein wenn Sie das tun, wo immer Sie es tun, unabhängig von "mit".
Annakata
4
Douglas Crockford sagte kürzlich, "mit" sei einer der schlimmsten Teile von JavaScript in einem .NET Rocks! Podcast.
Kern
51

Methoden (oder Funktionen) können für Objekte aufgerufen werden, die nicht dem Typ entsprechen, für den sie entwickelt wurden. Dies ist ideal, um native (schnelle) Methoden für benutzerdefinierte Objekte aufzurufen.

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

Dieser Code stürzt ab, weil listNodeses sich nicht um einen handeltArray

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

Dieser Code funktioniert, weil listNodesgenügend Array-ähnliche Eigenschaften (Länge, Operator []) definiert sind, um von verwendet zu werden sort().

Vincent Robert
quelle
43

Die prototypische Vererbung (populär gemacht von Douglas Crockford) revolutioniert die Art und Weise, wie Sie über viele Dinge in Javascript denken.

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

Es ist ein Mörder! Schade, wie fast niemand es benutzt.

Sie können damit neue Instanzen eines Objekts "erzeugen", erweitern und gleichzeitig eine (live) prototypische Vererbungsverknüpfung zu ihren anderen Eigenschaften beibehalten. Beispiel:

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
quelle
42

Einige würden dies Geschmackssache nennen, aber:

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

Der Trinary-Operator kann so verkettet werden, dass er sich wie im Schema verhält (cond ...):

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

kann geschrieben werden als ...

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

Dies ist sehr "funktional", da es Ihren Code ohne Nebenwirkungen verzweigt. Also statt:

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

Du kannst schreiben:

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

Funktioniert auch gut mit Rekursion :)

Andrey Fedorov
quelle
Ich mag die Prädikatsyntax, die Sie geben. Ich habe noch nie daran gedacht, so zu verketten. ordentlich.
Allain Lalonde
2
Äh ... JavaScript hat eine switch () - Anweisung. :-)
staticsan
Ich bin kein großer Fan von switch-Anweisungen - sie sind ein Artefakt von C, keine funktionale Programmierung. In meinem Beispiel würde eine switch-Anweisung immer noch drei separate Anweisungen benötigen, die alle mit "foo =" beginnen - eine offensichtliche unnötige Wiederholung.
Andrey Fedorov
14
Zum einen begrüße ich den ternären Operator.
Thomasrutter
8
Beim erneuten Lesen möchte ich darauf hinweisen, dass dies nicht "Code wie eine andere Sprache aussehen lässt", sondern die semantische Bedeutung des Codes vereinfacht: Wenn Sie versuchen zu sagen, "setzen Sie foo auf eine von drei." Dinge ", das ist eine Aussage, die mit" foo = ... "beginnen sollte, nicht mit" wenn ".
Andrey Fedorov
41

Zahlen sind auch Objekte. So kannst du coole Sachen machen wie:

// 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
quelle
OH MEIN GOTT! Ich wusste nicht über toString (radix) ...
Ates Goral
1
Diese Implementierung von timesist nicht effizient: Math.floorwird jedes Mal statt nur einmal aufgerufen.
Dolmen
33

Wie wäre es mit Schließungen in JavaScript (ähnlich wie bei anonymen Methoden in C # v2.0 +). Sie können eine Funktion erstellen, die eine Funktion oder einen "Ausdruck" erstellt.

Beispiel für Schließungen :

//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
quelle
1
Ich bin mir nicht sicher, kann aber zurückkehren (numberToCheck> lowerBound)? wahr falsch; einfach zu return werden (numberToCheck> lowerBound); Ich versuche nur mein Verständnis zu
verbessern
4
Ich würde sagen, anonyme Funktionen in C # entsprechen Schließungen, nicht umgekehrt :)
vava
11
Verschlüsse und anonyme Funktionen sind separate, unterschiedliche Konzepte. Dass Funktionen ohne Namen erstellt werden können, hat anonyme Funktionen. Dass eine Variable im Bereich "Erstellen" mit der erstellten Funktion verknüpft ist, ist ein Abschluss. Kurz gesagt, ein Abschluss ähnelt eher einer versteckten globalen Variablen.
Slebetman
1
Das stimmt. Nur wenn anonyme Methoden eine Variable aus dem Erstellungsbereich verwenden, ähnelt sie einem Abschluss. Ich habe das Englisch auf der Antwort aktualisiert. Es lässt immer noch zu wünschen übrig, aber ich bin ratlos für das richtige Englisch.
Tyler
2
Ich denke nicht, dass dies das beste oder am einfachsten zu verstehende Beispiel dafür ist, was eine Schließung ist. Ich sage nur. Der Punkt eines Abschlusses ist, dass selbst wenn eine Reihe von Variablen den Bereich zu verlassen scheinen, sie für eine Funktion verfügbar bleiben können, die ursprünglich in diesem Bereich definiert wurde. Im obigen Beispiel bedeutet dies, dass diese innere, anonyme Funktion auch dann auf die Variable lowerBound zugreifen kann, wenn die äußere Funktion buildGreaterThanFunction beendet wird.
Thomasrutter
32

Sie können Klassen auch erweitern (erben) und Eigenschaften / Methoden überschreiben, indem Sie den Prototyp-Kettenlöffel16 verwenden, auf den angedeutet wird.

Im folgenden Beispiel erstellen wir eine Klasse Pet und definieren einige Eigenschaften. Wir überschreiben auch die von Object geerbte .toString () -Methode.

Danach erstellen wir eine Dog-Klasse, die Pet erweitert und die .toString () -Methode überschreibt, um ihr Verhalten erneut zu ändern (Polymorphismus). Zusätzlich fügen wir der untergeordneten Klasse einige andere Eigenschaften hinzu.

Danach überprüfen wir die Vererbungskette, um zu zeigen, dass Dog immer noch vom Typ Dog, vom Typ Pet und vom Typ Object ist.

// 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

Beide Antworten auf diese Frage waren Codes, die aus einem großartigen MSDN-Artikel von Ray Djajadinata modifiziert wurden.

Tyler
quelle
31

Abhängig von ihrem Typ können Sie Ausnahmen abfangen. Zitiert aus 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
}

HINWEIS: Bedingte catch-Klauseln sind eine Netscape-Erweiterung (und damit Mozilla / Firefox), die nicht Teil der ECMAScript-Spezifikation ist und daher nur für bestimmte Browser verwendet werden kann.

Ionuț G. Stan
quelle
29
Ich konnte nicht anders: fangen (ich wenn du kannst)
Ates Goral
6
Lesen Sie den Hinweis auf der von Ihnen zitierten MDC-Seite: Bedingte catch-Klauseln sind eine Netscape-Erweiterung (und damit Mozilla / Firefox), die nicht Teil der ECMAScript-Spezifikation ist und daher nur für bestimmte Browser verwendet werden kann.
Jason S
31

Aus meinem Kopf ...

Funktionen

Argumente.callee bezieht sich auf die Funktion, die die Variable "Argumente" hostet, sodass damit anonyme Funktionen wiederholt werden können:

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

Das ist nützlich, wenn Sie so etwas tun möchten:

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

Objekte

Eine interessante Sache über Objektmitglieder: Sie können eine beliebige Zeichenfolge als Namen haben:

//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);
}

Saiten

String.split kann reguläre Ausdrücke als Parameter verwenden:

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

String.replace kann einen regulären Ausdruck als Suchparameter und eine Funktion als Ersatzparameter verwenden:

var i = 1;
"foo bar baz ".replace(/\s+/g, function() {return i++});
//returns "foo1bar2baz3"
Leo
quelle
Die Dinge, die Sie erwähnen ... Sind sie in allen Browsern implementiert?
Cllpse
4
Ich bin mir ziemlich sicher, dass Mosaic die meisten davon nicht hat.
jsight
2
Die Javascript-Funktionen sind in allen gängigen Browsern (IE6 / 7, FF2 / 3, Opera 9+, Safari2 / 3 und Chrome) implementiert. document.querySelectorAll wird noch nicht in allen Browsern unterstützt (es ist die W3C-Version von JQuerys $ () und Prototyps $$ ())
Leo
6
arguments.calleeist veraltet und wird in ECMAScript 5 eine Ausnahme
auslösen
nicht ganz wahr. Ein Objektschlüssel kann (oder sollte) die Zeichenfolge "hasOwnProperty" nicht als Namen verwenden, da dies die integrierte Objektmethode überschreiben würde.
Breton
29

Sie können die meiste Zeit Objekte anstelle von Schaltern verwenden.

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

Update: Wenn Sie besorgt sind, dass die Fälle, die im Voraus bewertet werden, ineffizient sind (warum machen Sie sich so früh im Programmdesign Sorgen um die Effizienz?), Können Sie Folgendes tun:

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)]();
}

Dies ist schwieriger zu tippen (oder zu lesen) als ein Schalter oder ein Objekt, behält jedoch die Vorteile der Verwendung eines Objekts anstelle eines Schalters bei, die im Kommentarbereich unten beschrieben werden. Dieser Stil macht es auch einfacher, dies in eine richtige "Klasse" zu verwandeln, sobald es groß genug ist.

update2: Mit den vorgeschlagenen Syntaxerweiterungen für ES.next wird dies

let getInnerText = o -> ({
    string: o -> o,
    array: o -> o.map(getInnerText).join(""),
    object: o -> getInnerText(o["childNodes"])
}[ typeis o ] || (->null) )(o);
Bretonisch
quelle
3
So kommt Python ohne switch-Anweisung aus.
Outis
2
Das Problem ist, dass immer alle Fälle ausgewertet werden.
Kornel
@porneL das ist wahr, aber es bringt einige Vorteile: Es ist logisch sauberer: Die Fälle sind Zeichenfolgen, die in einer Hashtabelle nachgeschlagen werden, keine Ausdrücke, die jeweils auf Gleichheit geprüft werden müssen, bis einer als wahr zurückgegeben wird. Während also mehr "Werte" ausgewertet werden, werden weniger "Schlüssel" ausgewertet. Objekte können dynamisch generiert und für eine spätere Skalierbarkeit geändert, zum Drucken der Benutzeroberfläche oder zum Generieren von Dokumenten verwendet und sogar durch eine dynamische Suchfunktion ersetzt werden, die besser ist als das Kopieren / Einfügen von Fällen. Es gibt keine Verwirrung über Unterbrechungen, Durchbrüche oder Standardwerte. Kann JSON serialisiert werden ...
Breton
@porneL oh yeah, und was die Skalierbarkeit betrifft, kann ein Objekt sogar einfach in eine externe Konfiguration oder Datendatei ausgegliedert werden. Dies ist eine etwas einfachere Änderung als bei einer switch-Anweisung. Aber trivial, wenn es zunächst für ein Objekt entworfen wurde mit.
Bretonischer
Ich weiß, dass dies ein verspäteter Eintrag ist, aber wenn Sie keine benutzerdefinierte Logik zur Typprüfung haben, wann wird ein Array jemals mit Ihrem Beispiel funktionieren? var arr = []; typeof arr; // object
Keeganwatkins
25

Stellen Sie sicher, dass Sie die hasOwnProperty- Methode verwenden, wenn Sie die Eigenschaften eines Objekts durchlaufen:

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

Dies geschieht so, dass Sie nur auf die direkten Eigenschaften von anObject zugreifen und nicht die Eigenschaften verwenden, die sich in der Prototypenkette befinden.

Andreas Grech
quelle
23

Private Variablen mit einer öffentlichen Schnittstelle

Es verwendet einen kleinen Trick mit einer selbstaufrufenden Funktionsdefinition. Alles innerhalb des zurückgegebenen Objekts ist in der öffentlichen Schnittstelle verfügbar, während alles andere privat ist.

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
quelle
1
Dies wird als Modulmuster bezeichnet, wie es von Eric Miraglia unter yuiblog.com/blog/2007/06/12/module-pattern genannt wurde. Ich denke, der Name ist irreführend, sollte als Singleton-Muster oder so ähnlich bezeichnet werden. Ich könnte auch hinzufügen, dass öffentliche Methoden auch andere öffentliche Methoden aufrufen können, indem sie 'this' verwenden. Ich verwende dieses Muster ständig in meinem Code, um die Dinge organisiert und sauber zu halten.
Mikeycgto