2012年6月3日日曜日

javascriptクイズ(解説編)

下記の記事の解説を試みてみる。

JavaScriptクイズ「x + 0 == x - 0」

筆者は7個まちがえて65/100点でございました。とはいえ、実際の動きを調べてみたら偶然結果が当たっていただけのこともあり、点数ほどは理解出来ていません。ちなみに、動作確認した処理系は、"node.js v0.7.5-pre"。

まずは、1問目の解説から。

まずは、左辺がどのように展開されるかの解説。
{}+0
  • ToPrimitive({}, PreferredType=Number)+0
    // No hint for PreferredType then default "Number".
    // See 8.6.2.6 [[DefaultValue]](hint).
  •     When the [[DefaultValue]] method of O is called with no hint, then it behaves as if the hint were Number
  • {}.toString()+0
    // See 8.6.2.6 [[DefaultValue]](hint)
        5. Call the [[Get]] method of object O with argument "toString".
    // ここ自信無い
  • '[object Object]'+0
  • '[object Object]'+0.toString()
    // Because Type(ToPrimitive({},PreferredType=Number)) is String.
    // See 11.6.1 The Addition operator (+ )
        7.If Type(Result(5)) is String or Type(Result(6)) is String, go to step 12
        12. Call ToString(Result(5)).
        13. Call ToString(Result(6)).
  • '[object Object]0'

うーん、しんどい。お次は、右辺。
{}-0

最後に、左辺と右辺の比較の解説
See 11.9.3 The Abstract Equality Comparison Algorithm.
'[object Object]0'==NaN
  • ToNumber('[object Object]0')==NaN
    // 1. If Type(x) is different from Type(y), go to step 14.
    // 17.If Type(x) is String and Type(y) is Number, return the result of the comparison ToNumber(x)== y.
  • NaN==NaN
  • false
    // 5.If x is NaN, return false.

うーん、これでもいくつかはしょってるけど、まじめに解説するとめっちゃ大変(どっか間違ってたら、ご指摘願います)。こっからはがしがしはしょっていきます。



[]+0==[]-0
  • [].toString()+0==ToNumber([])-0
  • ''+0==0-0
  • '0'==0
  • ToNumber('0')==0
  • 0==0
  • true
ポイントは、以下の2点かな。
  [].toString() returns ''
  ToNumber([]) returns 0



(function(){})+0==(function(){})-0
  • (function(){}).toString()+0==ToNumber((function(){}))-0
  • 'function (){}'+0==NaN-0
  • 'function (){}0'==NaN
  • ToNumber('function (){}0')==NaN
  • NaN==NaN
  • false
関数もオブジェクトのひとつ。あとは、1問目と同じ。



null+0==null-0
  • ToNumber(null)+0==ToNumber(null)-0
  • 0+0==0-0
  • 0==0
  • true
ToNumber(null) returns 0.
See 9.3 ToNumber.



undefined+0==undefined-0
  • ToNumber(undefined)+0==ToNumber(undefined)-0
  • NaN+0==NaN-0
  • NaN==NaN
  • false
ToNumber(undefined) returns NaN.
See 9.3 ToNumber.



Infinity+0==Infinity-0
  • Infinity==Infinity
  • true



Array+0==Array-0
  • Array.toString()+0==ToNumber(Array)-0
  • 'function Array() { [native code] }'+0==NaN-0
  • 'function Array() { [native code] }0'==NaN
  • ToNumber('function Array() { [native code] }0')==NaN
  • NaN==NaN
  • false
コンストラクタも関数オブジェクト。



0+0==0-0
  • true
何も言うまい。



false+0==false-0
  • ToNumber(false)+0==ToNumber(false)-0
  • 0+0==0-0
  • true
ToNumber(false) returns 0. (ToNumber(true) returns 1).
See 9.3 ToNumber.



NaN+0==NaN-0
  • NaN==NaN
  • false
See 11.6.3 Applying the Additive Operators ( +,- ) to Numbers
If either operand is NaN, the result is NaN.



