Path: csiph.com!usenet.pasdenom.info!news.albasani.net!rt.uk.eu.org!newsfeed.datemas.de!uucp.gnuu.de!newsfeed.arcor.de!newsspool4.arcor-online.net!news.arcor.de.POSTED!not-for-mail Content-Type: text/plain; charset="UTF-8" Message-ID: <2664592.4ckUSR1F5s@PointedEars.de> From: Thomas 'PointedEars' Lahn Reply-To: Thomas 'PointedEars' Lahn Organization: PointedEars Software (PES) Date: Sat, 15 Jun 2013 11:41:29 +0200 User-Agent: KNode/4.10.2 Content-Transfer-Encoding: 8Bit X-Face: %i>XG-yXR'\"2P/C_aO%~;2o~?g0pPKmbOw^=NT`tprDEf++D.m7"}HW6.#=U:?2GGctkL,f89@H46O$ASoW&?s}.k+&. <9415734.fqrm2ecmqt@PointedEars.de> <2068082.pen2y8QiGc@PointedEars.de> MIME-Version: 1.0 Lines: 133 NNTP-Posting-Date: 15 Jun 2013 11:41:32 CEST NNTP-Posting-Host: 00362337.newsspool2.arcor-online.net X-Trace: DXC=^mMk0G]>g8?kUFX=Y?aLP;A9EHlD;3Yc24Fo<]lROoR18kF]gf>RdK5H45i3F> X-Complaints-To: usenet-abuse@arcor.de Xref: csiph.com comp.lang.javascript:20300 Eric Bednarz wrote: > Stefan Weiss writes: >> On 2013-06-11 05:09, Thomas 'PointedEars' Lahn wrote: >>> >> >> There's one thing I don't understand about that algorithm: >> >> {} + "" > > That's a block statement followed by an unary + operator with the empty > string as its operand. Very good. I had not thought of that. To prove that ES 5.1, “11.6.1 The Addition operator” is properly implemented as concatenation operator: /* "[object Object]", as Stefan expected */ var x = {} + ""; or /* "[object Object]" */ ({}) + "" or /* "[object Object]" */ new Object() + "" The curious – maybe not obvious – thing here is, though, that it is _not_ the "" that causes the "[object Object]" result, but the conversion of the Object instance to a primitive value. The ToPrimitive() algorithm (§9.1) in step 5 – | 5. Let lprim be ToPrimitive(lval). – calls the [[DefaultValue]] internal method, passing the PreferredType on as argument for the hint. As there is no PreferredType, there is no hint. Object instances are native objects. Their [[DefaultValue]] method is specified in ECMAScript (§8.12.8). Calling it without hint works as if it was called with hint Number. Thus, it attempts to converts its object argument to a primitive value by attempting to call its valueOf() method first. Object instances inherit from Object.prototype a valueOf() method through the prototype chain; it returns a reference to the same object. That is *not* a primitive value. If the valueOf() method of the object cannot be called or does not return a primitive value, [[DefaultValue]] attempts to call the object's toString() method. Object instances inherit from Object.prototype a toString() method through the prototype chain which always returns a primitive string value that is the equivalent of "[object " + [[Class]] + "]" (we can use it to tell the [[Class]] of an object, for example for Array.isArray() emulation, as implemented by jsx.object.getClass()). Because that return value satisfies the condition in §8.12.8, hint Number, step 4b, that is the return value of [[DefaultValue]] and of ToPrimitive(). That in turn satisfies the condition in §11.6.1, step 7, where it says: | 7. If Type(lprim) is String or Type(rprim) is String, then […] It follows from logical shortcut evaluation that it does not matter that Type("") is String, because Type(({}).toString()) already is String. As a result, we observe in conforming implementations: /* "[object Object]23" */ ({}) + 23 And because of | 8. Return the result of applying the addition operation to | ToNumber(lprim) and ToNumber(rprim). See the Note below 11.6.3. /* 42 */ ({valueOf: function () { return 19; }}) + 23 [A possible application of the latter is: function Complex (re, im) { /* or throw exceptions */ this.re = (re ? +re : 0) this.im = (im ? +im : 0); } /** * @overrides Object.prototype.valueOf() */ Complex.prototype.valueOf = function () { if (!this.im) { return this.re; } return this; }; /* 42 */ new Complex(19) + 23 /* 42 */ new Complex(19) + new Complex(23) Unfortunately, without the possibility of operator overloading the following does not work: /* _not_ new Complex(42, 42) */ new Complex(19, 42) + new Complex(23) But you can work around it: Complex.prototype.add = function (o) { /* or “Complex” if you do not care for polymorphism */ var C = this.constructor; if (o instanceof C) { return new C(this.re + o.re, this.im + o.im); } return new C(this.re + (+o), this.im); }; /* new Complex(42, 42) */ (new Complex(19, 42)).add(new Complex(23)); ] -- PointedEars Twitter: @PointedEars2 Please do not Cc: me. / Bitte keine Kopien per E-Mail.