In strict mode, assigning to a property on a string throws a TypeError in Safari 6 and in Nightly WebKit, Version 6.0 (8536.25, 537+). This does not occur in other strict-aware browsers, tested with Firefox 15 and Chrome 20. They allow the assignment but then later reads of the property return undefined. It may be that I misunderstood the strict mode rules, but in that case I am surprised the browsers do not agree in this case. In case the URL to the JSBin goes away, the script code is the following: function stricty() { //comment out use strict and no error thrown. //No error thrown in other strict-aware browsers. 'use strict'; var value = 'foo', err, result; try { //THIS IS WHERE IT FAILS IN Safari 6/Nightly WebKit value.something = true; } catch (e) { err = e; } if (err) { result = 'ERROR: ' + err; } else { result = 'value.something is: ' + value.something; } document.getElementById('out').innerHTML = result; } stricty();
My reading of ECMA-262 says that comments are not relevant in determination of strict mode: 14.1 Directive Prologues and the Use Strict Directive A Directive Prologue is the longest sequence of ExpressionStatement productions occurring as the initial SourceElement productions of a Program or FunctionBody and where each ExpressionStatement in the sequence consists entirely of a StringLiteral token followed a semicolon. The semicolon may appear explicitly or may be inserted by automatic semicolon insertion. A Directive Prologue may be an empty sequence. A Use Strict Directive is an ExpressionStatement in a Directive Prologue whose StringLiteral is either the exact character sequences "use strict" or 'use strict'. A Use Strict Directive may not contain an EscapeSequence or LineContinuation. Comments of any form are not statement expressions (they are explicitly treated as a single space character)
Oh wait, i was misinterpreting what you were saying.
This is correct behaviour. The evaluation of "value.something = true" is evaluated with by getting the reference for the left hand side, then evaluating the right hand side, then calling put value. step 1) get the reference for assignment: 11.2.1 Property Accessors 1. essentially baseReference = &value 2. baseValue = value 3. propertyNameReference = &"something" // all lookup is perform as if a.b were a["b"] 4. propertyNameValue = "something" 5. /* do nothing */ 6. propertyNameString = ToString(propertyNameValue) /*"something"*/ 7. strict = true /*we're in strict mode code*/ 8. return Reference({base: baseValue /*string*/, name: propertyNameString /*"something"*/, strict: strict /*true*/}) we'll call the result of this lhsRef. step 2) Evalute the right hand side (which i won't go through as it's not relevant) step 3) perform the assignment PutValue(lhsRef, lhsSide /*true*/) 8.7.2 PutValue (V /*{base: string, name: "something", strict: true}*/, W/*rhs side, so the value: true*/) 1. V is a reference so do nothing 2. base=GetBase(V) /*string*/ 3. /* do nothing as we've got a reference */ 4. V is a property reference so we now do: a. base is a primitive type (string) so put = a special internal version of [[Put]] also defined in 8.7.2 b. put(base, V.name, W, V.strict) Internal [[Put]](base /* our string*/, P /*"something"*/, W/*true*/, Throw/*true -- because we're in strict mode*/) 1. O=ToObject(base) // yay allocate a String object 2. /* do nothing as there's no readonly "something" property in prototype chain */ 3. ownDesc = GetOwnProperty(O, P) // "something" doesn't existing on the String object so this is null 4. /* do nothing as ownDesc is null*/ 5. desc = GetProperty(O, P) // also null as "something" isn't a property that exists anywhere on the protochain 6. /* do nothing as desc is null so isn't an accessor property */ 7. We are trying to assign a property to a temporary object a. Throw is true, so we throw a TypeError. So this is the correct behaviour, and the long (even though it's abbreviated) and winding path to throwing an exception here in strict mode. You should file bugs on the other browsers for not doing this correctly. :D
For reference you could run the tests at http://test262.ecmascript.org/# -- it's an ongoing endeavour to have complete coverage of the entire spec. On Wednesday last week Safari 6 passed every test.
The linked test case is actually making the kind of mistake this exception was specifically designed to prevent -- attaching properties to primitive types does not work, as you are simply attaching the properties to a temporary. If there isn't a setter on the prototype with the right name all you're doing is creating an object, assigning a property, and then throwing the object away.
Safari 6.0's behavior is correct here, see ECMA-262, section 8.7.2. The expression 'value.something' returns a property reference, and per section 11.13.1 step 5 this calls PutValue (8.7.2). The base of the reference is a primitive string, so per step 4a the put method we'll use if the special [[Put]] implementation specified below, and per step 4b the 'Throw' argument to [[Put]] is true (since we're in strict code, this is a strict reference). As the String object & its prototypes do not contain a 'something' property, we'll reach step 7, and throw a type error per step 7a. cheers, G.
Oh, wait, Oliver already said all this. Ooops! :-)
Thanks for the info, looks like the other browsers just have not implemented the matching behavior yet.