""+0==""-0
  • ToString("")+ToString(0)==ToNumber("")-0
    // 7.If Type(Result(5)) is String or Type(Result(6)) is String, go to step 12.
    // 12. Call ToString(Result(5)).
    // 9.Call ToNumber(Result(6)).
  • ''+'0'==0-0
  • '0'==0
  • ToNumber('0')==0
  • 0==0
  • true
ToNumber("") returns 0.
See 9.3.1 ToNumber Applied to the String Type.
A StringNumericLiteral that is empty or contains only white space is converted to +0.



"a"+0=="a"-0
  • ToString("a")+ToString(0)==ToNumber("a")-0
  • 'a'+'0'==NaN-0
  • 'a'==NaN
  • ToNumber('a')==NaN
  • NaN==NaN
  • false



"0"+0=="0"-0
  • ToString("0")+ToString(0)==ToNumber("0")-0
  • '0'+'0'==0-0
  • '00'==0
  • ToNumber('00')==0
  • 0==0
  • true



"1"+0=="1"-0
  • ToString("1")+ToString(0)==ToNumber("1")-0
  • '1'+'0'==1-0
  • '10'==1
  • ToNumber('10')==1
  • 10==1
  • false



"0.1"+0=="0.1"-0
  • ToString("0.1")+ToString(0)==ToNumber("0.1")-0
  • '0.1'+'0'==0.1-0
  • '0.10'==0.1
  • ToNumber('0.10')==0.1
  • 0.1==0.1
  • true



"0x"+0=="0x"-0
  • ToString("0x")+ToString(0)==ToNumber("0x")-0
  • '0x'+'0'==NaN-0
  • '0x0'==NaN
  • ToNumber('0x0')==NaN
  • 0==NaN
  • false
'0x0' is HexIntegerLiteral.
See 9.3.1 ToNumber Applied to the String Type.



"."+0=="."-0
  • ToString(".")+ToString(0)==ToNumber(".")-0
  • '.'+'0'==NaN-0
  • '.0'==NaN
  • ToNumber('.0')==NaN
  • 0==NaN
  • false
ToNumber(".") returns NaN while ToNumber(".0") returns 0.
See 9.3.1 ToNumber Applied to the String Type.



" "+0==" "-0
  • ToString(" ")+ToString(0)==ToNumber(" ")-0
  • ' '+'0'==0-0
  • ' 0'==0
  • ToNumber(' 0')==0
  • 0==0
  • true
See 9.3.1 ToNumber Applied to the String Type.
StringNumericLiteral:::StrWhiteSpace(opt) StrNumericLiteral StrWhiteSpace(opt)
A StringNumericLiteral that is empty or contains only white space is converted to +0.



Array()+0==Array()-0
  • []+0==[]-0
  • あとは、2問目と同様。
  • [].toString()+0==ToNumber([])-0
  • ''+0==0-0
  • '0'==0
  • ToNumber('0')==0
  • 0==0
  • true
15.4.1 The Array Constructor Called as a Function
it creates and initialises a new Array object.
うーん、これは知らなかった。
See JavaScript: new無しで基本型のコンストラクタを呼んだ時の挙動.



(function(){}())+0==(function(){}())-0
  • undefined+0==undefined-0
  • あとは、5問目と同様。
  • ToNumber(undefined)+0==ToNumber(undefined)-0
  • NaN+0==NaN-0
  • NaN==NaN
  • false
12.9 The return Statement
ReturnStatement : return [no LineTerminator here] Expression(opt);
If Expression is omitted, the return value is undefined.


ここまで読んでくださったみなさま、ありがとうございました。
どっか間違ってるとこがあったら、ご指摘ください。
それにしても、20問の中にいろんなパターンが含まれていて、よくできてるなあ。

参考:
Standard ECMA-262 3rd Edition -December 1999
JavaScript: new無しで基本型のコンストラクタを呼んだ時の挙動
What is {} + {} in JavaScript?
[ ] == ![ ] の謎を自分でも解いてみた