{
  "assessmentTests": {
    "javascript_test": {
      "name": "JavaScript 테스트",
      "desc": "기본 구문 및 타입 강제, 함수/범위/클로저 및 this, 객체/배열 및 데이터 구조, 이벤트 루프/async/프로토타입 관용구에 관한 30개의 시나리오 질문 — 귀하의 JavaScript 능력이 채용공고에서 의미하는 JavaScript 숙련도와 일치하는지 알아보세요.",
      "recommendation": "귀하의 JavaScript 기술 프로필",
      "results": {
        "beginner": {"name": "초급자", "desc": "작동하는 함수와 객체를 작성할 수 있지만, 놓친 질문들은 구문보다는 타입 강제 및 참조 의미론에 집중되어 있습니다 — == 비교 전에 조용히 타입을 강제, 배열 할당이 복사가 아닌 하나의 객체를 공유, NaN이 자신과 같지 않은 이유. 이는 JavaScript가 약하다는 뜻이 아니라, 작동하는 코드를 작성하여 언어를 배운 사람들을 잡는 특정 규칙입니다. 값과 참조가 실제로 어떻게 작동하는지 배운 사람들은 이를 놓치지 않습니다. 업무에서 중요한 이유는 각각이 코드를 에러 없이 실행하지만 잘못된 일을 하는 장소이기 때문입니다.", "recommendation": "세 가지부터 시작하세요, 이 순서로: == 타입을 강제하는 이유와 === 그렇지 않은 이유, 배열 또는 객체를 새 변수에 할당하면 값이 아닌 참조를 복사하는 이유, var가 호이스트되고 undefined로 초기화되는 반면 let과 const는 선언 줄이 실행될 때까지 temporal dead zone에 머무르는 이유. MDN의 JavaScript 가이드는 실행 가능한 예제와 함께 이 세 가지를 모두 다룹니다."},
        "intermediate": {"name": "중급자", "desc": "일상적인 응용 프로그램 코드를 편하게 다루고 있으며, 기존 코드베이스 유지보수나 일반적인 기능 작업으로 인해 지연되지 않습니다. 여기서 고급으로의 격차는 주로 JavaScript의 범위 및 타이밍 규칙이 상호 작용하는 경우입니다: 루프 콜백 내에서 var를 캡처하면 모두 동일한 최종값을 읽고, 메서드가 객체에서 분리되면 this가 조용히 해당 객체를 더 이상 가리키지 않으며, 스프레드 복사가 깊어 보이지만 최상위 수준만 복사합니다. 이는 빠른 읽기에서 발견되지 않고 특정 런타임 조건에서만 나타나는 버그의 종류입니다.", "recommendation": "범위 및 this가 호출 시점에 실제로 어떻게 해결되는지에 초점을 맞추세요: var 기반 for 루프가 모든 콜백에 동일한 카운터 최종값을 전달하는 이유와 let이 그렇지 않은 이유, this가 작성된 위치가 아닌 호출 방식으로 결정되는 이유, 스프레드 및 Object.assign이 객체의 최상위 수준만 복사하는 이유. 그 다음 이벤트 루프, 이미 개별적으로 promise를 알고 있는 사람들이 이에 걸려드는 이유입니다."},
        "advanced": {"name": "고급", "desc": "대부분의 채용공고가 '강한 JavaScript'라고 의미하는 수준입니다. filter/map/reduce 체인을 읽고 원본 배열을 변경하지 않으면서 정확히 무엇을 반환하는지 예측할 수 있으며, 동기식 console.log가 항상 microtask를 이기고 microtask가 항상 setTimeout을 이기는 이유를 알고, Promise.all을 사용할 때 나머지를 기다리지 않고 입력 promise 중 하나가 거부되는 순간 거부되는 것을 알고 있습니다. 이 대역을 최상위에서 분리하는 것은 프로토타입 및 객체 모델 측면입니다: 프로토타입 체인이 인스턴스에 없는 상속 메서드를 어떻게 해결하는지, 클래스 private #fields가 외부 접근으로부터 실제로 무엇을 숨기는지.", "recommendation": "다른 코드도 터치하는 상태를 보호하는 측면으로 나아가세요: JavaScript의 프로토타입 체인이 인스턴스 자체에 없는 메서드 조회를 어떻게 해결하는지, 클래스의 private #fields가 외부 접근으로부터 무엇을 숨기는지, JSON.stringify가 일반 객체 내부와 배열 내부에서 undefined 및 함수를 다르게 처리하는 방법. MDN의 이벤트 루프 및 프로토타입 체인에 대한 자료는 둘 다에 대한 자연스러운 다음 단계입니다."},
        "expert": {"name": "전문가", "desc": "모든 섹션 — 기본 구문 및 타입 강제, 함수, 범위, 클로저 및 this, 객체, 배열 및 데이터 구조, async, 이벤트 루프, 프로토타입 및 관용구에서 최고 점수를 얻었습니다. 실제로, 이는 낯선 사람의 함수가 제공될 때 구문이 반환되어야 하는 것뿐만 아니라 왜 반환되는지 설명할 수 있음을 의미합니다. 이는 더 어렵고 더 가치 있는 기술입니다. 이 수준에서 언어 자체는 거의 업무의 제한 요소가 아닙니다. 제한은 일반적으로 async 제어 흐름 또는 그 아래의 데이터 형태입니다.", "recommendation": "반환은 이제 설계 및 진단에 있습니다: Promise.all과 Promise.race 사이의 경쟁 조건에 대해 추론하고 정의를 낭송하는 대신, private 상태에 대해 클로저가 올바른 도구인지 vs 클래스의 private 필드가 올바른 도구인지 선택, 프로덕션 로그에서 microtask-vs-macrotask 순서 버그를 읽습니다. 역할에 대한 심사를 받는 중이라면, JavaScript 기능을 이름으로 나열하는 대신 발견한 타이밍 버그 — stale closure 변수 또는 순서가 맞지 않은 async 콜백 — 를 설명하세요. 어휘력이 아닌 추론의 힘을 보여줍니다."}
      },
      "questions": [
        {"question": "console.log(x);\nvar x = 5;\n이것은 무엇을 출력합니까?", "options": [{"icon": "", "label": "5 — var 선언은 다른 모든 코드 이전에 실행됩니다"}, {"icon": "", "label": "ReferenceError: x가 정의되지 않음"}, {"icon": "", "label": "undefined — var 선언은 해당 범위의 최상위로 호이스트되고 undefined로 초기화되지만, 할당은 제자리에서 실행되므로 실행 전에 변수는 존재하지만 undefined를 보유합니다"}, {"icon": "", "label": "null"}]},
        {"question": "console.log(y);\nlet y = 5;\n이것은 무엇을 일으킵니까?", "options": [{"icon": "", "label": "ReferenceError: '초기화 전 y'에 접근할 수 없음 — let은 해당 범위의 최상위로 호이스트되지만 선언 줄이 실행될 때까지 temporal dead zone에 머물러 있습니다"}, {"icon": "", "label": "undefined를 출력합니다, var와 마찬가지로"}, {"icon": "", "label": "5를 출력합니다"}, {"icon": "", "label": "파싱 시에 SyntaxError를 발생시킵니다"}]},
        {"question": "const arr = [1, 2, 3];\narr.push(4);\nconsole.log(arr.length);\n이것은 무엇을 출력합니까?", "options": [{"icon": "", "label": "4 — const는 arr 바인딩 자체의 재할당만 방지하고, 그것이 가리키는 객체의 변경은 방지하지 않으므로 push는 여전히 작동합니다"}, {"icon": "", "label": "TypeError를 발생시킵니다, arr이 const이기 때문입니다"}, {"icon": "", "label": "3 — const 배열에서 push가 차단됩니다"}, {"icon": "", "label": "undefined"}]},
        {"question": "console.log('' == 0);\nconsole.log('' === 0);\n두 줄은 무엇을 출력합니까?", "options": [{"icon": "", "label": "true 그 다음 true"}, {"icon": "", "label": "false 그 다음 false"}, {"icon": "", "label": "true 그 다음 false — == 비교 전에 빈 문자열을 0으로 강제하지만, ===는 강제 없이 타입과 값을 비교하며, 문자열은 숫자와 엄격히 같을 수 없습니다"}, {"icon": "", "label": "false 그 다음 true"}]},
        {"question": "console.log(NaN === NaN);\nconsole.log(Number.isNaN(NaN));\n두 줄은 무엇을 출력합니까?", "options": [{"icon": "", "label": "true 그 다음 true"}, {"icon": "", "label": "true 그 다음 false"}, {"icon": "", "label": "false 그 다음 false"}, {"icon": "", "label": "false 그 다음 true — NaN은 JavaScript에서 === 아래 자신과 같지 않은 유일한 값이지만, Number.isNaN()은 어쨌든 올바르게 감지합니다"}]},
        {"question": "console.log(typeof null);\n이것은 무엇을 출력합니까?", "options": [{"icon": "", "label": "\"null\""}, {"icon": "", "label": "\"object\" — 언어의 오래된 버그: typeof null은 null이 원시적이더라도 \"object\"를 반환하며, 이래로 역호환성을 위해 유지되었습니다"}, {"icon": "", "label": "\"undefined\""}, {"icon": "", "label": "\"boolean\""}]},
        {"question": "if 조건에서 어느 것이 truthy입니까?", "options": [{"icon": "", "label": "0"}, {"icon": "", "label": "\"\" (빈 문자열)"}, {"icon": "", "label": "null"}, {"icon": "", "label": "\"0\" — 비어있지 않은 문자열은 JavaScript에서 항상 truthy이며, 그 내용이 문자열 \"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: bar는 함수가 아님을 발생시킵니다 — 함수 선언은 본문 전체로 호이스트되지만, var 할당된 함수 표현식은 var 자체만 호이스트됩니다 (undefined로), 할당은 아닙니다"}, {"icon": "", "label": "두 호출 모두 ReferenceError를 발생시킵니다"}, {"icon": "", "label": "foo()는 발생; 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": "0 그 다음 1"}, {"icon": "", "label": "undefined 그 다음 undefined"}, {"icon": "", "label": "1 그 다음 2 — 반환된 함수는 makeCounter 범위의 동일한 count 변수를 클로저하며, 해당 변수는 호출 사이에 리셋되지 않고 유지됩니다"}]},
        {"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 — var는 함수 범위이지 블록 범위가 아니므로, 세 개의 콜백 모두 동일한 i를 클로저하며, 이는 이미 루프를 끝내고 이들 중 어느 것이라도 실행될 때쯤 3과 같습니다"}, {"icon": "", "label": "0, 0, 0"}, {"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": "0, 0, 0"}, {"icon": "", "label": "undefined, undefined, undefined"}, {"icon": "", "label": "0, 1, 2 — let은 루프의 각 반복에 대해 i의 새로운 바인딩을 만들므로, 각 콜백은 하나의 공유 변수가 아닌 자신의 별도 복사본을 클로저합니다"}]},
        {"question": "function greet() { return `Hi, ${this.name}`; }\nconst person = { name: 'Ana' };\nconsole.log(greet.call(person));\n이것은 무엇을 출력합니까?", "options": [{"icon": "", "label": "\"Hi, Ana\" — Function.prototype.call은 this를 첫 번째 인수로 명시적으로 설정하여 함수를 호출하므로 this.name은 person에 대해 해결됩니다"}, {"icon": "", "label": "\"Hi, undefined\" — call()은 객체의 메서드인 함수에서만 작동합니다"}, {"icon": "", "label": "TypeError를 발생시킵니다, greet이 person의 메서드가 아니기 때문입니다"}, {"icon": "", "label": "\"Hi, ${this.name}\" — call()은 템플릿 리터럴을 평가하지 않습니다"}]},
        {"question": "const timer = {\n  seconds: 0,\n  start: function() {\n    setInterval(() => { this.seconds++; }, 1000);\n  },\n};\nsetInterval 내에서 사람들이 function() { this.seconds++ } 대신 화살표 함수를 선호하는 이유는 무엇입니까?", "options": [{"icon": "", "label": "화살표 함수는 자신의 this를 갖지 않습니다 — 주변 start 함수에서 렉시컬적으로 this를 캡처합니다. start가 timer.start()로 호출되었으므로 this는 timer이고, this.seconds는 모든 틱에서 올바르게 timer.seconds를 가리킵니다"}, {"icon": "", "label": "화살표 함수는 런타임에 일반 함수보다 더 빠르게 실행됩니다"}, {"icon": "", "label": "화살표 함수는 자동으로 this를 전역 객체에 바인딩합니다, 이것이 timer와 같습니다"}, {"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": "bind가 두 인수를 모두 미리 요구하기 때문에 오류를 발생시킵니다"}, {"icon": "", "label": "10 — bind는 this와 모든 선행 인수가 미리 설정된 새로운 함수를 반환합니다; double(5)를 호출하면 나머지 인수 b=5를 제공하므로 multiply(2, 5)가 실행됩니다"}, {"icon": "", "label": "NaN"}, {"icon": "", "label": "7, bind가 호출에 인수를 추가하기 때문입니다"}]},
        {"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 — inner의 자신의 let x는 inner의 범위 내에서만 outer의 x를 섀도하고; outer의 자신의 x는 절대 변경되지 않습니다"}, {"icon": "", "label": "10 그 다음 10"}, {"icon": "", "label": "x가 두 번 선언되었기 때문에 ReferenceError를 발생시킵니다"}]},
        {"question": "const a = [1, 2, 3];\nconst b = a;\nb.push(4);\nconsole.log(a.length);\n이것은 무엇을 출력합니까?", "options": [{"icon": "", "label": "3 — b는 a의 독립적인 복사본입니다"}, {"icon": "", "label": "undefined"}, {"icon": "", "label": "a가 const이기 때문에 TypeError를 발생시킵니다"}, {"icon": "", "label": "4 — 배열은 객체이므로 const b = a는 배열이 아닌 참조를 복사합니다; push로 b를 변경하면 a가 가리키는 정확한 동일한 배열도 변경됩니다"}]},
        {"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 — 스프레드는 얕은 복사일 뿐입니다: name과 같은 원시 속성은 값으로 복사되므로 copy.name을 재할당해도 original은 영향을 받지 않습니다; tags와 같은 중첩 배열은 참조로 복사되므로 copy.tags에 푸시하면 original.tags가 가리키는 정확한 동일한 배열이 변경됩니다"}, {"icon": "", "label": "'Bea' 3 — 스프레드는 모든 것을 참조로 복사하므로 최상위 및 중첩 변경 모두 original으로 다시 돌아옵니다"}, {"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 — a는 x로 이름이 변경되고 존재하므로 값 5를 유지합니다; b는 y로 이름이 변경되고 존재하지 않으므로 기본값 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] — rest는 first 이후의 모든 나머지 요소를 새로운 배열로 수집합니다"}, {"icon": "", "label": "2"}, {"icon": "", "label": "[1]"}]},
        {"question": "const nums = [10, 1, 2];\nnums.sort();\nconsole.log(nums);\n이것은 무엇을 출력합니까?", "options": [{"icon": "", "label": "[1, 2, 10] — sort는 항상 기본적으로 숫자를 수치적으로 오름차순으로 정렬합니다"}, {"icon": "", "label": "[10, 1, 2] — sort는 원본 배열을 변경하지 않습니다"}, {"icon": "", "label": "[1, 10, 2] — Array.prototype.sort의 기본 비교기는 요소를 문자열로 변환하고 사전식으로 비교하므로 \"10\"이 \"2\" 앞에 정렬됩니다; sort는 새로운 배열을 반환하는 대신 제자리에서 변경합니다"}, {"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' — ??는 0을 ||과 같은 방식으로 누락된 것으로 취급합니다"}, {"icon": "", "label": "0 그 다음 'unknown' — ??는 null 또는 undefined에서만 돌아오고, 0과 같은 다른 falsy 값에서는 돌아오지 않습니다. age (0)는 그대로 유지됩니다; user.address는 undefined이므로 ?. 전체 체인을 undefined로 단락시키고 ??는 '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]}' — 모든 지원되지 않는 값은 객체 및 배열과 같은 방식으로 어디서나 null이 됩니다"}, {"icon": "", "label": "'{\"a\":undefined,\"b\":undefined,\"c\":NaN,\"d\":[undefined,null,1]}'"}, {"icon": "", "label": "'{\"c\":null,\"d\":[null,null,1]}' — 값이 undefined 또는 함수인 객체 속성은 완전히 생략되고, NaN은 null로 직렬화되지만, 배열 내에서 이러한 동일한 지원되지 않는 값은 드롭되는 대신 null이 됩니다. 배열 요소를 제거하면 이후의 모든 인덱스가 이동합니다"}, {"icon": "", "label": "NaN을 JSON으로 직렬화할 수 없기 때문에 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 — 동기 코드가 먼저 실행됩니다 (1과 4가 즉시 출력), 그 다음 마이크로태스크 큐 (Promise 콜백)가 다음 매크로태스크로 이동하기 전에 완전히 드레인되므로 3이 setTimeout 콜백 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 — foo()는 첫 번째 await까지 동기적으로 실행되므로 foo()가 호출될 때 'a'가 즉시 로깅됩니다; await는 foo를 중단하고 호출자에게 제어를 반환하므로 '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' — Promise.all은 입력 promise 중 하나가 거부되는 즉시 거부되고, 다른 promise의 결과를 무시하므로 catch 핸들러가 해당 거부의 이유로 실행됩니다"}, {"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' — Promise.race는 입력 promise 중 하나가 settle되는 즉시 settle되고, 10ms 타이머가 100ms 타이머보다 훨씬 먼저 resolve됩니다"}, {"icon": "", "label": "race가 정확히 두 개의 promise를 요구하기 때문에 오류를 발생시킵니다"}]},
        {"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": "dog가 자신의 speak 메서드를 갖지 않기 때문에 TypeError를 발생시킵니다"}, {"icon": "", "label": "'Rex makes a sound' 그 다음 false — speak은 dog 인스턴스 자체가 아닌 Animal.prototype에서 정의되며; dog는 호출될 때 프로토타입 체인을 통해 이를 찾지만, hasOwnProperty는 인스턴스의 자신의 속성만 확인하고, 상속된 것은 확인하지 않습니다"}]},
        {"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 — #count는 private 클래스 필드이며, 클래스 자신의 메서드 내에서만 읽고 쓸 수 있습니다; c.count (#없음)는 설정되지 않은 완전히 다른 일반 속성이므로 undefined입니다"}, {"icon": "", "label": "1 그 다음 0"}, {"icon": "", "label": "1 그 다음 1"}, {"icon": "", "label": "c.count에 접근할 때 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] — filter, map 및 reduce는 각각 원본 배열을 변경하지 않으면서 새로운 배열이나 값을 반환합니다; nums는 변경되지 않고 result는 최종 감소된 합입니다 (2와 4, 20과 40으로 두 배, 60으로 합산됨)"}, {"icon": "", "label": "60 [2, 4, 20, 40]"}, {"icon": "", "label": "150 [1, 2, 3, 4, 5]"}, {"icon": "", "label": "60 [20, 40]"}]}
      ],
      "optionOrderVersion": "50fc0eba818f2d72"
    }
  }
}
