{
  "assessmentTests": {
    "javascript_test": {
      "name": "JavaScript 測驗",
      "desc": "30 道情景題涵蓋核心語法和型別強制轉換、函式/作用域/閉包和 this、物件/陣列和資料結構、事件迴圈/非同步/原型成語——瞭解您的 JavaScript 知識是否符合招募人員對 JavaScript 能力的期望。",
      "recommendation": "您的 JavaScript 技能檔案",
      "results": {
        "beginner": {
          "name": "初級",
          "desc": "您可以編寫可用的函式和物件，但您遺漏的問題圍繞型別強制轉換和引用語義而非語法——== 在比較前悄悄轉換型別，陣列賦值共享一個物件而非複製它，為什麼 NaN 永遠不等於自己。這都不是關於 JavaScript 不好的問題；這些是特定規則，它們讓透過編寫碰巧工作的程式碼來學習該語言的人而不是學習值和引用實際如何表現的人感到困惑。它們在工作中很重要，因為每一個都是程式碼執行沒有錯誤但仍然做了錯誤的地方。",
          "recommendation": "按以下順序從三件事開始：為什麼 == 在比較前強制轉換型別而 === 則不然；為什麼將一個數組或物件賦值給新變數會複製引用而不是值；以及 var 如何被提升並初始化為 undefined，而 let 和 const 保持在暫時死區直到其宣告執行。MDN 的 JavaScript 指南用可執行的示例涵蓋所有三個。"
        },
        "intermediate": {
          "name": "中級",
          "desc": "您熟練地處理日常應用程式碼——函式、陣列方法、直接的控制流——不會被常規功能工作拖慢。這裡和高級之間的差距主要在 JavaScript 的作用域和時序規則相互作用時發生的事情：在迴圈的回撥內捕獲的 var 都讀取相同的最後一個值，一個 this 在方法從其分離時悄悄停止指向物件，一個看起來深但只複製一層的展開副本。這些是透過快速閱讀就能通過的錯誤型別，僅在特定執行時條件下顯示。",
          "recommendation": "關注作用域和 this 在呼叫時而非定義時的實際解析方式：為什麼基於 var 的 for 迴圈為每個回撥提供相同的最後一個計數器值，而 let 則不然；this 如何由函式的呼叫方式而非編寫位置決定；以及為什麼展開或 Object.assign 只複製物件的頂級。然後是事件迴圈，因為這會讓已經知道單個承諾的人困惑。"
        },
        "advanced": {
          "name": "高級",
          "desc": "這是大多數工作公告用\"強大的 JavaScript\"表示的級別。您閱讀 filter/map/reduce 鏈並可以準確預測它返回什麼而不改變原始陣列，您知道為什麼同步 console.log 總是擊敗微任務，而微任務總是擊敗 setTimeout，您使用 Promise.all 知道它在任何一個承諾拒絕時立即拒絕，而不是等待其餘的。將此頻帶與頂部分離的是原型和物件模型工作的一側：原型鏈如何解析繼承方法與 hasOwnProperty，以及私有類欄位實際隱藏了什麼。",
          "recommendation": "推進保護其他程式碼也觸及的狀態的部分：JavaScript 的原型鏈如何解析不在例項本身上的方法查詢；類的私有 #fields 實際上從外部訪問隱藏了什麼；以及 JSON.stringify 如何在純物件內部與陣列內部以不同方式處理 undefined 和函式。MDN 關於事件迴圈和原型鏈的資料對兩者都是自然的下一步。"
        },
        "expert": {
          "name": "專家",
          "desc": "您在每個部分都獲得了最高分——核心語法、型別和強制轉換；函式、作用域、閉包和 this；物件、陣列和資料結構；以及非同步、事件迴圈、原型和成語。實際上，這意味著您可以接受陌生人的函式並解釋它為什麼返回它返回的內容，而不僅僅是語法說它應該做什麼，這是更困難和更有價值的技能。在這個級別，語言本身很少成為限制因素；限制通常是非同步控制流或其下的資料形狀。",
          "recommendation": "現在返回在設計和診斷中：關於 Promise.all 和 Promise.race 之間的競態條件進行推理而不是背誦其定義；選擇閉包何時是私有狀態的正確工具，何時是類的私有欄位；以及在生產日誌中讀取微任務對比宏任務排序錯誤而非在測驗中。如果您被篩選用於某個角色，請描述您發現的計時錯誤——陳舊的閉包變數或無序的非同步回撥——而非命名 JavaScript 功能；這表明了推理，而非僅僅是詞彙。"
        }
      },
      "questions": [
        {
          "question": "console.log(x);\nvar x = 5;\n這會列印什麼？",
          "options": [
            {
              "icon": "",
              "label": "5"
            },
            {
              "icon": "",
              "label": "ReferenceError: x 未定義"
            },
            {
              "icon": "",
              "label": "undefined"
            },
            {
              "icon": "",
              "label": "null"
            }
          ]
        },
        {
          "question": "console.log(y);\nlet y = 5;\n會發生什麼？",
          "options": [
            {
              "icon": "",
              "label": "它丟擲 ReferenceError"
            },
            {
              "icon": "",
              "label": "它列印 undefined"
            },
            {
              "icon": "",
              "label": "它列印 5"
            },
            {
              "icon": "",
              "label": "它丟擲 SyntaxError"
            }
          ]
        },
        {
          "question": "const arr = [1, 2, 3];\narr.push(4);\nconsole.log(arr.length);\n這會列印什麼？",
          "options": [
            {
              "icon": "",
              "label": "4"
            },
            {
              "icon": "",
              "label": "它丟擲 TypeError"
            },
            {
              "icon": "",
              "label": "3"
            },
            {
              "icon": "",
              "label": "undefined"
            }
          ]
        },
        {
          "question": "console.log('' == 0);\nconsole.log('' === 0);\n兩行列印什麼？",
          "options": [
            {
              "icon": "",
              "label": "true 然後 true"
            },
            {
              "icon": "",
              "label": "false 然後 false"
            },
            {
              "icon": "",
              "label": "true 然後 false"
            },
            {
              "icon": "",
              "label": "它丟擲 TypeError"
            }
          ]
        },
        {
          "question": "console.log(NaN === NaN);\nconsole.log(Number.isNaN(NaN));\n兩行列印什麼？",
          "options": [
            {
              "icon": "",
              "label": "true 然後 true"
            },
            {
              "icon": "",
              "label": "它丟擲 TypeError"
            },
            {
              "icon": "",
              "label": "false 然後 false"
            },
            {
              "icon": "",
              "label": "false 然後 true"
            }
          ]
        },
        {
          "question": "console.log(typeof null);\n這會列印什麼？",
          "options": [
            {
              "icon": "",
              "label": "\"null\""
            },
            {
              "icon": "",
              "label": "\"object\""
            },
            {
              "icon": "",
              "label": "\"undefined\""
            },
            {
              "icon": "",
              "label": "\"boolean\""
            }
          ]
        },
        {
          "question": "以下哪個在 if 條件中使用時為真？",
          "options": [
            {
              "icon": "",
              "label": "0"
            },
            {
              "icon": "",
              "label": "\"\"（空字串）"
            },
            {
              "icon": "",
              "label": "null"
            },
            {
              "icon": "",
              "label": "\"0\"（字串）"
            }
          ]
        },
        {
          "question": "foo();\nfunction foo() { console.log('a'); }\nbar();\nvar bar = function() { console.log('b'); };\n會發生什麼？",
          "options": [
            {
              "icon": "",
              "label": "兩個呼叫都列印，先是 \"a\"，然後是 \"b\""
            },
            {
              "icon": "",
              "label": "foo() 列印 \"a\"；bar() 丟擲 TypeError"
            },
            {
              "icon": "",
              "label": "foo() 和 bar() 都丟擲 ReferenceError"
            },
            {
              "icon": "",
              "label": "foo() 丟擲 ReferenceError；bar() 列印 \"b\""
            }
          ]
        },
        {
          "question": "function makeCounter() {\n  let count = 0;\n  return function() { count++; return count; };\n}\nconst counter = makeCounter();\nconsole.log(counter());\nconsole.log(counter());\n兩行列印什麼？",
          "options": [
            {
              "icon": "",
              "label": "1 然後 1"
            },
            {
              "icon": "",
              "label": "NaN 然後 NaN"
            },
            {
              "icon": "",
              "label": "undefined 然後 undefined"
            },
            {
              "icon": "",
              "label": "1 然後 2"
            }
          ]
        },
        {
          "question": "for (var i = 0; i < 3; i++) {\n  setTimeout(() => console.log(i), 0);\n}\n這會列印什麼？",
          "options": [
            {
              "icon": "",
              "label": "0, 1, 2"
            },
            {
              "icon": "",
              "label": "3, 3, 3"
            },
            {
              "icon": "",
              "label": "它丟擲 ReferenceError"
            },
            {
              "icon": "",
              "label": "undefined, undefined, undefined"
            }
          ]
        },
        {
          "question": "for (let i = 0; i < 3; i++) {\n  setTimeout(() => console.log(i), 0);\n}\n這會列印什麼？",
          "options": [
            {
              "icon": "",
              "label": "3, 3, 3"
            },
            {
              "icon": "",
              "label": "它丟擲 ReferenceError"
            },
            {
              "icon": "",
              "label": "undefined, undefined, undefined"
            },
            {
              "icon": "",
              "label": "0, 1, 2"
            }
          ]
        },
        {
          "question": "function greet() { return `Hi, ${this.name}`; }\nconst person = { name: 'Ana' };\nconsole.log(greet.call(person));\n這會列印什麼？",
          "options": [
            {
              "icon": "",
              "label": "\"Hi, Ana\""
            },
            {
              "icon": "",
              "label": "\"Hi, undefined\""
            },
            {
              "icon": "",
              "label": "它丟擲 TypeError"
            },
            {
              "icon": "",
              "label": "\"Hi, ${this.name}\""
            }
          ]
        },
        {
          "question": "const timer = {\n  seconds: 0,\n  start: function() {\n    setInterval(() => { this.seconds++; }, 1000);\n  },\n};\n為什麼人們在這裡的 setInterval 內更喜歡箭頭函式而非 function() { this.seconds++ }？",
          "options": [
            {
              "icon": "",
              "label": "箭頭函式沿用 start 的 this，即 timer"
            },
            {
              "icon": "",
              "label": "箭頭函式的執行速度比普通函式更快"
            },
            {
              "icon": "",
              "label": "箭頭函式會把 this 繫結到全域性物件"
            },
            {
              "icon": "",
              "label": "箭頭函式會把 this 變成一個全域性變數"
            }
          ]
        },
        {
          "question": "function multiply(a, b) { return a * b; }\nconst double = multiply.bind(null, 2);\nconsole.log(double(5));\n這會列印什麼？",
          "options": [
            {
              "icon": "",
              "label": "5"
            },
            {
              "icon": "",
              "label": "10"
            },
            {
              "icon": "",
              "label": "NaN"
            },
            {
              "icon": "",
              "label": "7"
            }
          ]
        },
        {
          "question": "function outer() {\n  let x = 10;\n  function inner() {\n    let x = 20;\n    console.log(x);\n  }\n  inner();\n  console.log(x);\n}\nouter();\n兩個 console.log 呼叫列印什麼？",
          "options": [
            {
              "icon": "",
              "label": "20 然後 20"
            },
            {
              "icon": "",
              "label": "20 然後 10"
            },
            {
              "icon": "",
              "label": "10 然後 10"
            },
            {
              "icon": "",
              "label": "它丟擲 SyntaxError"
            }
          ]
        },
        {
          "question": "const a = [1, 2, 3];\nconst b = a;\nb.push(4);\nconsole.log(a.length);\n這會列印什麼？",
          "options": [
            {
              "icon": "",
              "label": "3"
            },
            {
              "icon": "",
              "label": "undefined"
            },
            {
              "icon": "",
              "label": "它丟擲 TypeError"
            },
            {
              "icon": "",
              "label": "4"
            }
          ]
        },
        {
          "question": "const original = { name: 'Ana', tags: ['x', 'y'] };\nconst copy = { ...original };\ncopy.name = 'Bea';\ncopy.tags.push('z');\nconsole.log(original.name, original.tags.length);\n這會列印什麼？",
          "options": [
            {
              "icon": "",
              "label": "'Ana' 2"
            },
            {
              "icon": "",
              "label": "'Ana' 3"
            },
            {
              "icon": "",
              "label": "'Bea' 3"
            },
            {
              "icon": "",
              "label": "'Bea' 2"
            }
          ]
        },
        {
          "question": "const { a: x = 10, b: y = 20 } = { a: 5 };\nconsole.log(x, y);\n這會列印什麼？",
          "options": [
            {
              "icon": "",
              "label": "undefined undefined"
            },
            {
              "icon": "",
              "label": "5 undefined"
            },
            {
              "icon": "",
              "label": "10 20"
            },
            {
              "icon": "",
              "label": "5 20"
            }
          ]
        },
        {
          "question": "const [first, ...rest] = [1, 2, 3, 4];\nconsole.log(rest);\n這會列印什麼？",
          "options": [
            {
              "icon": "",
              "label": "[1, 2, 3, 4]"
            },
            {
              "icon": "",
              "label": "[2, 3, 4]"
            },
            {
              "icon": "",
              "label": "2"
            },
            {
              "icon": "",
              "label": "[1]"
            }
          ]
        },
        {
          "question": "const nums = [10, 1, 2];\nnums.sort();\nconsole.log(nums);\n這會列印什麼？",
          "options": [
            {
              "icon": "",
              "label": "[1, 2, 10]"
            },
            {
              "icon": "",
              "label": "[10, 1, 2]"
            },
            {
              "icon": "",
              "label": "[1, 10, 2]"
            },
            {
              "icon": "",
              "label": "[2, 1, 10]"
            }
          ]
        },
        {
          "question": "const user = { profile: { age: 0 } };\nconsole.log(user.profile?.age ?? 'unknown');\nconsole.log(user.address?.city ?? 'unknown');\n兩行列印什麼？",
          "options": [
            {
              "icon": "",
              "label": "'unknown' 然後 'unknown'"
            },
            {
              "icon": "",
              "label": "0 然後 'unknown'"
            },
            {
              "icon": "",
              "label": "0 然後 undefined"
            },
            {
              "icon": "",
              "label": "'unknown' 然後 0"
            }
          ]
        },
        {
          "question": "const obj = { a: undefined, b: function(){}, c: NaN, d: [undefined, function(){}, 1] };\nconsole.log(JSON.stringify(obj));\n這會列印什麼？",
          "options": [
            {
              "icon": "",
              "label": "'{\"a\":null,\"b\":null,\"c\":null,\"d\":[null,null,1]}'"
            },
            {
              "icon": "",
              "label": "'{\"c\":NaN,\"d\":[1]}'"
            },
            {
              "icon": "",
              "label": "'{\"c\":null,\"d\":[null,null,1]}'"
            },
            {
              "icon": "",
              "label": "它丟擲 TypeError"
            }
          ]
        },
        {
          "question": "console.log('1');\nsetTimeout(() => console.log('2'), 0);\nPromise.resolve().then(() => console.log('3'));\nconsole.log('4');\n這些按什麼順序列印？",
          "options": [
            {
              "icon": "",
              "label": "1, 2, 3, 4"
            },
            {
              "icon": "",
              "label": "1, 4, 2, 3"
            },
            {
              "icon": "",
              "label": "1, 4, 3, 2"
            },
            {
              "icon": "",
              "label": "1, 3, 4, 2"
            }
          ]
        },
        {
          "question": "async function foo() {\n  console.log('a');\n  await null;\n  console.log('b');\n}\nconsole.log('start');\nfoo();\nconsole.log('end');\n這些按什麼順序列印？",
          "options": [
            {
              "icon": "",
              "label": "start, a, end, b"
            },
            {
              "icon": "",
              "label": "start, a, b, end"
            },
            {
              "icon": "",
              "label": "start, end, a, b"
            },
            {
              "icon": "",
              "label": "a, start, end, b"
            }
          ]
        },
        {
          "question": "Promise.all([\n  Promise.resolve(1),\n  Promise.reject('err'),\n  Promise.resolve(3),\n]).then(r => console.log('ok', r)).catch(e => console.log('fail', e));\n這會列印什麼？",
          "options": [
            {
              "icon": "",
              "label": "'fail err'"
            },
            {
              "icon": "",
              "label": "'ok' [1, 3]"
            },
            {
              "icon": "",
              "label": "'ok' [1, undefined, 3]"
            },
            {
              "icon": "",
              "label": "丟擲異常，且沒有任何處理程序執行"
            }
          ]
        },
        {
          "question": "const fast = new Promise(res => setTimeout(() => res('fast'), 10));\nconst slow = new Promise(res => setTimeout(() => res('slow'), 100));\nPromise.race([fast, slow]).then(v => console.log(v));\n這會列印什麼？",
          "options": [
            {
              "icon": "",
              "label": "'slow'"
            },
            {
              "icon": "",
              "label": "['fast', 'slow']"
            },
            {
              "icon": "",
              "label": "'fast'"
            },
            {
              "icon": "",
              "label": "它丟擲 TypeError"
            }
          ]
        },
        {
          "question": "function Animal(name) { this.name = name; }\nAnimal.prototype.speak = function() { return `${this.name} makes a sound`; };\nconst dog = new Animal('Rex');\nconsole.log(dog.speak());\nconsole.log(dog.hasOwnProperty('speak'));\n兩行列印什麼？",
          "options": [
            {
              "icon": "",
              "label": "'Rex makes a sound' 然後 true"
            },
            {
              "icon": "",
              "label": "undefined 然後 false"
            },
            {
              "icon": "",
              "label": "它丟擲 TypeError"
            },
            {
              "icon": "",
              "label": "'Rex makes a sound' 然後 false"
            }
          ]
        },
        {
          "question": "class Counter {\n  #count = 0;\n  increment() { this.#count++; return this.#count; }\n}\nconst c = new Counter();\nconsole.log(c.increment());\nconsole.log(c.count);\n兩行列印什麼？",
          "options": [
            {
              "icon": "",
              "label": "1 然後 undefined"
            },
            {
              "icon": "",
              "label": "1 然後 0"
            },
            {
              "icon": "",
              "label": "1 然後 1"
            },
            {
              "icon": "",
              "label": "它丟擲 SyntaxError"
            }
          ]
        },
        {
          "question": "const items = ['a', 'b'];\nconst label = `Items: ${items.length > 0 ? items.join(', ') : 'none'}`;\nconsole.log(label);\n這會列印什麼？",
          "options": [
            {
              "icon": "",
              "label": "'Items: ${items.length > 0 ? items.join(\\', \\') : \\'none\\'}'"
            },
            {
              "icon": "",
              "label": "'Items: none'"
            },
            {
              "icon": "",
              "label": "'Items: a, b'"
            },
            {
              "icon": "",
              "label": "它丟擲 SyntaxError"
            }
          ]
        },
        {
          "question": "const nums = [1, 2, 3, 4, 5];\nconst result = nums.filter(n => n % 2 === 0).map(n => n * 10).reduce((sum, n) => sum + n, 0);\nconsole.log(result, nums);\n這會列印什麼？",
          "options": [
            {
              "icon": "",
              "label": "60 [1, 2, 3, 4, 5]"
            },
            {
              "icon": "",
              "label": "60 [2, 4, 20, 40]"
            },
            {
              "icon": "",
              "label": "150 [1, 2, 3, 4, 5]"
            },
            {
              "icon": "",
              "label": "60 [20, 40]"
            }
          ]
        }
      ],
      "optionOrderVersion": "7335aa056fc9d33a"
    }
  },
  "testNames": {
    "javascript-test": "JavaScript 技能"
  }
}
