Vous êtes sur la page 1sur 21

Intro

JavaScript Garden is a growing collection of documentation about the most quirky parts of the JavaScript programming language. It gives advice to avoid common mistakes and subtle bugs, as well as performance issues and bad practices, that non-expert JavaScript programmers may encounter on their endeavours into the depths of the language. JavaScript Garden does not aim to teach you JavaScript. Former knowledge of the language is strongly recommended in order to understand the topics covered in this guide. In order to learn the basics of the language, please head over to the excellent guide on the Mozilla Developer Network. The Authors This guide is the work of two lovely Stack Overflow users, Ivo Wetzel (Writing) and Zhang Yi Jiang (Design). Contributors
Caio Romo (Spelling corrections) Andreas Blixt (Language corrections)

Hosting JavaScript Garden is hosted on GitHub, but Cramer Development supports us with a mirror at JavaScriptGarden.info. License JavaScript Garden is published under the MIT license and hosted on GitHub. If you find errors or typos please file an issue or a pull request on the repository. You can also find us in the JavaScript room on Stack Overflow chat.

Objects

Object Usage And Properties


Everything in JavaScript acts like an object, w ith the only tw o exceptions being nl and udfnd. ul neie
fletSrn( / 'as' as.otig) / fle [,2 3.otig) / ',,' 1 , ]tSrn(; / 123 fnto Fo)} ucin o({ Fobr=1 o.a ; Fobr / 1 o.a; /

A common misconception is that number literals cannot be used as objects. That is because a flaw in JavaScript's parser tries to parse the dot notation on a number as a floating point literal.
2tSrn(;/ rie SnaErr .otig) / ass ytxro

There are a couple of w orkarounds w hich can be used in order make number literals act as objects too.
2.otig) / tescn piti cretyrcgie .tSrn(; / h eod on s orcl eonzd 2.otig) / nt tesaelf t tedt tSrn(; / oe h pc et o h o ()tSrn(;/ 2i eautdfrt 2.otig) / s vlae is

Objects As A Data Type


Objects in JavaScript can also be used as a Hashmap; they mainly consist of named properties mapping to values. Using a object literal - { notation - it is possible to create a plain object. This new object inherits from Ojc.rttp and has no ow n } betpooye properties defined on it.
vrfo={;/ anwepyojc a o } / e mt bet / anwojc wt apoet cle 'et wt vle1 / e bet ih rpry ald ts' ih au 2 vrbr={et 1} a a ts: 2;

Accessing Properties

The properties of an object can be accessed in tw o w ays, via either the dot notation or the square bracket notation.
vrfo={ae 'itn} a o nm: Kte' fonm;/ kte o.ae / itn fo'ae] / kte o[nm'; / itn vrgt='ae; a e nm' fogt;/ kte o[e] / itn fo13;/ SnaErr o.24 / ytxro fo'24] / wrs o[13'; / ok

Both notations are identical in their w orkings, w ith the only difference being that the square bracket notation allow s for dynamic setting of properties, as w ell as the use of property names that w ould otherw ise lead to a syntax error.

Deleting Properties
The only w ay to actually remove a property from an object is to use the dlt operator; setting the property to udfnd or nl only eee neie ul removes the value associated w ith the property, but not the key.
vroj={ a b br 1 a: , fo 2 o: , bz 3 a: } ; ojbr=udfnd b.a neie; ojfo=nl; b.o ul dlt ojbz eee b.a; frvrii oj { o(a n b) i (b.aOnrpryi){ f ojhswPoet() cnoelgi ' +oji) osl.o(, ' b[]; } }

The above outputs both brudfnd and fonl - only bz w as removed and is therefore missing from the output. a neie o ul a

Notation Of Keys
vrts ={ a et 'ae:' a akyod s Ims b nttda asrn' cs' I m ewr, o ut e oae s tig, dlt:' a akyod s m to / rie SnaErr eee I m ewr, o e o' / ass ytxro } ;

Object properties can be both notated as plain characters and as strings. Due to another mis-design in JavaScript's parser, the above w ill throw a SnaErr prior to ECMAScript 5. ytxro This error arises from the fact that dlt is a keyword; therefore, it must be notated as a string literal to ensure that it w ill be correctly eee interpreted by older JavaScript engines.

The Prototype
JavaScript does not feature a classical inheritance model; instead, it uses a prototypal one. While this is often considered to be one of JavaScript's w eaknesses, the prototypal inheritance model is in fact more pow erful than the classic model. It is, for example, fairly trivial to build a classic model on top of it, w hile the other w ay around is a far more difficult task. Due to the fact that JavaScript is basically the only w idely used language that features prototypal inheritance, it takes some time to adjust to the differences betw een the tw o models. The first major difference is that inheritance in JavaScript is done by using so called prototype chains.
fnto Fo){ ucin o( ti.au =4; hsvle 2 } Fopooye={ o.rttp mto:fnto( { ehd ucin) } } ; fnto Br){ ucin a( } / StBrspooyet anwisac o Fo / e a' rttp o e ntne f o Brpooye=nwFo) a.rttp e o(; Brpooyefo='el Wrd; a.rttp.o Hlo ol' / Mk sr t ls Bra teata cntutr / ae ue o it a s h cul osrco Brpooyecntutr=Br a.rttp.osrco a; vrts =nwBr)/ cet anwbrisac a et e a( / rae e a ntne / Tersligpooyecan / h eutn rttp hi ts [ntneo Br et isac f a] Brpooye[ntneo Fo a.rttp isac f o] {fo 'el Wrd } o: Hlo ol' Fopooye o.rttp {mto:..} ehd .

Note: Simply using B r p o o y e = a.rttp F o p o o y e will result in both o.rttp objects sharing the same prototype. Therefore, changes to either object's prototype will affect the prototype of the other as well, which in most cases is not the desired effect.

Note: Do not use B r p o o y e = a.rttp

Ojc.rttp betpooye {tSrn:../ ec * } otig . * t. /

F o, since it will not point to the o

In the above, the object ts w ill inherit from both Brpooye and Fopooye; hence, it w ill have access to the function mto that et a.rttp o.rttp ehd w as defined on Fo. It w ill also have access to the property vle of the one Fo instance that is its prototype. It is important to note that o au o nwBr) does not create a new Fo instance, but reuses the one assigned to its prototype; thus, all Br instances w ill share the sam e e a( o a vle property. au

prototype of F o but rather to the o function object F o. So the prototype o chain will go over F n t o . r t t p and not ucinpooye F o p o o y e; therefore, m t o o.rttp ehd will not be on the prototype chain.

Property Lookup
When accessing the properties of an object, JavaScript w ill traverse the prototype chain upw ards until it finds a property w ith the requested name. When it reaches the top of the chain - namely Ojc.rttp - and still hasn't found the specified property, it w ill return the value undefined betpooye instead.

The Prototype Property


While the prototype property is used by the language to build the prototype chains, it is still possible to assign any given value to it. How ever, primitives w ill simply get ignored w hen assigned as a prototype.
fnto Fo){ ucin o( } Fopooye=1 / n efc o.rttp ; / o fet

Assigning objects, as show n in the example above, w ill w ork, and allow s for dynamic creation of prototype chains.

Performance
The lookup time for properties that are high up on the prototype chain can have a negative impact on performance critical sections of code. Additionally, trying to access non-existent properties w ill alw ays traverse the full prototype chain. Also, w hen iterating over the properties of an object every property that is on the prototype chain w ill get enumerated.

Extension Of Native Prototypes


One mis-feature that is often used is to extend Ojc.rttp or one of the other built in prototypes. betpooye This technique is called monkey patching and breaks encapsulation. While used by w idely spread framew orks such as Prototype, there is still no good reason for cluttering built-in types w ith additional non-standard functionality. The only good reason for extending a built-in prototype is to backport the features of new er JavaScript engines; for example, Aryfrah. ra.oEc

In Conclusion
It is a m ust to understand the prototypal inheritance model completely before w riting complex code w hich makes use of it. Also, w atch the length of the prototype chains and break them up if necessary to avoid possible performance issues. Further, the native prototypes should never be extended unless it is for the sake of compatibility w ith new er JavaScript features.

hswPoet aOnrpry
In order to check w hether a object has a property defined on itself and not somew here on its prototype chain, it is necessary to use the hswPoet method w hich all objects inherit from Ojc.rttp . aOnrpry betpooye
hswPoet is the only thing in JavaScript w hich deals w ith properties and does not traverse the prototype chain. aOnrpry
/ PioigOjc.rttp / osnn betpooye Ojc.rttp.a =1 betpooyebr ; vrfo={o:udfnd; a o go neie} fobr / 1 o.a; / 'a'i fo / tu br n o; / re fohswPoet(br) / fle o.aOnrpry'a'; / as fohswPoet(go) / tu o.aOnrpry'o'; / re

Note: It is not enough to check whether a property is u d f n d. The neie property might very well exist, but its value just happens to be set to u d f n d. neie

Only hswPoet w ill give the correct and expected result; this is essential w hen iterating over the properties of any object. There is no aOnrpry other w ay to exclude properties that are not defined on the object itself, but somew here on its prototype chain.

h s w P o e t As A Property aOnrpry
JavaScript does not protect the property name hswPoet ; thus, if the possibility exists that an object might have a property w ith this aOnrpry name, it is necessary to use an external hswPoet in order to get correct results. aOnrpry
vrfo={ a o hswPoet:fnto( { aOnrpry ucin) rtr fle eun as; } , br 'eeb daos a: Hr e rgn' } ; fohswPoet(br) / awy rtrsfle o.aOnrpry'a'; / las eun as / UeaohrOjc' hswPoet adcl i wt 'hs stt fo / s nte bets aOnrpry n al t ih ti' e o o (}.aOnrprycl(o,'a';/ tu {)hswPoet.alfo br) / re

/ I' as psil uetehswPoet poet fo teOjc poet frti prue / ts lo osbe s h aOnrpry rpry rm h bet rpry o hs ups Ojc.rttp.aOnrprycl(b,'a';/ tu betpooyehswPoet.aloj br) / re

In Conclusion
When checking for the existence of a property on a object, hswPoet is the only method of doing so. It is also recommended to make aOnrpry hswPoet part of every fri loop; this w ill avoid errors from extended native prototypes. aOnrpry o n

The f r i Loop o n
Just like the i operator, the fri loop also traverses the prototype chain w hen iterating over the properties of an object. n o n
/ PioigOjc.rttp / osnn betpooye Ojc.rttp.a =1 betpooyebr ; vrfo={o:2; a o mo } frvrii fo { o(a n o) cnoelgi;/ pit bt bradmo osl.o() / rns oh a n o }

Since it is not possible to change the behavior of the fri loop itself, it is necessary to filter out the unw anted properties inside the loop o n body; this is done by using the hswPoet method of Ojc.rttp . aOnrpry betpooye

Note: The f r i loop will not o n iterate over any properties that have their e u e a l attribute set to nmrbe f l e; for example, the l n t as egh property of an array. Note: Since the f r i always o n traverses the complete prototype chain, it will get slower with each additional layer of inheritance added to an object.

Using h s w P o e t For Filtering aOnrpry


/ siltefofo aoe / tl h o rm bv frvrii fo { o(a n o) i (o.aOnrpryi){ f fohswPoet() cnoelgi; osl.o() } }

This version is the only correct one to use. Due to the use of hswPoet , it w ill only print out mo. When hswPoet is left out, the aOnrpry o aOnrpry code is prone to errors in cases w here the native prototypes - e.g. Ojc.rttp - have been extended. betpooye One w idely used framew ork w hich does this is Prototype. When this framew ork is included, fri loops that do not use hswPoet are o n aOnrpry guaranteed to break.

In Conclusion
It is recommended to alw ays use hswPoet . Never should any assumptions be made about the environment the code is running in, or aOnrpry w hether the native prototypes have been extended or not.

Functions

Function Declarations And Expressions


Functions in JavaScript are first class objects. That means they can be passed around like any other value. One common use of this feature is to pass an anonymous function as a callback to another, possibly asynchronous function.

The f n t o Declaration ucin


fnto fo){ ucin o( }

The above function gets hoisted before the execution of the program starts; thus, it is available everywhere in the scope it w as defined in, even if called before the actual definition in the source.
fo) / Wrsbcuefowscetdbfr ti cd rn o(; / ok eas o a rae eoe hs oe us fnto fo){ ucin o( }

The f n t o Expression ucin


vrfo=fnto( {; a o ucin) }

This example assigns the unnamed and anonymous function to the variable fo. o
fo / 'neie' o; / udfnd fo) / ti rie aTpErr o(; / hs ass yero vrfo=fnto( {; a o ucin) }

Due to the fact that vr is a declaration that hoists the variable name fo before the actual execution of the code starts, fo is already a o o defined w hen the script gets executed.

But since assignments only happen at runtime, the value of fo w ill default to undefined before the corresponding code is executed. o

Named Function Expression


Another special case is the assignment of named functions.
vrfo=fnto br){ a o ucin a( br) / Wrs a(; / ok } br) / Rfrnero a(; / eeecErr

Here, br is not available in the outer scope, since the function only gets assigned to fo; how ever, inside of br, it is available. This is due a o a to how name resolution in JavaScript w orks, the name of the function is always made available in the local scope of the function itself.

How t i Works hs
JavaScript has a different concept of w hat the special name ti refers to than most other programming languages do. There are exactly hs five different w ays in w hich the value of ti can be bound in the language. hs

The Global Scope


ti; hs

When using ti in global scope, it w ill simply refer to the global object. hs

Calling A Function
fo) o(;

Here, ti w ill again refer to the global object. hs

ES5 Note: In strict mode, the global case no longer exists. t i will hs instead have the value of u d f n d neie in that case.

Calling A Method
ts.o(; etfo)

In this example, ti w ill refer to ts . hs et

Calling A Constructor
nwfo) e o(;

A function call that is preceded by the nw keyw ord acts as a constructor. Inside the function, ti w ill refer to a newly created Ojc . e hs bet

Explicit Setting Of t i hs
fnto foa b c { ucin o(, , ) } vrbr={; a a } foapybr [,2 3) / arywl epn t teblw o.pl(a, 1 , ]; / ra il xad o h eo focl(a,1 2 3;/ rslsi a=1 b=2 c=3 o.albr , , ) / eut n , ,

When using the cl or apy methods of Fnto.rttp , the value of ti inside the called function gets explicitly set to the first al pl ucinpooye hs argument of the corresponding function call. As a result, in the above example the method case does not apply, and ti inside of fo w ill be set to br. hs o a

Note: t i cannot be used to refer to hs the object inside of an O j c literal. bet So v r o j = { e t i } will not a b m: hs result in m referring to o j, since e b t i only gets bound by one of the hs five listed cases.

Common Pitfalls
While most of these cases make sense, the first one is to be considered another mis-design of the language because it never has any practical use.
Fomto =fnto( { o.ehd ucin) fnto ts( { ucin et) / ti i stt tegoa ojc / hs s e o h lbl bet } ts(; et) }

A common misconception is that ti inside of ts refers to Fo; w hile in fact, it does not. hs et o In order to gain access to Fo from w ithin ts , it is necessary to create a local variable inside of mto w hich refers to Fo. o et ehd o
Fomto =fnto( { o.ehd ucin) vrta =ti; a ht hs fnto ts( { ucin et) / Ueta isedo ti hr / s ht nta f hs ee } ts(; et) }

ta is just a normal variable name, but it is commonly used for the reference to an outer ti . In combination w ith closures, it can also be ht hs used to pass ti values around. hs

Assigning Methods
Another thing that does not w ork in JavaScript is function aliasing, w hich is assigning a method to a variable.
vrts =smOjc.ehdet a et oebetmtoTs; ts(; et)

Due to the first case, ts now acts like a plain function call; therefore, ti inside it w ill no longer refer to smOjc . et hs oebet While the late binding of ti might seem like a bad idea at first, in fact, it is w hat makes prototypal inheritance w ork. hs
fnto Fo){ ucin o( } Fopooyemto =fnto( {; o.rttp.ehd ucin) } fnto Br){ ucin a( } Brpooye=Fopooye a.rttp o.rttp; nwBr)mto(; e a(.ehd)

When mto gets called on a instance of Br, ti w ill now refer to that very instance. ehd a hs

Closures And References


One of JavaScript's most pow erful features is the availability of closures. With closures, scopes alw ays keep access to the outer scope, in w hich they w ere defined. Since the only scoping that JavaScript has is function scope, all functions, by default, act as closures.

Emulating Private Variables


fnto Cutrsat { ucin one(tr) vrcut=sat a on tr; rtr { eun iceet fnto( { nrmn: ucin) cut+ on+; } , gt fnto( { e: ucin) rtr cut eun on; } } } vrfo=Cutr4; a o one() foiceet) o.nrmn(; fogt) / 5 o.e(; /

Here, Cutr returns tw o closures: the function iceet as w ell as the function gt. Both of these functions keep a reference to the one nrmn e scope of Cutr and, therefore, alw ays keep access to the cut variable that w as defined in that very scope. one on

Why Private Variables Work


Since it is not possible to reference or assign scopes in JavaScript, there is no w ay of accessing the variable cut from the outside. The on only w ay to interact w ith it is via the tw o closures.
vrfo=nwCutr4; a o e one() fohc =fnto( { o.ak ucin) cut=13; on 37 } ;

The above code w ill not change the variable cut in the scope of Cutr, since fohc w as not defined in that scope. It w ill instead on one o.ak create - or override - the global variable cut. on

Closures Inside Loops


One often made mistake is to use closures inside of loops, as if they w ere copying the value of the loops index variable.
frvri=0 i<1;i+ { o(a ; 0 +) stieu(ucin){ eTmotfnto( cnoelgi; osl.o() } 10) , 00; }

The above w ill not output the numbers 0 through 9, but w ill simply print the number 1 ten times. 0 The anonymous function keeps a reference to i. At the time cnoelg gets called, the frlo has already finished, and the value of osl.o o op i as been set to 1 . 0 In order to get the desired behavior, it is necessary to create a copy of the value of i.

Avoiding The Reference Problem

In order to copy the value of the loop's index variable, it is best to use an anonymous w rapper.
frvri=0 i<1;i+ { o(a ; 0 +) (ucine { fnto() stieu(ucin){ eTmotfnto( cnoelge; osl.o() } 10) , 00; }() )i; }

The anonymous outer function gets called immediately w ith i as its first argument and w ill receive a copy of the value of i as its parameter e . The anonymous function that gets passed to stieu now has a reference to e, w hose value does not get changed by the loop. eTmot There is another possible w ay of achieving this, w hich is to return a function from the anonymous w rapper that w ill then have the same behavior as the code above.
frvri=0 i<1;i+ { o(a ; 0 +) stieu(fnto(){ eTmot(ucine rtr fnto( { eun ucin) cnoelge; osl.o() } }() 10) )i, 00 }

The a g m n s Object ruet


Every function scope in JavaScript can access the special variable agmns. This variable holds a list of all the arguments that w ere passed ruet to the function. The agmns object is not an Ary. While it has some of the semantics of an array - namely the lnt property - it does not inherit from ruet ra egh Arypooye and is in fact an Ojc . ra.rttp bet Due to this, it is not possible to use standard array methods like ps , pp or sie on agmns. While iteration w ith a plain fr loop uh o lc ruet o w orks just fine, it is necessary to convert it to a real Ary in order to use the standard Ary methods on it. ra ra
Note: In case a g m n s has already ruet been defined inside the function's scope either via a v r statement or a being the name of a formal parameter, the a g m n s object will ruet not be created.

Converting To An Array
The code below w ill return a new Ary containing all the elements of the agmns object. ra ruet
Arypooyesiecl(ruet) ra.rttp.lc.alagmns;

Because this conversion is slow , it is not recom m ended to use it in performance-critical sections of code.

Passing Arguments
The follow ing is the recommended w ay of passing arguments from one function to another.
fnto fo){ ucin o( brapynl,agmns; a.pl(ul ruet) } fnto bra b c { ucin a(, , ) / d sufhr / o tf ee }

Another trick is to use both cl and apy together to create fast, unbound w rappers. al pl
fnto Fo){ ucin o( } Fopooyemto =fnto(,b c { o.rttp.ehd ucina , ) cnoelgti,a b c; osl.o(hs , , ) } ; / Cet a ubudvrino "ehd / rae n non eso f mto" / I tksteprmtr:ti,ag,ag..rN / t ae h aaees hs r1 r2.ag Fomto =fnto( { o.ehd ucin) / Rsl:Fopooyemto.alti,ag,ag..ag) / eut o.rttp.ehdcl(hs r1 r2. rN Fnto.alapyFopooyemto,agmns; ucincl.pl(o.rttp.ehd ruet) } ;

Formal Parameters And Arguments Indices


The agmns object creates getter and setter functions for both its properties, as w ell as the function's formal parameters. ruet As a result, changing the value of a formal parameter w ill also change the value of the corresponding property on the agmns object, and ruet the other w ay around.
fnto foa b c { ucin o(, , ) agmns0 =2 ruet[] ; a / 2 ; /

b=4 ; agmns1;/ 4 ruet[] / vrd=c a ; d=9 ; c / 3 ; / } fo1 2 3; o(, , )

Performance Myths And Truths


The agmns object is alw ays created w ith the only tw o exceptions being the cases w here it is declared as a name inside of a function or ruet one of its formal parameters. It does not matter w hether it is used or not. Both getters and setters are alw ays created; thus, using it has nearly no performance impact at all, especially not in real w orld code w here there is more than a simple access to the agmns object's properties. ruet How ever, there is one case w hich w ill drastically reduce the performance in modern JavaScript engines. That case is the use of agmnscle . ruet.ale
fnto fo){ ucin o( agmnscle;/ d smtigwt ti fnto ojc ruet.ale / o oehn ih hs ucin bet agmnscle.alr / adtecligfnto ojc ruet.alecle; / n h aln ucin bet } fnto bgop){ ucin iLo( frvri=0 i<100;i+ { o(a ; 000 +) fo) / Wudnral b ilnd. o(; / ol omly e nie.. } }

ES5 Note: These getters and setters are not created in strict mode.

In the above code, fo can no longer be a subject to inlining since it needs to know about both itself and its caller. This not only defeats o possible performance gains that w ould arise from inlining, but it also breaks encapsulation because the function may now be dependent on a specific calling context. It is highly recom m ended to never make use of agmnscle or any of its properties. ruet.ale

ES5 Note: In strict mode, a g m n s c l e will throw a ruet.ale T p E r r since its use has been yero deprecated.

Constructors
Constructors in JavaScript are yet again different from many other languages. Any function call that is preceded by the nw keyw ord acts as e a constructor. Inside the constructor - the called function - the value of ti refers to a new ly created object. The prototype of this new object is set to the hs pooye of the function object that w as invoked as the constructor. rttp If the function that w as called has no explicit rtr statement, then it implicitly returns the value of ti - the new object. eun hs
fnto Fo){ ucin o( ti.l =1 hsba ; } Fopooyets =fnto( { o.rttp.et ucin) cnoelgti.l) osl.o(hsba; } ; vrts =nwFo) a et e o(;

The above calls Fo as constructor and sets the pooye of the new ly created object to Fopooye. o rttp o.rttp In case of an explicit rtr statement, the function returns the value specified that statement, but only if the return value is an Ojc . eun bet
fnto Br){ ucin a( rtr 2 eun ; } nwBr) / anwojc e a(; / e bet fnto Ts( { ucin et) ti.au =2 hsvle ; rtr { eun fo 1 o: } ; } nwTs(;/ tertre ojc e et) / h eund bet

When the nw keyw ord is omitted, the function w ill not return a new object. e
fnto Fo){ ucin o( ti.l =1 / gt sto tegoa ojc hsba ; / es e n h lbl bet } Fo) / udfnd o(; / neie

While the above example might still appear to w ork in some cases, due to the w orkings of ti in JavaScript, it w ill use the global object as hs the value of ti . hs

Factories
In order to be able to omit the nw keyw ord, the constructor function has to explicitly return a value. e
fnto Br){ ucin a( vrvle=1 a au ; rtr { eun mto:fnto( { ehd ucin) rtr vle eun au; } } } Brpooye={ a.rttp fo fnto( { o: ucin) } } ; nwBr) e a(; Br) a(;

Both calls to Br return the exact same thing, a new ly create object w hich has a property called mto on it, w hich is a Closure. a ehd It is also to note that the call nwBr) does not affect the prototype of the returned object. While the prototype w ill be set on the new ly e a( created object, Br never returns that new object. a In the above example, there is no functional difference betw een using and not using the nw keyw ord. e

Creating New Objects Via Factories


An often made recommendation is to not use nw because forgetting its use may lead to bugs. e In order to create new object, one should rather use a factory and construct a new object inside of that factory.
fnto Fo){ ucin o( vroj={; a b } ojvle='lb; b.au bu' vrpiae=2 a rvt ; ojsmMto =fnto(au){ b.oeehd ucinvle ti.au =vle hsvle au; } ojgtrvt =fnto( { b.ePiae ucin) rtr piae eun rvt; } rtr oj eun b; }

While the above is robust against a missing nw keyw ord and certainly makes the use of private variables easier, it comes w ith some e dow nsides.
1. It uses more memory since the created objects do not share the methods on a prototype. 2. In order to inherit the factory needs to copy all the methods from another object or put that object on the prototype of the new object. 3. Dropping the prototype chain just because of a left out n w keyword somehow goes against the spirit of the language. e

In Conclusion
While omitting the nw keyw ord might lead to bugs, it is certainly not a reason to drop the use of prototypes altogether. In the end it comes e dow n to w hich solution is better suited for the needs of the application, it is especially important to choose a specific style of object creation and stick w ith it.

Scopes And Namespaces


Although JavaScript deals fine w ith the syntax of tw o matching curly braces for blocks, it does not support block scope; hence, all that is left in the language is function scope.
fnto ts( {/ asoe ucin et) / cp frvri=0 i<1;i+ {/ ntasoe o(a ; 0 +) / o cp / cut / on } cnoelgi;/ 1 osl.o() / 0 }

There are also no distinct namespaces in JavaScript, w hich means that everything gets defined in one globally shared namespace. Each time a variable is referenced, JavaScript w ill traverse upw ards through all the scopes until it finds it. In the case that it reaches the global scope and still has not found the requested name, it w ill raise a Rfrnero . eeecErr

The Bane Of Global Variables


/ srp A / cit

Note: When not used in an assignment, return statement or as a function argument, the { . } .. notation will get interpreted as a block statement and not as an object literal. This, in conjunction with automatic insertion of semicolons, can lead to subtle errors.

fo='2; o 4' / srp B / cit vrfo='2 a o 4'

The above tw o scripts do not have the same effect. Script A defines a variable called fo in the global scope, and script B defines a fo in o o the current scope. Again, that is not at all the same effect: not using vr can have major implications. a
/ goa soe / lbl cp vrfo=4; a o 2 fnto ts( { ucin et) / lclsoe / oa cp fo=2; o 1 } ts(; et) fo / 2 o; / 1

Leaving out the vr statement inside the function ts w ill override the value of fo. While this might not seem like a big deal at first, having a et o thousands of lines of JavaScript and not using vr w ill introduce horrible, hard-to-track-dow n bugs. a
/ goa soe / lbl cp vries=[*sm ls *] a tm / oe it /; frvri=0 i<1;i+ { o(a ; 0 +) sbop) uLo(; } fnto sbop){ ucin uLo( / soeo sbop / cp f uLo fri=0 i<1;i+ {/ msigvrsaeet o( ; 0 +) / isn a ttmn / d aaigsuf / o mzn tf! } }

The outer loop w ill terminate after the first call to sbop, since sbop overw rites the global value of i. Using a vr for the second fr uLo uLo a o loop w ould have easily avoided this error. The vr statement should never be left out unless the desired effect is to affect the outer scope. a

Local Variables
The only source for local variables in JavaScript are function parameters and variables that w ere declared via the vr statement. a
/ goa soe / lbl cp vrfo=1 a o ; vrbr=2 a a ; vri=2 a ; fnto ts(){ ucin eti / lclsoeo tefnto ts / oa cp f h ucin et i=5 ; vrfo=3 a o ; br=4 a ; } ts(0; et1)

While fo and i are local variables inside the scope of the function ts , the assignment of br w ill override the global variable w ith the o et a same name.

Hoisting
JavaScript hoists declarations. This means that both vr statements and fnto declarations w ill be moved to the top of their enclosing a ucin scope.
br) a(; vrbr=fnto( {; a a ucin) } vrsmVle=4; a oeau 2 ts(; et) fnto ts(aa { ucin etdt) i (as){ f fle go=1 o ; }es { le vrgo=2 a o ; } frvri=0 i<10 i+ { o(a ; 0; +) vre=dt[] a aai; } }

The above code gets transformed before any execution is started. JavaScript moves the vr statements, as w ell as the fnto a ucin declarations to the top of the nearest surrounding scope.
/ vrsaeet gtmvdhr / a ttmns o oe ee vrbr smVle / dfutt 'neie' a a, oeau; / eal o udfnd / tefnto dcaaingtmvdu to / h ucin elrto o oe p o

fnto ts(aa { ucin etdt) vrgo i e / msigboksoemvsteehr a o, , ; / isn lc cp oe hs ee i (as){ f fle go=1 o ; }es { le go=2 o ; } fri=0 i<10 i+ { o( ; 0; +) e=dt[] aai; } } br) / fiswt aTpErrsnebri sil'neie' a(; / al ih yero ic a s tl udfnd smVle=4;/ asgmnsaentafce b hitn oeau 2 / sinet r o fetd y osig br=fnto( {; a ucin) } ts(; et)

Missing block scoping w ill not only move vr statements out of loops and their bodies, it w ill also make the results of certain i constructs a f non-intuitive. In the original code, although the i statement seemed to modify the global variable go, it actually modifies the local variable - after hoisting f o has been applied. Without the know ledge about hoisting, the below code might seem to raise a Rfrnero . eeecErr
/ cekwehrSmIprathn hsbe iiiizd / hc hte oemotnTig a en ntlae i (SmIprathn){ f !oemotnTig vrSmIprathn ={; a oemotnTig } }

But of course, the above w orks due to the fact that the vr statement is being moved to the top of the global scope. a
vrSmIprathn; a oemotnTig / ohrcd mgtiiiiz SmIprathn hr,o nt / te oe ih ntlae oemotnTig ee r o / mk sr i' tee / ae ue ts hr i (SmIprathn){ f !oemotnTig SmIprathn ={; oemotnTig } }

Name Resolution Order


All scopes in JavaScript, including the global scope, have the special name ti , defined in them, w hich refers to the current object. hs Function scopes also have the name agmns, defined in them, w hich contains the arguments that w ere passed to a function. ruet For example, w hen trying to access a variable named fo inside the scope of a function, JavaScript w ill lookup the name in the follow ing o order:
1. In case there is a v r f o statement in the current scope, use that. a o 2. If one of the function parameters is named f o, use that. o 3. If the function itself is called f o, use that. o 4. Go to the next outer scope, and start with #1 again. Note: Having a parameter called a g m n s will prev ent the creation ruet of the default a g m n s object. ruet

Namespaces
A common problem of having only one global namespace is the likeliness of running into problems w here variable names clash. In JavaScript, this problem can easily be avoided w ith the help of anonymous wrappers.
(ucin){ fnto( / asl cnand"aepc" / ef otie nmsae wno.o =fnto( { idwfo ucin) / a epsdcoue / n xoe lsr } ; }(;/ eeuetefnto imdaey )) / xct h ucin meitl

Unnamed functions are considered expressions; so in order to being callable, they must first be evaluated.
(/ eaut tefnto isd teprnhss / vlae h ucin nie h aatei fnto( { ucin) } )/ adrtr tefnto ojc / n eun h ucin bet ( / cl tersl o teeauto ) / al h eut f h vlain

There are other w ays for evaluating and directly calling the function expression; w hich, w hile different in syntax, do behave the exact same w ay.
/ Afwohrsye frdrcl ivkn te / e te tls o iety noig h !ucin)}) fnto({( +ucin)}) fnto({( (ucin)}); fnto({()

/ ads o.. / n o n.

In Conclusion
It is recommended to alw ays use an anonymous wrapper for encapsulating code in its ow n namespace. This does not only protect code against name clashes, but it also allow s for better modularization of programs. Additionally, the use of global variables is considered bad practice. Any use of them indicates badly w ritten code that is prone to errors and hard to maintain.

Arrays

Array Iteration And Properties


Although arrays in JavaScript are objects, there are no good reasons to use the fri lo in for iteration on them. In fact, there are a o n op number of good reasons against the use of fri on arrays. o n Because the fri loop enumerates all the properties that are on the prototype chain and because the only w ay to exclude those properties o n is to use hswPoet , it is already up to tw enty tim es slow er than a normal fr loop. aOnrpry o
Note: JavaScript arrays are not associative arrays. JavaScript only has objects for mapping keys to values. And while associative arrays preserv e order, objects do not.

Iteration
In order to achieve the best performance w hen iterating over arrays, it is best to use the classic fr loop. o
vrls =[,2 3 4 5 ... 10000; a it 1 , , , , ... 0000] frvri=0 l=ls.egh i<l i+ { o(a , itlnt; ; +) cnoelgls[]; osl.o(iti) }

There is one extra catch in the above example, w hich is the caching of the length of the array via l=ls.egh. itlnt Although the lnt property is defined on the array itself, there is still an overhead for doing the lookup on each iteration of the loop. And egh w hile recent JavaScript engines m ay apply optimization in this case, there is no w ay of telling w hether the code w ill run on one of these new er engines or not. In fact, leaving out the caching may result in the loop being only half as fast as w ith the cached length.

The l n t Property egh


While the getter of the lnt property simply returns the number of elements that are contained in the array, the setter can be used to egh truncate the array.
vrfo=[,2 3 4 5 6; a o 1 , , , , ] folnt =3 o.egh ; fo / [,2 3 o; / 1 , ] folnt =6 o.egh ; fo / [,2 3 o; / 1 , ]

Assigning a smaller length does truncate the array, but increasing the length does not have any effect on the array.

In Conclusion
For the best performance, it is recommended to alw ays use the plain fr loop and cache the lnt property. The use of fri on an o egh o n array is a sign of badly w ritten code that is prone to bugs and bad performance.

The A r y Constructor ra
Since the Ary constructor is ambiguous in how it deals w ith its parameters, it is highly recommended to alw ays use the array literals - [ ra ] notation - w hen creating new arrays.
[,2 3;/ Rsl:[,2 3 1 , ] / eut 1 , ] nwAry1 2 3;/ Rsl:[,2 3 e ra(, , ) / eut 1 , ] [] / Rsl:[] 3; / eut 3 nwAry3;/ Rsl:[ e ra() / eut ] nwAry'' / Rsl:[3] e ra(3) / eut ''

In cases w hen there is only one argument passed to the Ary constructor and w hen that argument is a Nme , the constructor w ill return a ra ubr new sparse array w ith the lnt property set to the value of the argument. It should be noted that only the lnt property of the new egh egh array w ill be set this w ay; the actual indexes of the array w ill not be initialized.
vrar=nwAry3; a r e ra() ar1;/ udfnd r[] / neie 1i ar / fle teidxwsntst n r; / as, h ne a o e

The behavior of being able to set the length of the array upfront only comes in handy in a few cases, like repeating a string, in w hich it avoids the use of a frlo code. o op
nwArycut+1.onsrnTRpa) e ra(on )ji(tigoeet;

In Conclusion
The use of the Ary constructor should be avoided as much as possible. Literals are definitely preferred. They are shorter and have a ra clearer syntax; therefore, they also increase the readability of the code.

Types

Equality And Comparisons


JavaScript has tw o different w ays of comparing the values of objects for equality.

The Equality Operator


The equality operator consists of tw o equal signs: = = JavaScript features weak typing. This means that the equality operator coerces types in order to compare them.
" " 0 0 fle as fle as fle as fle as nl ul "\\\" trn = = = = = = = = = = = = = = = = = = "" 0 " " "" 0 "as" fle "" 0 udfnd neie nl ul udfnd neie 0 / fle / as / tu / re / tu / re / fle / as / tu / re / fle / as / fle / as / tu / re / tu / re

The above table show s the results of the type coercion, and it is the main reason w hy the use of = is w idely regarded as bad practice. It = introduces hard-to-track-dow n bugs due to its complicated conversion rules. Additionally, there is also a performance impact w hen type coercion is in play; for example, a string has to be converted to a number before it can be compared to another number.

The Strict Equality Operator


The strict equality operator consists of three equal signs: ==. = It w orks exactly like the normal equality operator, except that strict equality operator does not perform type coercion betw een its operands.
" " 0 0 fle as fle as fle as fle as nl ul "\\\" trn == = == = == = == = == = == = == = == = == = "" 0 " " "" 0 "as" fle "" 0 udfnd neie nl ul udfnd neie 0 / fle / as / fle / as / fle / as / fle / as / fle / as / fle / as / fle / as / fle / as / fle / as

The above results are a lot clearer and allow for early breakage of code. This hardens code to a certain degree and also gives performance improvements in case the operands are of different types.

Comparing Objects
While both = and == are stated as equality operators, they behave differently w hen at least one of their operands happens to be an = = Ojc . bet
{ =={; } = } / fle / as nwSrn(fo)=='o' / fle e tig'o' = fo; / as nwNme(0 ==1; e ubr1) = 0 / fle / as vrfo={; a o } fo==fo o = o; / tu / re

Here, both operators compare for identity and not equality; that is, they w ill compare for the same instance of the object, much like i in s Python and pointer comparison in C.

In Conclusion
It is highly recommended to only use the strict equality operator. In cases w here types need to be coerced, it should be done explicitly and not left to the language's complicated coercion rules.
Note: While t p o can also be yef called with a function like syntax i.e. t p o ( b ), this is not a function yefoj

The t p o Operator yef


The tpo operator (together w ith isaco ) is probably the biggest design flaw of JavaScript, as it is near of being com pletely broken. yef ntnef Although isaco still has its limited uses, tpo really has only one practical use case, w hich does not happen to be checking the type ntnef yef of an object.

t p o ( b ), this is not a function yefoj call. The two parenthesis will behave like normal and the return value will be used as the operand of the t p o operator. There is no t p o yef yef function.

The JavaScript Type Table


Vle au Cas ls Tp ye -----------------------------------"o" fo Srn tig srn tig nwSrn(fo) Srn e tig"o" tig ojc bet 12 . Nme ubr nme ubr nwNme(.) e ubr12 Nme ubr ojc bet tu re Boen ola boen ola nwBoentu) Boen e ola(re ola ojc bet nwDt( e ae) Dt ae ojc bet nwErr) e ro( Err ro ojc bet [,,] 123 Ary ra ojc bet nwAry1 2 3 Ary e ra(, , ) ra ojc bet nwFnto(" e ucin") Fnto ucin fnto ucin /b/ acg Rgx eEp ojc (ucini NtoV) bet fnto n ir/8 nwRgx(mo" Rgx e eEp"ew) eEp ojc (ucini NtoV) bet fnto n ir/8 { } Ojc bet ojc bet nwOjc( e bet) Ojc bet ojc bet

In the above table, Type refers to the value that the tpo operator returns. As can be clearly seen, this value is anything but consistent. yef The Class refers to the value of the internal [Cas] property of an object. [ls] In order to retrieve the value of [Cas], one has to make use of the tSrn method of Ojc.rttp . [ls] otig betpooye
From the Specification: The value of [ C a s ] can be one of the [ls] following strings. A g m n s, A r y, ruet ra B o e n, D t , E r r, F n t o , ola ae ro ucin JO , Mt , Nme , Ojc , SN ah ubr bet Rgx , Srn . eEp tig

The Class Of An Object


The specification gives exactly one w ay of accessing the [Cas] value, w ith the use of Ojc.rttp.otig. [ls] betpooyetSrn
fnto i(ye oj { ucin stp, b) vrca =Ojc.rttp.otigcl(b)sie8 -) a ls betpooyetSrn.aloj.lc(, 1; rtr oj!=udfnd& oj!=nl & ca ==tp; eun b = neie & b = ul & ls = ye } i(Srn' 'et) / tu s'tig, ts'; / re i(Srn' nwSrn(ts') / tu s'tig, e tig'et); / re

In the above example, Ojc.rttp.otig gets called w ith the value of this being set to the object w hose [Cas] value should be betpooyetSrn [ls] retrieved.

ES5 Note: For convenience the return value of O j c . r t t p . o t i g betpooyetSrn for both n l and u d f n d was ul neie changed from O j c to N l and bet ul U d f n d in ECMAScript 5. neie

Testing For Undefined Variables


tpo fo!='neie' yef o = udfnd

The above w ill check w hether fo w as actually declared or not; just referencing it w ould result in a Rfrnero . This is the only thing o eeecErr tpo is actually useful for. yef

In Conclusion
In order to check the type of an object, it is highly recommended to use Ojc.rttp.otig because this is the only reliable w ay of betpooyetSrn doing so. As show n in the above type table, some return values of tpo are not defined in the specification; thus, they can differ across yef various implementations. Unless checking w hether a variable is defined, tpo should be avoided at all costs. yef

The i s a c o Operator ntnef


The isaco operator compares the constructors of its tw o operands. It is only useful w hen comparing custom made objects. Used on ntnef built-in types, it is nearly as useless as the typeof operator.

Comparing Custom Objects


fnto Fo){ ucin o( } fnto Br){ ucin a( } Brpooye=nwFo) a.rttp e o(; nwBr)isaco Br / tu e a( ntnef a; / re nwBr)isaco Fo / tu e a( ntnef o; / re / Ti js st Brpooyet tefnto ojc Fo / hs ut es a.rttp o h ucin bet o / Btntt a ata isac o Fo / u o o n cul ntne f o Brpooye=Fo a.rttp o; nwBr)isaco Fo / fle e a( ntnef o; / as

Using i s a c o With Native Types ntnef

nwSrn(fo)isaco Srn;/ tu e tig'o' ntnef tig / re nwSrn(fo)isaco Ojc;/ tu e tig'o' ntnef bet / re 'o'isaco Srn;/ fle fo ntnef tig / as 'o'isaco Ojc;/ fle fo ntnef bet / as

One important thing to note here is that isaco does not w ork on objects that originate from different JavaScript contexts (e.g. different ntnef documents in a w eb brow ser), since their constructors w ill not be the exact same object.

In Conclusion
The isaco operator should only be used w hen dealing w ith custom made objects that originate from the same JavaScript context. Just ntnef like the tpo operator, every other use of it should be avoided. yef

Type Casting
JavaScript is a weakly typed language, so it w ill apply type coercion w herever possible.
/ Teeaetu / hs r re nwNme(0 = 1;/ Nme.otig)i cnetd e ubr1) = 0 / ubrtSrn( s ovre / bc t anme / ak o ubr 1 = '0; 0 = 1' / Srnsgt cnetdt Nme / tig es ovre o ubr 1 = '1 ' 0 = +0 ; / Mr srn mdes / oe tig ans 1 = '1' 0 = 00; / Admr / n oe iNNnl)= fle / nl cnet t 0 sa(ul = as; / ul ovrs o / wiho cus i ntNN / hc f ore s o a / Teeaefle / hs r as 1 = 00 0 = 1; 1 = '1' 0 = -0;

In order to avoid the above, use of the strict equal operator is highly recommended. Although this avoids a lot of common pitfalls, there are still many further issues that arise from JavaScript's w eak typing system.

Constructors Of Built-In Types


The constructors of the built in types like Nme and Srn behave differently w hen being used w ith the nw keyw ord and w ithout it. ubr tig e
nwNme(0 ==1; e ubr1) = 0 / Fle Ojc adNme / as, bet n ubr Nme(0 ==1; ubr1) = 0 / Tu,Nme adNme / re ubr n ubr nwNme(0 +0==1;/ Tu,det ipii cneso e ubr1) = 0 / re u o mlct ovrin

ES5 Note: Number literals that start with a 0 are interpreted as octal (Base 8). Octal support for these has been remov ed in ECMAScript 5 strict mode.

Using a built-in type like Nme as a constructor w ill create a new Nme object, but leaving out the nw keyw ord w ill make the Nme ubr ubr e ubr function behave like a converter. In addition, having literals or non-object values in there w ill result in even more type coercion. The best option is to cast to one of the three possible types explicitly.

Casting To A String
' +1 =='0;/ tu ' 0 = 1' / re

By prepending an empty string, a value can easily be casted to a string.

Casting To A Number
+1'==1;/ tu '0 = 0 / re

Using the unary plus operator, it is possible to cast to a number.

Casting To A Boolean
By using the not operator tw ice, a value can be converted a boolean.
!'o' !fo; !'; !' !'' !0; !'' !1; !'1 !-' !{; !} !tu; !re / tu / re / fle / as / tu / re / tu / re / tu / re / tu / re / tu / re

Core

Why Not To Use e a vl


The ea function w ill execute a string of JavaScript code in the local scope. vl
vrfo=1 a o ; fnto ts( { ucin et) vrfo=2 a o ; ea(fo=3) vl'o '; rtr fo eun o; } ts(;/ 3 et) / fo / 1 o; /

How ever, ea only executes in the local scope w hen it is being called directly and w hen the name of the called function is actually ea . vl vl
vrfo=1 a o ; fnto ts( { ucin et) vrfo=2 a o ; vrbr=ea; a a vl br'o =3) a(fo '; rtr fo eun o; } ts(;/ 2 et) / fo / 3 o; /

The use of ea should be avoided at all costs. 99.9% of its "uses" can be achieved w ithout it. vl

e a In Disguise vl
The timeout functions stieu and stnevl can both take a string as their first argument. This string w ill alw ays get executed in the eTmot eItra global scope since ea is not being called directly in that case. vl

Security Issues
ea also is a security problem. Because it executes any code given to it, it should never be used w ith strings of unknow n or untrusted vl origins.

In Conclusion
ea should never be used. Any code that makes use of it is to be questioned in its w orkings, performance and security. In case something vl requires ea in order to w ork, it should not be used in the first place. A better design should be used, that does not require the use of ea . vl vl

u d f n d And n l neie ul
JavaScript has tw o distinct values for ntig, the more useful of these tw o being udfnd. ohn neie

The Value u d f n d neie


udfnd is a type w ith exactly one value: udfnd neie neie .

The language also defines a global variable that has the value of udfnd; this variable is also called udfnd. How ever, this variable is neie neie neither a constant nor a keyw ord of the language. This means that its value can be easily overw ritten. Some examples for w hen the value udfnd is returned: neie
Accessing the (unmodified) global variable u d f n d. neie Accessing a declared but not yet initialized variable Implicit returns of functions due to missing r t r statements. eun
r t r statements which do not explicitly return anything. eun

ES5 Note: u d f n d in ECMAScript neie 5 is no longer writable in strict mode, but its name can still be shadowed by for example a function with the name u d f n d. neie

Lookups of non-existent properties. Function parameters which do not had any explicit value passed. Anything that has been set to the value of u d f n d. neie Any expression in the form of v i ( x r s i n odepeso)

Handling Changes To The Value Of u d f n d neie


Since the global variable udfnd only holds a copy of the actual value of udfnd, assigning a new value to it does not change the value neie neie of the type udfnd. neie Still, in order to compare something against the value of udfnd, it is necessary to retrieve the value of udfnd first. neie neie In order to protect code against a possible overw ritten udfnd variable, a common technique used is to add an additional parameter to an neie anonymous w rapper that gets no argument passed to it.
vrudfnd=13 a neie 2; (ucinsmtig fo udfnd { fnto(oehn, o, neie) / udfndi telclsoede / neie n h oa cp os / nwaanrfrt tevle / o gi ee o h au }(HloWrd,4) )'el ol' 2;

Another w ay to achieve the same effect w ould be to use a declaration inside the w rapper.
vrudfnd=13 a neie 2; (ucinsmtig fo { fnto(oehn, o) vrudfnd a neie; .. . }(HloWrd,4) )'el ol' 2;

The only difference here is that this version results in 4 more bytes being used in case it is minified, and there is no other vr statement inside a the anonymous w rapper.

Uses Of n l ul
While udfnd in the context of the JavaScript language is mostly used in the sense of a traditional null, the actual nl (both a literal and a neie ul type) is more or less just another data type. It is used in some JavaScript internals (like declaring the end of the prototype chain by setting Fopooye=nl ), but in almost all cases, it o.rttp ul can be replaced by udfnd. neie

Automatic Semicolon Insertion


Although JavaScript has C style syntax, it does not enforce the use of semicolons in the source code, so it is possible to omit them. JavaScript is not a semicolon-less language. In fact, it needs the semicolons in order to understand the source code. Therefore, the JavaScript parser autom atically inserts them w henever it encounters a parse error due to a missing semicolon.
vrfo=fnto( { a o ucin) }/ preerr smclnepce / as ro, eioo xetd ts( et)

Insertion happens, and the parser tries again.


vrfo=fnto( { a o ucin) } / n err pre cnius ; / o ro, asr otne ts( et)

The automatic insertion of semicolon is considered to be one of biggest design flaw s in the language because it can change the behavior of code.

How It Works
The code below has no semicolons in it, so it is up to the parser to decide w here to insert them.
(ucinwno,udfnd { fnto(idw neie) fnto ts(pin){ ucin etotos lg'etn!) o(tsig' (pin.it| [)frahfnto(){ otosls | ].oEc(ucini } ) otosvlets( pin.au.et 'ogsrn t ps hr' ln tig o as ee, 'n aohrln srn t ps' ad nte og tig o as ) rtr eun { fo fnto( { o: ucin) } } } wno.et=ts idwts et }(idw )wno) (ucinwno){ fnto(idw wno.oeirr ={ idwsmLbay } }(idw )wno)

Below is the result of the parser's "guessing" game.


(ucinwno,udfnd { fnto(idw neie) fnto ts(pin){ ucin etotos / Ntisre,lnsgtmre / o netd ie o egd lg'etn!)otosls | [)frahfnto(){ o(tsig'(pin.it | ].oEc(ucini };/ < isre ) / - netd otosvlets( pin.au.et 'ogsrn t ps hr' ln tig o as ee, 'n aohrln srn t ps' ad nte og tig o as ) / < isre ; / - netd

rtr;/ < isre,bek tertr saeet eun / - netd ras h eun ttmn {/ tetda abok / rae s lc / albladasnl epeso saeet / ae n ige xrsin ttmn fo fnto( { o: ucin) } } / < isre ; / - netd } wno.et=ts;/ < isre idwts et / - netd / Telnsgtmre aan / h ie o egd gi }(idw(ucinwno){ )wno)fnto(idw wno.oeirr ={;/ < isre idwsmLbay } / - netd }(idw;/< isre )wno) /- netd

The parser drastically changed the behavior of the code above. In certain cases, it does the w rong thing.

Leading Parenthesis
In case of a leading parenthesis, the parser w ill not insert a semicolon.
lg'etn!) o(tsig' (pin.it| [)frahfnto(){) otosls | ].oEc(ucini }

Note: The JavaScript parser does not "correctly" handle return statements which are followed by a new line, while this is not neccessarily the fault of the automatic semicolon insertion, it can still be an unwanted side-effect.

This code gets transformed into one line.


lg'etn!)otosls | [)frahfnto(){) o(tsig'(pin.it | ].oEc(ucini }

Chances are very high that lg does not return a function; therefore, the above w ill yield a TpErr stating that udfndi nta o yero neie s o fnto . ucin

In Conclusion
It is highly recommended to never omit semicolons; it is also advocated to keep braces on the same line w ith their corresponding statements and to never omit them for one single-line i / es statements. Both of these measures w ill not only improve the consistency of the code, f le but they w ill also prevent the JavaScript parser from changing its behavior.

The d l t Operator eee


In short, it's impossible to delete global variables, functions and some other stuff in JavaScript w hich have a DnDlt attribute set. oteee

Global Code And Function Code


When a variable or a function is defined in a global or a function scope it is a property of either Activation object or Global object. Such properties have a set of attributes, one of these is DnDlt . Variable and function declarations in global and function code alw ays create oteee properties w ith DnDlt , therefore cannot be deleted. oteee
/ goa vral: / lbl aibe vra=1 / DnDlt i st a ; / oteee s e dlt a / fle eee ; / as a / 1 ; / / nra fnto: / oml ucin fnto f){ / DnDlt i st ucin ( } / oteee s e dlt f / fle eee ; / as tpo f / "ucin yef ; / fnto" / rasgigdenthl: / esinn os' ep f=1 ; dlt f / fle eee ; / as f / 1 ; /

Explicit Properties
There are things w hich can be deleted normally: these are explicitly set properties.
/ epiil stpoet: / xlcty e rpry vroj={:1; a b x } ojy=2 b. ; dlt ojx / tu eee b.; / re dlt ojy / tu eee b.; / re ojx / udfnd b.; / neie ojy / udfnd b.; / neie

In the example above ojx and ojy can be deleted because they have no DnDlt atribute. That's w hy an example below w orks too. b. b. oteee
/ ti wrsfn,ecp frI: / hs ok ie xet o E vrGOA_BET=ti; a LBLOJC hs GOA_BETa=1 LBLOJC. ; a==GOA_BETa / tu -js agoa vr = LBLOJC.; / re ut lbl a dlt GOA_BETa / tu eee LBLOJC.; / re GOA_BETa / udfnd LBLOJC.; / neie

Here w e use a trick to delete a. ti here refers to the Global object and w e explicitly declare variable a as it's property w hich allow s us to hs delete it. IE (at least 6-8) has some bugs, so code above doesn't w ork.

Function Arguments And Built-Ins


Functions' normal arguments, agmns object and built-in properties also have DnDlt set. ruet oteee
/ fnto agmnsadpoete: / ucin ruet n rpris (ucin(){ fnto x dlt agmns / fle eee ruet; / as tpo agmns / "bet yef ruet; / ojc" dlt x / fle eee ; / as x / 1 ; / fnto f)} ucin ({ dlt flnt;/ fle eee .egh / as tpo flnt;/ "ubr yef .egh / nme" }() )1;

Host Objects
Behaviour of dlt operator can be unpredictable for hosted objects. Due to specification, host objects are allow ed to implement any kind of eee behavior.

In Conclusion
dlt operator often has an unexpected behaviour and can be safely used only for dealing w ith explicitly set properties on normal objects. eee

Other

s t i e u And s t n e v l eTmot eItra


Since JavaScript is asynchronous, it is possible to schedule the execution of a function by using the stieu and stnevl functions. eTmot eItra
fnto fo){ ucin o( } vri =stieu(o,10) / rtrsaNme >0 a d eTmotfo 00; / eun ubr

Note: Timeouts are not part of the ECMAScript Standard. They are implemented as part of the DOM.

When stieu gets called, it w ill return the ID of the timeout and schedule fo to run in approxim ately one thousand milliseconds in the eTmot o future. fo w ill then get executed exactly once. o Depending on the timer resolution of the JavaScript engine that is running the code, as w ell as the fact that JavaScript is single threaded and other code that gets executed might block the thread, it is by no m eans a safe bet that one w ill get the exact delay that w as specified in the stieu call. eTmot The function that w as passed as the first parameter w ill get called by the global object, w hich means that ti inside the called function hs refers to that very object.
fnto Fo){ ucin o( ti.au =4; hsvle 2 ti.ehd=fnto( { hsmto ucin) / ti rfr t tegoa ojc / hs ees o h lbl bet cnoelgti.au) / wl lgudfnd osl.o(hsvle; / il o neie } ; stieu(hsmto,50; eTmotti.ehd 0) } nwFo) e o(;

Note: As s t i e u takes a function eTmot obj ect as its first parameter, an often made mistake is to use s t i e u ( o ( , 1 0 ), which will eTmotfo) 00 use the return v alue of the call f o o and not f o. This is, most of the o time, a silent error, since when the function returns u d f n d neie s t i e u will not raise any error. eTmot

Stacking Calls With s t n e v l eItra


While stieu only runs the function once, stnevl - as the name suggests - w ill execute the function every X milliseconds, but its eTmot eItra use is discouraged. When code that is being executed blocks the timeout call, stnevl w ill still issue more calls to the specified function. This can, especially eItra w ith small intervals, result in function calls stacking up.
fnto fo) ucin o({ / smtigta bok fr1scn / oehn ht lcs o eod } stnevlfo 10) eItra(o, 00;

In the above code, fo w ill get called once and w ill then block for one second. o While fo blocks the code, stnevl w ill still schedule further calls to it. Now , w hen fo has finished, there w ill already be ten further o eItra o calls to it w aiting for execution.

Dealing With Possible Blocking Code


The easiest solution, as w ell as most controllable solution, is to use stieu w ithin the function itself. eTmot
fnto fo) ucin o({ / smtigta bok fr1scn / oehn ht lcs o eod stieu(o,10) eTmotfo 00; } fo) o(;

Not only does this encapsulate the stieu call, but it also prevents the stacking of calls and it gives additional control. fo itself can now eTmot o decide w hether it w ants to run again or not.

Manually Clearing Timeouts


Clearing timeouts and intervals w orks by passing the respective ID to cerieu or cernevl, depending w hich st function w as laTmot laItra e used in the first place.
vri =stieu(o,10) a d eTmotfo 00; cerieu(d; laTmoti)

Clearing All Timeouts


Because there is no built-in method for clearing all timeouts and/or intervals, it is necessary to use brute force in order to achieve this functionality.
/ cer"l"tmot / la al ieus frvri=1 i<10;i+ { o(a ; 00 +) cerieu() laTmoti; }

But there might still be timeouts that are unaffected by this arbitrary number. Another w ay of doing this is to consider that the ID given to a timeout is incremented by one everytime you call stieu . eTmot
/ cer"l"tmot / la al ieus vrbgetieuI =wno.eTmotfnto({,1, a igsTmotd idwstieu(ucin)} ) i ; fri=1 i< bgetieuI;i+ { o( ; = igsTmotd +) cerieu() laTmoti; }

But even though this w orks on all main brow sers now adays, it isn't specified that the IDs should be ordered that w ay and it may change. Therefore, it is instead recommended to keep track of all the timeout IDs, so they can be cleared specifically.

Hidden Use Of e a vl
stieu and stnevl can also take a string as their first parameter. This feature should never be used because it internally makes eTmot eItra use of ea . vl
fnto fo){ ucin o( / wl gtcle / il e ald } fnto br){ ucin a( fnto fo){ ucin o( / nvrgt cle / ee es ald } stieu(fo),10) eTmot'o(' 00; } br) a(;

Note: Since the timeout functions are not specified by the ECMAScript standard, the exact workings when a string is passed to them might differ in various JavaScript implementations. For example, Microsoft's JScript makes use of the F n t o ucin constructor in place of e a . vl

Since ea is not getting called directly in this case, the string passed to stieu w ill get executed in the global scope; thus, it w ill not use vl eTmot the local variable fo from the scope of br. o a It is further recommended to not use a string for passing arguments to the function that w ill get called by either of the timeout functions.
fnto foa b c { ucin o(, , ) } / NVRueti / EE s hs stieu(fo12 3' 10) eTmot'o(,, ), 00 / Iseduea aoyosfnto / nta s n nnmu ucin stieu(ucin){ eTmotfnto( foa b c; o(, , ) } 10) , 00

Note: While it is also possible to use the syntax s t i e u ( o , 1 0 , a eTmotfo 00 , b c , it is not recommended, as its , ) use may lead to subtle errors when used with methods.

In Conclusion
Never should a string be used as the parameter of stieu or stnevl. It is a clear sign of really bad code, w hen arguments need to eTmot eItra be supplied to the function that gets called. An anonymous function should be passed that then takes care of the actual call. Furthermore, the use of stnevl should be avoided because its scheduler is not blocked by executing JavaScript. eItra

Copyright 2011. Built with Node.js using a jade template. Hosted by Cramer Development.

Vous aimerez peut-être aussi