본문으로 건너뛰기
yceffort
PostsSeriesTagsAbout🧪 Research
EN

Tweaks

theme
accent palette
film grain
minimal mode
BACK TO INDEX
◆ ESSAY
--min
--year
KOoriginal

mailMail icongithubtwitter
yceffort
•
© 2026
•
https://yceffort.kr
BACK TO INDEX
◆ ESSAY

자바스크립트 스킬을 향상 시킬 10개의 질문

avatar
yceffort
2020-06-03 · 6분
6min
2020year
KOoriginal
javascript

자바스크립트 스킬을 향상 시킬 10개의 질문

10 JavaScript Quiz Questions and Answers to Sharpen Your Skills 의 질문을 보고, 답에 대한 해석을 제멋대로 써보았습니다.

1. 배열 정렬 비교

const arr1 = ['a', 'b', 'c']
const arr2 = ['b', 'c', 'a']

console.log(
  arr1.sort() === arr1,
  arr2.sort() == arr2,
  arr1.sort() === arr2.sort(),
)

당연한 얘기지만, 자바스크립트에서의 비교는 (==, ===), 원시 타입이 아니라면 reference를 참조해서 비교하게 된다. 먼저 첫 번째 부터 알아보자. sort()는 적절하게 정렬한 후에 그 배열 자체를 반환한다고 되어 있다.

sort() 메서드는 배열의 요소를 적절한 위치에 정렬한 후 그 배열을 반환합니다.

따라서 저 arr1.sort()의 결과가 맞던지 틀리던지 상관없이, 같은 참조값을 리턴하므로 true가 된다.

두 번째도 앞선 이유와 마찬가지로, 정렬의 결과가 어쨌든 간에 - 같은 참조를 하고 있으므로 true를 리턴하게 된다. 세 번째 역시, 앞선 이유와 같이 정렬의 결과를 비교하는게 아닌 참조를 비교하게 되므로 false가 된다.

만약 자바스크립트의 배열을 비교 하고 싶다면 어떻게 해야할까? stackoverflow에 미친 답변들이 많지만, JSON.stringify를 이용하는게 가장 쉬울 것 같다.

2. Set에 Object가 들어 있다면?

const mySet = new Set([{a: 1}, {a: 1}])
const result = [...mySet]
console.log(result)

Set은 어디까지나 원시값을 비교해서 제거하므로, {a: 1}이라는 중복을 제거해주지 않는다. 따라서

[{a: 1}, {a: 1}]가 나올 것이다.

3. Deep Object.freeze

const user = {
  name: 'Joe',
  age: 25,
  pet: {
    type: 'dog',
    name: 'Buttercup',
  },
}

Object.freeze(user)

user.pet.name = 'Daffodil'

console.log(user.pet.name)

Object.freeze는 객체를 동결시키는 메소드다. 동결된 객체는 새로운 속성을 추가하거나, 제거, 삭제를 할 수 없다. 그러나 freeze는 얕은 동결만 수행한다. 따라서, Object안에 있는 object에 대해서는 동결이 되지 않는다. 따라서 문제의 결과는 변경된 값을 리턴하게 된다. 하위 객체까지 모두 동결 시키기 위해서는, 재귀함수를 활용해야 할 것이다.

function deepFreeze(object) {
  const propNames = Object.getOwnPropertyNames(object)

  for (const name of propNames) {
    const value = object[name]

    // 값이 존재하고, 그값이 object라면 다시 deepFreeze를 수행한다.
    object[name] =
      value && typeof value === 'object' ? deepFreeze(value) : value
  }

  return Object.freeze(object)
}

혹은 deep-freeze라이브러리를 써도 된다.

4. 프로토타입 상속

function Dog(name) {
  this.name = name
  this.speak = function () {
    return 'woof'
  }
}

const dog = new Dog('Pogo')

Dog.prototype.speak = function () {
  return 'arf'
}

console.log(dog.speak())

Dog 인스턴스가 생성될때마다, speak 프로퍼티에는 woof를 반환하는 함수가 매번 할당되게 된다. 그 결과, 인터프리터는 이미 speak가 프로퍼티에 할당되어 있으므로, prototype체인을 보지 않는다. 따라서, prototype으로 할당한 speak는 쓰이지 않게 된다.

5. Promise.all의 순서

const timer = (a) => {
  return new Promise((res) =>
    setTimeout(() => {
      res(a)
    }, Math.random() * 100),
  )
}

