來源地址:
http://dmitrysoshnikov.com/ecmascript/the-quiz/#q1
另一篇帖子 看看國外的javascript題目,你能全部做對嗎?
http://www.cnblogs.com/aaronjs/p/3172112.html
答案都是自己總結的,畢竟是人肉解釋器,解釋不一定完全正確,如有不對歡迎大家指出!
題目1. 結果是什么?
typeof typeof(null)
- “undefined”
- SyntaxError
- “string”
- “object”
- TypeError

答案
題目2. 下面的檢測是否等價?
typeof foo == 'undefined'
typeof foo === 'undefined'
- Yes
- No

答案
題目3. 結果是什么?
100['toString']['length']
- 100
- 3
- 1
- 8
- 0
- SyntaxError
這個估計好多人想不通了
JavaScript 中所有變量都是對象,除了兩個例外 null 和 undefined
false.toString(); // 'false' [1, 2, 3].toString(); // '1,2,3'
function Foo(){} Foo.bar = 1; Foo.bar; // 1
一個常見的誤解是數字的字面值(literal)不是對象。這是因為 JavaScript 解析器的一個錯誤, 它試圖將點操作符解析為浮點數字面值的一部分。
2.toString(); // 出錯:SyntaxError
例如以下這種就OK
true.toString() "true" false.toString() "false" 01.toString() "1" 0x20.toString() "32"
true.toString()、false.toString()、02.toString()、 0x20.toString()都是可以的
我仔細查了下,網上大多給的解釋
2.toString()出錯是因為解釋器讀到“2. ”不知道這個“點”究竟該作為小數點還是“.”操作符, 或者也就是說在這里產生了一個“shift-shift conflit”
有很多變通方法可以讓數字的字面值看起來像對象
2..toString(); // 第二個點號可以正常解析 2 .toString(); // 注意點號前面的空格 (2).toString(); // 2先被計算
訪問100['toString']的length返回toString方法形參個數;
換個
(function(a,b){ //輸出2 })['length']
fn = { f : function(a,b,c){ //3 } }; fn.f['length']
有長度屬性的函數,這個長度就是用來計算多個參數的,
可以分解為
100['toString'].length
由於toString是個方法,所以它length屬性返回的是toString的形參個數,而toString方法可以接收一個radix(基數)作為形參(比如:toString(2),返回該數值的二進制,16則代表16進制),所以最終返回結果是1。
function toString( [radix : Number] ) : String
radix 可選項。為將數字值轉換為字符串指定一個基數。此值僅用於數字。
所以當數字調用toString的時候,會有一個參數radix,其它的比如:Function、Array、String這些調用的話,結果會是 0
剛才上面的100['toString']['length']為什么不分解成100.toString.length?
這是是由於100后面的.是小數點之后是小數部分,從而導致語法錯誤
解決的方法也說了
100..toString.length
1
參考資料
http://www.dengpeng.org/archives/615
題目4:結果是什么?
var a = (1,5 - 1) * 2
- 0.999999999
- 1
- 0.5
- 8
- -0.5
- 4
這里主要是理解這個 逗號操作符了
在for循環中,增量表達式
j = 10;
for (i = 0; i <5; i++, j++) { k = i + j; } i j k 0 10 10 1 11 12 2 12 14 3 13 16 4 14 18
允許多個表達式被當作單個表達式,所以這兩個變量可以遞增。
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comma_Operator
當有一個包含一個或多個逗號表達式,表達式的值等於最后一個值
var a = (1,2,3,4) //4
* 逗號操作符的最佳用途是定義多個變量和示例使用這里是絕對不推薦的
答案呼之欲出了就是8,
題目5 結果是什么?
var x = 10; var foo = { x: 20, bar: function () { var x = 30; return this.x; } }; console.log( foo.bar(), // 1. (foo.bar)(), // 2. (foo.bar = foo.bar)(), // 3. (foo.bar, foo.bar)() // 4. );
- 20, 20, 20, 20
- 20, 20, 10, 10
- 20, 20, 20, 10
- 20, 20, 10, 30
- 20, 10, 10, 10
- 20, 10, 30, SyntaxError
我們一句一句的分解
這個很簡單,直接調用bar 方法,此時的上下文就是foo對象,所以this.x = 20 return 的結果也就是20了
我們看看括號的定義 ECMA語言規范
11.1.6 The Grouping Operator The production PrimaryExpression : ( Expression ) is evaluated as follows: 1. Evaluate Expression. This may be of type Reference. 2. Return Result(1). NOTE This algorithm does not apply GetValue to Result(1). The principal motivation for this is so that operators such as delete and typeof may be applied to parenthesised expressions.
引用類型的值與函數上下文中的this值如何相關?——從最重要的意義上來說。 一個函數上下文中確定this值的通用規則如下:
在一個函數上下文中,this由調用者提供,由調用函數的方式來決定。如果調用括號()的左邊是引用類型的值,this將設為引用類型值的base對象(base object),在其他情況下(與引用類型不同的任何其它屬性),這個值為null。不過,實際不存在this的值為null的情況,因為當this的值為null的時候,其值會被隱式轉換為全局對象。注:第5版的ECMAScript中,已經不強迫轉換成全局變量了,而是賦值為undefined。
這是對組操作符的描述,說明得到的結果是一個 Reference 引用類型
alert( foo.bar === (foo.bar) ) //true
關於引用類型的解釋,參考
這一題我也做錯了,呵呵
查了查資料,我們先看看
var foo = { bar: function () { alert(this); alert(this === foo); } };
foo.bar(); // foo, true
var exampleFunc = foo.bar;
alert(exampleFunc === foo.bar); // true
// 再一次,同一個function的不同的調用表達式,this是不同的
exampleFunc(); // global, false
可見將foo.bar的引用賦給一個變量,在執行的時候,這個this的指向就被改變了
重點(=)賦值是如何處理的?
不懂就翻規范唄,又去找找ECMA語言規范
11.13.1 Simple Assignment (= ) The production AssignmentExpression : LeftHandSideExpression = AssignmentExpression is evaluated as follows: 1. Evaluate LeftHandSideExpression. 2. Evaluate AssignmentExpression. 3.Call GetValue(Result(2)). 4.Call PutValue(Result(1), Result(3)). 5.Return Result(3).
8.7.2 PutValue(V, W) 1. If Type(V) is not Reference, throw a ReferenceError exception. 2. Call GetBase(V). 3. If Result(2) is null, go to step 6. 4. Call the [[Put]] method of Result(2), passing GetPropertyName(V) for the property name and W for the value. 5. Return. 6. Call the [[Put]] method for the global object, passing GetPropertyName(V) for the property name and W for the value. 7. Return.
我也沒有看太明白, 還要慢慢消化,但是大體的定義
賦值運算符調用了GetValue方法。返回的結果是函數對象(但不是引用類型),這意味着this設為null,結果是global對象
語句返回的是 foo.bar 的函數值
因此,賦值操作符返回的是「值(Value)」而不是「引用(Reference)」。
因為函數體需要 this 值獲取 x 屬性的值,那么接下來我們考慮改函數時調用時的上下文作用域以及背后的具體流程。 尤其注意第七條規則
... 6. If Type(Result(1)) is Reference, Result(6) is GetBase( Result(1)). Otherwise, Result(6) is null. 7. If Result(6) is an activation object, Result(7) is null. Otherwise, Result(7) is the same as Result(6). 8. Call the [[Call]] method on Result(3), providing Result(7) as the this value and providing the list Result(2) as the argument values. …
那么在這種情況下,GetBase
操作實際上返回的是 null
,因此此條語句函數執行的作用域為 global ,在瀏覽器中也就是 window 。
(foo.bar = foo.bar)()
那么,上面的語句中我們可以得知
- Grouping Operator 中的賦值語句返回的是 foot.bar 的函數值(「Value」)
- 該函數執行的上下文作用域為 window
找了幾篇相關文章具體參考:
http://www.w3.org/html/ig/zh/wiki/ES5/%E8%A1%A8%E8%BE%BE%E5%BC%8F
http://www.cnblogs.com/TomXu/archive/2012/01/17/2310479.html
逗號運算符和邏輯運算符(OR)調用了GetValue 方法,相應地,我們失去了引用而得到了函數。並再次設為global。
我們似乎可以總結一下:
JavaScript 是弱類型語言,這就意味着,等於操作符會為了比較兩個值而進行強制類型轉換。
兩個等號組成:==
"" == "0" // false 0 == "" // true 0 == "0" // true false == "false" // false false == "0" // true false == undefined // false false == null // false null == undefined // true " \t\r\n" == 0 // true
嚴格等於操作符由三個等號組成:===
"" === "0" // false 0 === "" // false 0 === "0" // false false === "false" // false false === "0" // false false === undefined // false false === null // false null === undefined // false " \t\r\n" === 0 // false
==
被廣泛認為是不好編程習慣的主要原因, 由於它的復雜轉換規則,會導致難以跟蹤的問題。
此外,強制類型轉換也會帶來性能消耗,比如一個字符串為了和一個數字進行比較,必須事先被強制轉換為數字。
關於Object.prototype.toString方法的原理參考
https://developer.mozilla.org/zh-CN/docs/JavaScript/Reference/Global_Objects/Object/toString
http://www.cnblogs.com/ziyunfei/archive/2012/11/05/2754156.html
還有5道題,需要深思熟慮了...
PS:JS越學越謙卑........