Comments None

All our attempts to achieve ideal code are actually about trade-offs. Unfortunately, sometimes one is influenced by hype.

I'd like to talk about reduce, which is gaining popularity with various libraries and whatnot. Redux, which is a "state container" based mostly on reduce abstraction. Another example is transducers, which made their way into JavaScript from closure. Incidentally, I consider the implementation no more than just a trade-off: you gain in performance (less GC thrashing), but lose a little in readability.

These are cool things and they have their applications in some cases, but reduce abstraction comes with a cost and shouldn't be used just because it's cool.

  1. Reduce is hard to comprehend. Not nearly as hard as e.g. monads (which is burrito), but such operation isn't what developers use often in their work and hence it's not JIT-optimized in their brains.

  2. Reduce in JavaScript is hard to parse. Of course, I'm talking about parsing by meatware. Normally we read JavaScript code from left to right thanks mostly to chaining, promoted in front-end land by jQuery (which is monad and therefore a burrito). But initial value for the reduce function is the last argument. This is especially a problem when reduce is deeply nested inside the code. Let's look at the code from a recent jstip.

var combineTotalPriceReducers = function(reducers) { // (1)
  return function(state, item) { // (2)
    return Object.keys(reducers).reduce( // (3), ouch this is a reduce
                                         // let's look for initial value
      function(nextState, key) { // (5)
        reducers[key](state, item); // (6)
        return state; // (7)
      {} // (4) here it is, let's go back

Such jumps drastically reduce (no pun intended) our ability to quickly look through the code, which is important. If you're not convinced – think: what is the most infamous thing in programming? I'd say, goto, which requires us to leap through the code like an injured frog. From reading perspective reduce pattern might be as bad as a couple of gotos.

So back to the example. Here reduce is abused. Return value is discarded. Twice: (6) and (7). On top of that, neither nextState (5) nor initial value (4) is used. It's just as unsemantical as using map instead of forEach, for bare iteration.

Actually the code from the js-pieceof-tip could be rewritten as:

let addPrice =
  (currency, exchangeRate) =>
    (state, item) => state[currency] += item.price * exchangeRate;
visitors = [ // rewritten to array for simpler iteration, still easy to read
  addPrice('dollars', 1),
  addPrice('euros', 0.897424392),
  addPrice('pounds', 0.692688671),
  addPrice('yens', 113.852)

let applyAllPriceVisitors = (visitors) =>
  (state, item) => visitors.forEach(visitor =>
    visitor(state, item));

  ({dollars: 0, euros:0, yens: 0, pounds: 0}, {price: 10});

"Visitor" might be not the best name here, but neither is reducer.

So when to use reduce considering all its disadvantages? In functional programming where you have only pure functions and passing values through the chain of reduce's callback is the only way to keep state. If we have used immutable collections, then the example can be written as:

let addPrice =
  (currency, exchangeRate) =>
    (state, item) => state.update(currency, v => v + item.price * exchangeRate);
reducers = [ // rewritten to array for simpler iteration, still easy to read
  addPrice('dollars', 1),
  addPrice('euros', 0.897424392),
  addPrice('pounds', 0.692688671),
  addPrice('yens', 113.852)

let applyAllPriceReducers = (reducers) =>
  (initial, item) => reducers.reduce(
    reducer => reducer(state, item),

  (Immutable.Map({dollars: 0, euros:0, yens: 0, pounds: 0}), {price: 10});

BTW partially applied applyAllPriceReducers(reducers) is itself a suitable pure function for reducer. But this is another story.

Don't use reduce just because it's cool. Tame the hype. Learn your tools and use appropriately.


Comments None

In JavaScript we have two kind of quotes at our disposal for strings. Most style guides either favors single quotes or implies no limitations but consistency. One might come up with a lot of arguments for each side.

To be honest all of them are either far-fetched or have corresponding counter-arguments. Pieces of HTML as well as messages (which often have single quotes) should mostly reside in script-blocks or separate files and making extra escape for a few strings in the whole app won't work one's fingers to the bone. After all, it's 2015 now, we can use es6 template strings!

There's a misconception I'd like to point out here: "(single|double) quotes eliminate the need to escape (double|single) quotes". Nope! Most strings can have both types: '27" apple cinema display', "levi's jeans". Message can have both single quotes as apostrophe as well as quotes for Press "escape 'em all" button to achieve the desired effect. This is mostly related to generation of HTML as strings, which happens more often on back-end, but nonetheless.

So, to the main point. What I think is that using only one type of quotes is somewhat limiting. I've spontaneously come to the following usage of quotes in JavaScript. In short, I prefer single quotes in cases where options are limited. A notable example is event types. There are only a few dozen event types: click, submit and so on. Semantically those can be considered as an enumeration. On the other side there are strings where the number of combinations is virtually limitless. Two things, which come to mind are inline text resources (logging messages are OK in that role) and mini-templates.

Another interesting idea by @medikoo how to tap into having two types of quotes in the language from the article I mentioned above:

Single quotes for internal strings and double for external.

So mostly people prefer what I'd call "cheap-and-dirty" solution: use only one type to reduce cognitive load, but this isn't the only answer to this question. What do you think? Will adding semantic to different types of quotes and using both of them simultaneously pay off?


Comments None

Updated on 23. June 2014

Last weekend I watched a video about Java8 and Nashorn. This is a much faster successor to Rhino by Oracle. They claimed to have passing all of more than 11000 tests of es5 spec, even though no browser vendor made compatibility to so scrupulous degree. The presentation was from late 2012, hence I decided to check, how things are going for now. You can run them by yourself here, but I already did that for most popular browsers and even not popular ones. And moreover, I found that tests often fail not because of the feature in description is implemented incorrectly. Simpler, some tests are not independent. Extrapolating that to all tests would be an survival bias. Hence I'm not saying all tests are badly written. But if one wants to interpret the fact of test fail, reading description is not enough. On the bad note, though, a pair of tests are out of tune with specification. They expect some certain behavior, when it is clearly stated that it may be implementation-dependent.
Here's a hg repo viewer, where separate tests could be found.


If you don't want to go deep into details about different tests and my rants about their quality, here's a list what you'd better not to do from es5:

  • test your code in different browsers, even if you're using bulletproof library like jQuery - these tests themselves couldn't be run in IE8 due to bug in UI
  • in Firefox one cannot change numerical properties on window
  • in Firefox [[Writable]], [[Configurable]] and [[Enumerable]] are incorrectly set to false when not provided in re-defining properties on window - just pass them for every defineProperty call.
  • do not rely on features of strict mode. For example, sometimes primitives used as this are still wrapped into objects - in special cases or in browsers (IE9) which, do not support strict mode at all. I personally faced a bug emerged from combination of jQuery.each on array of primitives and using strict equality for this.
    Using strict mode as a helper for early problem detection is encouraged, though.
  • do not rely exclusively on feature presence - some implementations are rather buggy - e.g. defineProperty in Safari 5
  • IE before 11th use slightly different representation for Date.toString, hence do not rely on exact values.
  • some old browsers still parse strings as octal numbers, starting from zero - use parseInt(n, 10) or Number(n) if you're sure there're no trailing characters.
  • String.prototype.localeCompare returns incorrect results for non-canonical Unicode representations in many browsers
  • do no not rely on assumption that code will fail at some certain point with some certain error. This is mostly OK for tests, though.
  • hardly one would use that in real code, but messing with numeric properties on Array.prototype is not only difficult to understand, but is also vulnerable to subtle differences in implementations

Detailed analysis of failed tests

Listing full test names could be too "noisy" for visual perception, hence I compacted several names with syntax similar to imports in es6. E.g.: "1.1.2, 1.1.3" is written as "1.1.{2,3}".

First of all I need to mention, that six Date tests do not fail if and only if you live California or elsewhere near. Relax, it is neither discrimination, nor location tracking - just OS setting, timezone should be UTC-8.

Tests that String.prototype.localeCompare returns 0 when comparing Strings that are considered canonically equivalent by the Unicode standard

All browsers except Chrome and Firefox 29 beta fails that test.
Interesting enough, strings from test case ("\u1111\u1171\u11B6" vs "\ud4db") are even displayed differently in FF29- (and strangely Chrome33-34): the first string looks like linear Hangul, whilst the second one is normal Jamo:
퓛 vs

OK, mainstream browsers go first in some arbitrary order.

Chrome 32+


Call arguments are not evaluated before the check is made to see if the object is actually callable (undefined member)

I.e. in expression ({}).b(f()); engine should call f() before .b is evaluated and detected as non-callable, whilst for ({}).a.b(f()); browser should not call f(). In the second case Chrome incorrectly calls f() as well.


Checking if Math.exp is approximately equals to its mathematical values on the set of 64 argument values; all the sample values is calculated with LibC

Chrome35 have similar bugs in 3 more tests.

The relative error is 2-50, while precision of IEEE754 doubles used in javascript, is 52 bits. So this error hardly matters, unless you're doing a REAL SCIENCE. Moreover, specification [15.8.2] doesn't impose any certain requirements on computation accuracy for math functions:

The behaviour of the functions acos, asin, atan, atan2, cos, exp, log, pow, sin, sqrt, and tan is not precisely specified here except to require specific results for certain argument values that represent boundary cases of interest. For other argument values, these functions are intended to compute approximations to the results of familiar mathematical functions, but some latitude is allowed in the choice of approximation algorithms.

Test itself is rather arguable. Are those approximations enough or not? Even if this is a problem, it's not a big one.

Safari 7 (MacOS/iOS){16,18}-s
TypeError should be thrown when changing global.NaN or global.undefined in strict mode.

Safari 6 (iOS)

Surprisingly it doesn't fail the previous test.

eval within global execution context - scopes are not chained properly

Tests that String.prototype.localeCompare treats a missing "that" argument, undefined, and "undefined" as equivalent.

str.localeCompare(), str.localeCompare(undefined) and str.localeCompare("undefined") should be the same for any possible value of str.

Firefox 27-33


Strict mode should not ToObject thisArg if not an object.

In es3 and non-strict es5, primitive passed as this, are wrapped into object (String, Number or Boolean). In strict mode primitives should not be unwrapped. This works in general wherever strict mode is enabled and supported.
In getter, defined on Object.prototype and used on primitive value (via boxing), this still should be a primitive. And this is where Firefox fails.

Actually, if you write cross-browser code, you shouldn't rely on aforementioned feature of strict mode.

Error.prototype.toString return empty string when 'name' is empty string and 'msg' is undefined

FF returns "Error" if name is empty. Not a serious bug, again.

Numerous bugs with Object.defineProperty.

Sometimes (6 from{292-296}) checks interfere with implementation details of mapping between arguments object and actual named arguments like this:

(function (a) {
    Object.defineProperty(arguments, '0', { value: 2 });
    return a;

BTW in strict mode all browsers demonstrate the same behavior as Firefox.

-354-4, -354-13, -360-3, -360-7, -531-4, -531-13, -538-3, -538-7 and
In these cases there's really an error. All 3 properties: writable, enumerable and configurable become false on re-definition if they're not provided. This is detected on window only and doesn't happen for normal objects. -531-17 and -538-7 fails even earlier due to inability to redefine numerical properties on window.

Problems with Array.prototype methods applied to global object.
The same reason as just mentioned - it fails because one cannot declare numerical keys on window - they continue to be undefined.

Actually, every method of Array.prototype has a NOTE like:

The reduce function is intentionally generic; it does not require that its this value be an Array object. Therefore it can be transferred to other kinds of objects for use as a method. Whether the reduce function can be applied successfully to a host object is implementation-dependent.

I.e. spec doesn't require ability to successfully apply those methods to host objects! So tests are just incorrect.


[[Prototype]] of Array instance is Array.prototype, [[Prototype] of Array.prototype is Object.prototype

This test fails due to implementation details of concat (not own property remains not own in Firefox).

Array.prototype.concat will concat an Array when index property (read-only) exists in Array.prototype (Step 5.c.i)

It fails because[0] results in number primitive, and not Number object. The check of copy's properties existence actually passes.


The latest 11th version fails only one test about localeCompare


IE11 in IE10 emulation mode shows the same behavior.

It fails one more test, which is rather funny:
Fails for eastern hemisphere (UTC+N timezones), cause IE does not display leading zeroes for dates: new Date(0).toString() → "Thu Jan 1 04:00:00 UTC+0400 1970"
Yeah, it sounds so arcane, but check in code is really like that:
(date.indexOf(date.getTimezoneOffset()>0 ? '31' : '01')) === 8
One way or another, it reveals a piece of non-standard behavior of IE.


IE9 fails significantly more tests additionally to aforementioned two. And true IE9 shows results somewhat different from higher versions in corresponding emulation mode (surprise-surprise). The only good point about that is that both emulation modes (IE11@9 and IE10@9) works the same.
Of course, it also can't pass 500+ tests about strict mode. I didn't even check 'em all - just filtered out.

8.12.9-9-c-i_{1,2} (passes in emulation mode)

Redefine a configurable accessor property to be a data property on a non-extensible object

with preventExtensions.

10.6-13-a-2 (passes in emulation mode)

A direct call to arguments.callee.caller should work

(function (called) {
    function test1(flag) { if (!flag) test2(); else called = true; }
    function test2() { arguments.callee.caller(true); }
    return called;   

Rather tricky and strange.


Call arguments are evaluated before the check is made to see if the object is actually callable.

It fails differently than in Chrome.


Error.prototype.{name,message} are not enumerable{1,2}

Using Object.prototype.valueOf for non-object values

Expected result: primitive value should be wrapped into corresponding object. Workaround: if you need to wrap primitive into object, Object(value) seems to be working properly everywhere.

Object.prototype.valueOf invoked with null/undefined should throw an error.

Array.prototype.concat will concat an Array when index property (read-only) exists in Array.prototype (Step 5.c.i)

The same as in Firefox. (passes in emulation mode)

'this' object used by the replaceValue function of a String.prototype.replace invocation

S15.5.4.14_A1_T{6-9}, ...A2_T7
Split should not coerce its argument to string "undefined" if its argument is undefined.

Date.prototype.setFullYear - Date.prototype is itself an instance of Date

Test just calls Date.prototype.setFullYear(2012); and expects 2012 to be read back. Hardly you'll need that in practice, but this test fails only in IE9. All other higher and lower versions aren't affected.

Old non-IEs

They are not widespread at all for now, hence only short overviews for each. Nonetheless, number of such client will not drop abruptly in foresee future - because of vendor-lock or similar situation.

Safari 5 (Win)

  • even though, it claims support of defining properties, it fails on hundreds of tests regarding them.
  • and on dozens regarding strict mode
  • parseInt still accepts octal.
  • JSON.parse('{"__proto__":[]}'); returns object with 2 __proto__ properties!

Opera 12

Surprisingly good, only 4 bugs.

  • parseInt still accepts octal.
  • Does not treat whitespace characters from [\u2000-\u23ff] as those in regular expressions. (2 tests).
  • String.prototype.localeCompare does not treat missing 'that' argument as undefined.

Android 4.3 (Galaxy S3)

  • parseInt still accepts octal.
  • String.prototype.localeCompare does not treat missing 'that' argument as undefined.
  • Failed to add a property to an object when the object's prototype has a property with the same name and [[Writable]] set to false. Non-writable property on a prototype written to.
  • Call arguments are not evaluated before the check is made

Android 4.1 (ASUS fonepad)

  • JSON.parse('{"__proto__":[]}'); returns object with 2 __proto__ properties!
  • String.prototype.localeCompare does not treat missing 'that' argument as undefined.
  • do not mess with function.length for fn instances.
  • numerous bugs with Array.prototype methods applied to the global object (window)


After few hours of night hacking I made test suite running in IE8 - there're several things, which break in the GUI and test runner itself.

Of course, there're no es5 features, but they could be polyfilled to some extent. Nonetheless, some bugs due to subtle discrepancies in syntax parsing can arise.

Bugs are limitless, but I'll try to summarize them in concise way. Keep in mind, that most bugs from IE9 are also reproduced, but they're too minor comparing to the HELL happening below.

Incompatibilities described in terms how IE8 behaves. Correct behavior is either stated explicitly or considered obvious.


  • indirect eval call does not set scope to the global context
  • variable name spoiling:
    • function declared within if block
    • named function expressions spoil the outside scope.
    • multiple names for function
    • name used in catch block
  • TypeError is used instead of ReferenceError for referencing variable
  • delete behave differently in unusual positions. Like delete foo();
  • global properties couldn't be removed with delete operator, workaround
  • it's only possible to define length variable with var keyword in a global scope. Otherwise you'll get an error, trying to set it.
  • it's possible to delete prototype property.


  • trailing comma adds extra empty element to array and fail with SyntaxError in object literals
  • most reserved words can't be used for dot-notation, in object literals and function names. More or less real use cases for them are:
    • jQuery("<div>", { class: "someClass" })
    • jQuery(someSelector).css({ float: "left" })
      The first one fails in IE, while the second one doesn't, because it isn't a reserved word in IE8. For the same reason IE8 allows other names such as let, interface and so on.
      And both pieces of code fails in deprecated YUI compressor.
  • the following constructions should generate syntax error:
    • if (...) { ... }; else
    • do {}; while(..)
    • try {...}; finally{...}
  • \\v VERTICAL TAB, U+2028 LINE SEPARATOR and U+2029 PARAGRAPH SEPARATOR can mess your code everywhere: in code itself, RegExp literals, comments.


  • many whitespace characters are not considered as \s. E.g. &nbsp; U+00A0 or separators from previous point.
  • Symbol "İ" U+0130 is considered as \w (ru-RU locale)
  • backreference used before actual capturing-group incorrectly considered as charcode escape.
    /\1(A)(B)\2/.exec("\1ABB"); vs /\1(A)(B)\2/.exec("ABB");
  • /[^]/ should match anything and /[]/ should match nothing, RegExpError is thrown instead
  • RegExpError is thrown instead of SyntaxError for wrong syntax
  • RegExpError is thrown instead of TypeError for wrong flags
  • flag duplications is allowed in both literals (/./ii) and dynamic construction via RegExp
  • non-matched capturing groups become "" instead of undefined
  • non-matched capturing groups inside repetition do not overwrite matched ones from previous matches
(z)((aa)( )  (c))
   (( ) (bbb)(c))
   ((a) ( )  (c))
     ^   ^    ^
     a   bbb  c

Here "bbb" incorrectly "fall-through": match[4] should be undefined or at least ""


  • parseInt still accepts octal
  • Number.prototype.toString(undefined) fails with error
  • Number.prototype.toFixed(Infinity) should fail with TypeError
  • (1e21).toFixed() should return 1e+21, not 1000000000000000000000


  • No indexOf and lastIndexOf as well as other functional stuff.
  • Array.isArray is missing
  • array.slice(n, undefined) always returns an empty array
  • [].sort(undefined) fails with error
  • Array.prototype.splice on objects doesn't remove values
  • setting non-integer (but numeric) length for array should fail


  • trim and lastIndexOf methods are missing
  • "".match() returns null instead of ""
  • "".search() returns null instead of 0
  • empty strings are not included if separator argument is regex: "101101".split(/1/) === ["0", "0"]
  • capturing groups are not included in the final results: "010".split(/(1)/) === ["0", "0"]
  • split should not coerce to string undefined passed as separator argument
  • split should coerce limit argument with ToUint32
  • incorrect length value for fromCharCode, replace, slice, search, indexOf and lastIndexOf methods


  • ES5 methods of Object are not supported. defineProperty and getOwnPropertyDescriptor are present. Alas, MSDN tells us that function
... supports DOM objects but not user-defined objects. The enumerable and configurable attributes can be specified, but they are not used
  • Date.prototype.toISOString is missing
  • Object.prototype.toString incorrectly returns "[object Object]" when applied to window, DOM nodes, undefined or null.
  • JSON shouldn't allow characters U+0010 through U+001F


Comments None

The other day I found rather thorough quiz on css, html and js. One may consider it boring, nonetheless many interesting edge-cases are considered.

The only problem I consider is that no explanations is given. Author promotes his book at the end of the quiz, but I decided to be a naughty person and provide explanation to all questions for free ;-) I'd suggest you to take the quiz again, skipping all questions and not answering last one.

Take the quiz



  1. Are attribute names in CSS case-sensitive?
    CSS2: 4.1.3 Characters and case

    All CSS syntax is case-insensitive within the ASCII range (i.e., [a-z] and [A-Z] are equivalent)

  2. Do vertical margins affect size of inline elements?
    CSS2: 9.4.2. Inline formatting contexts
    Also see note on margin-top and margin-bottom in CSS21: 8.3 Margin properties

    These properties have no effect on non-replaced inline elements.

  3. Do vertical paddings affect size of inline elements?
    CSS2: 9.4.2. Inline formatting contexts

    In an inline formatting context, boxes are laid out horizontally, one after the other, beginning at the top of a containing block. Horizontal margins, borders, and padding are respected between these boxes.

  4. CSS3: 5.1.1 rem unit
    Resize of the window doesn't affect font-size of the body in general case

  5. CSS3: The :checked pseudo-class

    :checked pseudo-class initially applies to such elements that have the HTML4 selected and checked attributes as described in Section 17.2.1 of HTML4

  6. CSS3: :root pseudo-class

    The :root pseudo-class represents an element that is the root of the document. In HTML 4, this is always the HTML element.

  7. translate is a 2D translation and is defined as 3D translation with z = 0.

  8. color is inherited in CSS

  9. specificity: (0,1,0,0) vs (0,0,0,2)

  10. specificity: (0,1,0,0) vs (0,0,2,0)

  11. Here specificity of first selector is greater, but second selector is applied directly to an element

  12. In cascading order for point 2 we have "4. author important declarations", which are prioritized before specificity.

  13. :nth-of-type(odd) is applicable here, hence rule with it is used

  14. specificity (1,2,1) vs (1,1,2)

  15. negative margin - see image

  16. Actually specification is not generous describing details on how negative margins work. We could rely on intuition and extrapolate behavior.

  17. CSS3 backgrounds: 3.3. Image Sources: the ‘background-image’ property

    Implementations may optimize by not downloading and drawing images that are not visible (e.g., because they are behind other, fully opaque images).

    Not very thorough, therefore some practical tests should be preformed. SO:Are unused CSS images downloaded Also most web-developers know, that for example if some item with :hover has separate background-image, this image would not be loaded until actual hover happens.

  18. Most browsers download background image for elements with display:none - test#2

  19. Most browsers do not download background image for children of element with display:none test#3 and not due to visibility:hidden.

  20. CSS3 Media Queries

    The keyword ‘only’ can also be used to hide style sheets from older user agents. User agents must process media queries starting with ‘only’ as if the ‘only’ keyword was not present.

  21. CSS21: Block formatting context, shorter list on MDN

  22. CSS3 Media Queries
    screen media means that content is intended to be rendered on screen, nevertheless width is defined for viewport size.


  1. Does <kbd> tag exists in html5?

  2. What does <bdo> tag mean?

  3. Is it ok to use certain html within <figure> tag?

  4. Where it is appropriate to use <small> tag in html5? Also on MDN:html5 tags

  5. Are multiple headings ok for SEO?
    "Organic" and semantically adjusted tags are ok for SEO.

  6. Which element to use for highlighting keyword in search results - <mark>. One may as well read about all elements (there's no highlight element, though) and make sure that semantic of all but &lt;mark> tag don't fit the situation.

  7. Scope attribute of <style> tag

  8. <a> tags as block at html5doctor

  9. Image hidden via visibility
    visibility:hidden preserves element in content flow and its sizes should be determined. For image element default size is obtained from its content, hence image should be loaded. Also see next point.

  10. Image inside display:none element
    I can't find direct statement, that images should be loaded, there're some evidence for that, though:

    In a browsing context where scripting is disabled, user agents may obtain images immediately or on demand. In a browsing context where scripting is enabled, user agents must obtain images immediately

    Also practical observations show, that image is loaded even when detached from DOM. This feature has been being used for js image preload for long time.

  11. No explicit statements found, but see emphasised a style sheet that is blocking scripts in HTML5: 4.2.7 Styling
    Also see google's advice #3.

  12. I failed to found explicit statement regarding that, but there's nothing about one stylesheet blocking subsequent ones.

  13. Again, no success in reading specs.
    Real testing shows that IE (all versions) is the only browser rendering content preceding style tag. Possibly most browsers delay rendering to avoid flash of unstyled content.


  1. es5#11.6.1: The Addition operator

    If Type(lprim) is String or Type(rprim) is String, then Return the String that is the result of concatenating ToString(lprim) followed by ToString(rprim)

    hence addition of number and string is a concatenation of two operands converted to strings

  2. Addition has left associativity (operator precedence) hence numbers are summed up first and then result is concatenated with last operand.

  3. Function declaration is always hoisted. It declares local variable foo and first line foo = 10; actually overwrites local variable.
    Top-level name foo is remained untouched and its initial value is alerted.

  4. Function declaration hoisting again plus variable hoisting. The same es5#10.5 covers variable declaration in point 8. Code sample could be rewritten in more explicit way:

function bar() {
    var foo = function () {}; // both declaration and initialization is hoisted
    return foo;
    foo = 10;
    foo = 11; // re-declaration does nothing

Variable hoisting is really an important thing to understand. One more link to good article about hoisting.

  1. In simple words, go become detached reference w/o any knowledge, whose method it was and this become global for its calls.
    More formally go is actually a reference variable in current scope. When function call is performed, according to 6b, _thisValue_ is taken from top-level scope: object environment record. Its ImplicitThisValue returns undefined, which is replaced with global object when entering function code
    BTW constructions like (1,; also leads to detached function reference.

  2. Similarly anonymous functions always have this set to global context.

  3. x is referred to primitive value from outer scope. According to es5#13.2.2 if return type is not an object, actual return value is as if no return was called.

  4. arguments object always has list of actually passed arguments. It is foo.length, what is equals to 1.

    args be the actual arguments passed to the [[Call]] internal method ...
    1. Let len be the number of elements in args ...
    7. Call the [[DefineOwnProperty]] internal method on obj passing "length", the Property Descriptor {[[Value]]: len, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true}, and false as arguments.

  5. Name bar is only available within the function body: see note on es5#13:function definition. There is a bug in IE8-, though, when such names leaks into scope. JScript Deviations from ES3 2.7 Function Expressions: §11.2.5, p10.

  6. Arrays are (special) objects, hence they can have additional named properties. Nonetheless the length is affected only by assigning numerical-indexed properties. More on that in es5#

  7. Named arguments and indexed properties of arguments are references to same values. See note 1 on es5#10.6:arguments.
    Mixing up these two representations is not recommended, though.

  8. es5# property of the function has Configurable es5#8.6.1:attribute set to false and hence property could not be deleted.

Wow, you made it so far. If you wonder, I got 79% on the first try.


← Older Newer →