const all = Promise.all([timer('first'), timer('second')]).then((data) =>
  console.log(data),
)

Promise.all에 관해 물어보는 문제다. Promise.all은 배열 안에 있는 모든 Promise가 실행되거나 어느 하나라도 거부되기를 기다린다. 따라서 배열안에 있는 Promise의 완료 순서와는 상관없이 모두 끝나기를 기다리므로, all에서의 data의 순서는 보장 될 것이다.

6. Reduce 계산

const arr = [(x) => x * 1, (x) => x * 2, (x) => x * 3, (x) => x * 4]

console.log(arr.reduce((agg, el) => agg + el(agg), 1))
1 + 1 * 1 = 2
2 + 2 * 2 = 6
6 + 6 * 3 = 24
24 + 24 * 4 = 120

7. 복수형 (s) 추가하기

const notifications = 1

console.log(
  `You have ${notifications} notification${notifications !== 1 && 's'}`,
)

&&는 false를 리턴할 것이다. 이를 정확히 표현하기 위해서는

notification >= 1 ? 's' : ''

이 되야 할 것이다.

8. 전개 구문과 변수명 변경

const arr1 = [{firstName: 'James'}]
const arr2 = [...arr1]
arr2[0].firstName = 'Jonah'

console.log(arr1)

전개 구문은 shallow copy를 수행하므로 사실상 arr2는 arr1을 가리키고 있다. 따라서, arr2를 바꾸는 것은 arr1에도 영향을 미친다.

9. 배열 함수에 바인딩

const map = ['a', 'b', 'c'].map.bind([1, 2, 3])
map((el) => console.log(el))

조금 의외였는데 - 생각해보니 당연한 거였다.

.map은 단순히 Array.prototype.map을 this 값과 함께 호출한 것이다. bind call apply는 함수에서 호출할 this를 지정할 수 있으므로, 결과는 1, 2, 3 이 된다.

10. Set의 유일성과 순서

const arr = [...new Set([3, 1, 2, 3, 4])]
console.log(arr.length, arr[2])

Set은 유일성은 보장해주지만, 순서는 보장하지 않는다. 따라서 길이는 4가 될 것이고, 3번째 엘리먼트는, 2가 될 것이다. arr은 3, 1, 2, 4

정리

  • 자바스크립트에서 원시형이 아닌 나머지는 reference 값을 가지고 있는 것일 뿐이므로, 비교를 할 때 주의를 해야 한다.
  • 얕은비교, 얕은복사에 대해서 잘 알아두자
  • 자바스크립트 내장 함수가 무엇을 리턴하는지 잘 확인해보자.

관련 글

  • #turbopack#nextjs#bundler

    Next.js turbopack에서 싱글톤이 두 개가 됐다: scope hoisting 버그와 순환 import

    Next.js 16 turbopack 프로덕션 빌드에서 모듈 스코프 싱글톤이 런타임에 두 개가 됐다. 같은 동기 구간에서 조건 판정이 뒤집히고, 응답이 도착해도 타임아웃이 나는 증상을 번들 산출물로 추적한 기록. scope hoisting의 부분 병합, 순환 import, 이미 고쳐져 있던 upstream 버그, 그리고 뒤늦게 돌린 단일 변수 실험까지.

    2026-08-19·28분
  • #javascript#animation#web-animations-api

    number-flow를 구형 브라우저로 이식하기: 다섯 가지 결정과 두 가지 번복

    number-flow가 애니메이션을 켜는 최소 버전은 Chrome 125, Safari 17.2다. 이 하한을 Chrome 66과 WebKit 16.4까지 내리는 포크를 만들면서 내린 결정들과, 뒤집게 된 판단 두 가지, 그리고 자동 강등을 포기한 Safari 버그 조사의 기록.

    2026-08-11·44분
  • #nodejs#security#javascript

    Node.js vm 모듈의 함정: 샌드박스가 아닌 이유

    집필 중인 Node.js Deep Dive의 5.2장(vm 모듈의 함정) 일부를 미리 공개합니다.

    2026-02-27·25분
  • #nodejs#javascript

    Node.js Deep Dive (가제) 베타 리더를 모십니다.

    많관부22

    2026-02-19·5분

새 글을 놓치고 싶지 않으시다면 RSS로 구독해 주세요.

RSS 구독 →

yceffort — 프론트엔드 엔지니어입니다. 발표·기술 자문·기고 문의는 이곳에서 받고 있습니다.

← Back to the blogIssue on GitHub →