Skip to content

sejungkim/javascript-learning-keywords

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

17 Commits
 
 
 
 

Repository files navigation

학습키워드 정리

1. 목표

  • 아래 질문에 대한 대답 정리하기
  • 각 질문에 대한 느낀 점도 포함하기
    • 어디에 쓸 수 있을지
    • 어떤 특징이 이러이러한 것 같다 등

2. 질문 리스트

1. 비트 연산자 보수 이해하기

1.1. 비트와 비트 연산자

  • bit란 binary digit로 컴퓨터에서 데이터의 가장 작은 단위이다. 0과 1을 사용하여 2진법으로 표현한다.
  • 비트 연산자는 Bitwise operators라고 하며 비트를 조작하는 연산자를 지칭한다.
  • 부호가 있는 정수는 가장 왼쪽 첫 번째에 있는 최상위 비트로 음수를 표현한다. 0은 양수, 1은 음수를 나타낸다. 부호를 표현하는 비트를 제외한 나머지 비트로 정수의 값을 표현한다.

1.2. 2진법의 음수 표현 - 2의 보수

  • 구하려는 음수의 절대값의 2진 표현을 구한 후 이 숫자에 대해 1의 보수를 구한다. 1의 보수는 1은 0으로, 0은 1로 바꾸면 된다.
  • 위의 결과에 1을 더한다.
    • 예를 들어 6비트로 -18을 표현해보자.
    • -18의 2진 표현을 구하기 위해 절대값 18의 2진 표현인 010010의 1의 보수를 구한다.
    • 010010의 1의 보수는 101101이다.
    • 101101에 1을 더한 101110이 -18의 6비트 정수 표현이다.

1.3. 비트연산자

1.3.1. 비트 NOT
  • ~a와 같이 틸데(~)를 사용하며, 피연산자의 1의 보수를 반환한다. 즉, 비트를 뒤집는다.
  • ~010010 => 101101
1.3.2. 비트 AND
  • a & b 처럼 앰퍼샌드(&)를 사용하여 두 개의 피연산자를 취한다.
  • 두 피연산자의 대응되는 비트가 모두 1이면 1을 반환하고, 아니면 0을 반환한다.
  • 1010 & 1001 => 1000
1.3.3. 비트 OR
  • a | b 와 같이 파이프(|)을 사용하여 두 개의 피연산자를 취한다.
  • 두 연산자의 대응되는 비트 중 하나라도 1이면 1을 반환하고, 아니면 0을 반환한다.
  • 1010 | 1001 => 1011
1.3.4. 비트 XOR
  • a ^ b 와 같이 캐럿(^)을 사용하여 두 개의 피연산자를 취한다.
  • 두 연산자의 대응되는 비트가 서로 다를 때 1을 반환, 그 외에는 0을 반환한다.
  • 1010 ^ 1001 => 0011
1.3.5. 왼쪽 시프트
  • a << b 와 같이 <<를 사용하여 두 개의 피연산자를 취한다.
  • 좌항의 모든 비트를 우항의 숫자만큼 왼쪽으로 움직이고, 오른쪽은 0으로 채운다. 부호는 유지한다.
  • 1010 << 2 => 101000
1.3.6. 부호 있는 오른쪽 시프트
  • a >> b 와 같이 >>를 사용하여 두 개의 피연산자를 취한다.
  • 좌항의 모든 비트를 우항의 숫자만큼 오른쪽으로 움직이고, 부호는 유지한다. 왼쪽은 부호 비트로 채우고 오른쪽 남는 비트는 버린다.
  • 11010 >> 2 => 11110
1.3.7. 부호 없는 오른쪽 시프트
  • a >>> b 와 같이 >>>를 사용하여 두 개의 피연산자를 취한다.
  • 좌항의 모든 비트를 우항의 숫자만큼 오른쪽으로 움직이고, 왼쪽은 0으로 채운다. 오른쪽 남는 비트는 버린다.
  • 11010 >>> 2 => 00110

1.4. 느낀 점

  • 어디에 어떤 용도로 사용할 수 있는지는 잘 모르겠지만, 컴퓨터 내부에서 이루어지는 정수 연산 방법을 이해하게 된 것 같다.

2. 10을 2진 표현으로 변경하려면 어떤 순서로 계산해야 하는지 설명하기

2.1. 설명

  1. 10을 2로 나눠 몫과 나머지를 구한다.
  2. 1에서 구한 나머지를 결과 배열에 unshift 한다.
  3. 1에서 구한 몫으로 1, 2번을 반복한다.
  4. 몫이 2보다 작을 때까지 반복한다.
  5. 2보다 작아진 마지막 몫의 값을 결과 배열에 마지막으로 unshift 한다.
  6. 결과 배열을 순서대로 출력한다.

2.2. 느낀 점

10진 표현을 2진 표현으로 변경하는 방법을 알게 됐고 코드로 구현하는 방법도 명확하게 알게 되었다. 알고리즘 문제로 나오면 금방 풀 수 있을 것 같다.


3. hoisting 에 대해서 설명하기

3.1. 호이스팅이란?

  • 자바스크립트에서 hoisting이란 변수와 함수의 선언이 그들이 포함된 scope의 최상단으로 끌어올려지는 것을 의미한다.
  • scope는 전역(global) 또는 지역(local) 범위가 있으며 자바스크립트에서 local은 대부분의 경우 함수 범위를 말한다.

3.2. 변수의 호이스팅

  • 변수는 식별자의 선언만 호이스팅되기 때문에 값 할당 구문 이전에 변수에 접근하게 되면 var로 선언된 변수의 경우 undefined 값을 갖고 있다.
  • let 또는 const로 선언된 변수 또한 호이스팅 되나, var와는 다르게 값 선언 구문 이전에 변수에 접근하게 되면 ReferenceError를, 선언 후 할당 전에 접근하게 되면 undefined 값을 출력한다.

3.3. 함수의 호이스팅

  • 함수 선언식의 경우 함수 전체가 호이스팅되며, 함수 표현식은 변수 호이스팅과 마찬가지로 함수를 할당하려는 변수의 식별자만 호이스팅 된다.
  • 위와 같은 이유로 함수 표현식으로 선언된 함수(특히 var)를 함수 할당 이전에 호출하게 되면 함수가 아니라는 TypeError가 출력된다.

3.4. 결론

자바스크립트에서 변수와 함수가 호이스팅 되는 특징은 변수와 함수가 어디서 선언되든 상관없이 접근하고 사용할 수 있다는 장점도 있지만, 코드의 실행 결과를 예측하기 어렵게 하고 잠재적 오류의 가능성을 높인다는 단점도 있다. 그래서 함수 표현식을 포함한 변수는 최대한 선언과 초기화 후에 접근 및 사용하는 것이 좋다.

3.5. 느낀 점

자바스크립트에서의 변수와 함수의 내부 동작 방식을 어느 정도 이해할 수 있게 되었고 왜 변수를 선언, 초기화 한 후 사용해야 하는지, 함수 선언식과 표현식의 차이가 무엇인지에 대해서도 알 수 있게 되었다. 이를 통해 잠재적 오류를 좀 더 쉽게 잡아낼 수 있을 것 같다.


4. !! 은 무엇을 의미하는가? 어떻게 활용할 수 있을까?

4.1. 설명

  • !!(double exclamation)은 논리연산자 NOT(!)을 두 번 쓴 것으로, boolean type이 아닌 값을 boolean type으로 바꿔주는 효과가 있다.
  • Boolean data type이란 true 또는 false의 두 가지 값만 갖는 데이터 타입이다.
  • 어떤 값에 논리연산자 NOT을 적용하면 그 값의 반대되는 boolean 값을 얻을 수 있지만, !를 두 번 적용하게 되면 한 번 더 NOT이 되므로 원래 값의 boolean 값을 얻을 수 있는 것이다.
    • !5 === false
    • !!5 === true
  • 즉, !!valueBoolean(value)와 같은 효과가 있다.
    • !!5 === Boolean(5)

4.2. 느낀 점

!은 자주 썼었지만 !!은 사실 처음 봤는데 어떤 값의 boolean 값을 얻고 싶을 때 편리하게 사용할 수 있을 것 같다.


5. 3개 이상의 switch 문을 어떻게 3항 연산자로 대체할 수 있을까? 코드로 예시를 들라.

5.1. 설명

삼항 연산자는 conditional operator 또는 ternary operator라고 하는데, 자바스크립트의 연산자 중 유일하게 3개의 피연산자를 갖는다.

다음과 같은 3개 이상의 case를 갖는 switch 문이 있다고 하자.

const value = 4;

switch (value) {
  case 1:
    console.log('one');
    break;
  case 2:
    console.log('two');
    break;
  case 3:
    console.log('three');
    break;
  default:
    console.log('nothing');
}

value 값에 따라 다른 결과를 출력하는 간단한 예제인데, 이 코드를 삼항 연산자로 바꾸어 똑같이 동작하도록 만들 수 있다. 삼항 연산자로 바꾼 코드는 아래와 같다.

const value = 4;

value === 1 ? console.log('one')
: value === 2 ? console.log('two')
: value === 3 ? console.log('three')
: console.log('nothing');

3가지 case일 때 뿐만 아니라 그 이상의 case가 있어도 위와 같이 삼항 연산자를 이용하여 코드를 작성할 수 있다.

5.2. 느낀 점

2개의 케이스가 있을 때만 삼항 연산자를 사용했었는데 3개 이상의 케이스에서도 삼항 연산자를 사용할 수 있다는 걸 새로 알게 됐다. 또, if-else 문 뿐만 아니라 switch 문도 삼항 연산자로 바꿔 쓸 수 있음을 알 수 있었다. 코드 작성 중 적합한 경우에 삼항 연산자를 잘 이용하면 더욱 간결한 코드를 작성할 수 있을 것 같다.


6. ==와 ===의 차이는 정확히 무엇인가?

6.1. 설명

  • ==는 Double equals로 느슨한 같음(abstract comparison)을 비교한다. ==는 비교하려는 두 값이 type이 다르면 비교 가능한 같은 type으로 강제 형 변환을 한 후 엄격한 비교를 한다.
  • ===는 Triple equals로 엄격한 같음(strict comparison)을 비교한다. ===는 비교하려는 두 값의 type과 value가 모두 같을 때 true를 반환한다.

6.2. 기억할만한 예외들

6.2.1. ==를 사용할 때
  • 0과 ''(빈 문자열)은 false와 같다.
    • 0 == false
    • '' == false
  • null과 undefined는 서로 같지만 다른 것들과는 같지 않다.
    • null == undefined
  • NaN은 자기 자신인 NaN을 포함하여 그 어떤 것과도 같지 않다.
  • Infinity는 true처럼 사용되지만 true나 false와 비교할 수 없다.
  • 빈 배열 []은 true처럼 사용되지만 0, '', false와 비교하면 같다.
    • [] == 0
    • [] == ''
    • [] == false
6.2.2. ===를 사용할 때
  • NaN은 자기 자신인 NaN과도 비교할 수 없다.

6.3. 느낀 점

==이 값을 비교하기 전에 강제로 형 변환을 한다는 사실을 새로 알게 되었고 ==에 예측하기 어려운 예외상황이 많다는 것도 알게 되었다. 웬만하면 ===을 쓰라는 말만 들었지 왜 그런지 정확히 이해하지 못했는데 이번에 알아보면서 이유를 체감하게 된 것 같다. 앞으로 최대한 ===만 쓸 수 있도록 하고, 어쩔 수 없이 ==을 사용해야 하는 상황이 오면 결과를 확실히 확인한 후 사용해야겠다.


7. const value = a || b; 코드의 의미는 무엇인가?

7.1. 설명

  • || 은 Logical OR라고 하며 논리연산자 중 하나로, 비교하는 두 개의 피연산자 중 하나만 true여도 true를 반환하고 모두 false이면 false를 반환한다.
  • const value = a || b; 는 위와 같은 원리를 이용하여 변수 초기값을 할당하는 방법이다. a와 b가 boolean 타입의 변수라면 원래 작동 방식대로 true나 false를 반환하겠지만, boolean이 아닌 평가할 수 있는 다른 타입의 값이라면 다음과 같이 작동한다.
    • true로 평가할 수 있는 값이 있다면 true로 평가할 수 있는 첫 번째 값을 반환한다.
      • undefined || 1 은 1을 반환
      • true || 2 는 true을 반환
    • 모든 값이 false로 평가된다면 가장 마지막 값을 반환한다.
      • null || 0 은 0을 반환
  • a와 b의 자리에는 변수뿐만 아니라 함수나 수식과 같은 표현도 쓸 수 있고, 반환 값을 통해 같은 방식으로 평가된다. 또한 객체는 항상 true로 평가된다.
    • (x = 0) || (x = 1)x = 1 의 결과인 1을 반환
  • 논리연산자는 결과를 확정 지을 수 있을 때 평가를 멈추고 결과를 바로 반환하는 '단축 평가(Short-circuit evaluation)'를 수행한다.
    • || 은 피연산자 중 하나만 true여도 평가 결과가 true이기 때문에, 왼쪽부터 평가를 시작해서 true로 평가되는 피연산자를 만나면 더이상 진행하지 않고 true로 평가를 종료한다.
    • true || (x = 1) 는 첫 번째 인자가 true이기 때문에 다음 인자인 x = 1 을 수행하지 않고 바로 true를 반환한다. 따라서 변수 x에는 1이 할당되지 않는다.

7.2. 느낀 점

논리연산자 ||은 종종 사용하던 것이었는데 좀 더 명확하게 작동 방식을 알게 되었고, 단축 평가를 수행하여 생각보다 효율적으로 동작하고 있다는걸 알게 되었다. 사용하려는 어떤 값의 단순한 유효성 검사와 할당에 유용할 것 같고 간단한 if 문을 대신해서 더욱 간결하게 사용 할 수 있을 것 같다.


8. eval 은 무엇인가?

8.1. 설명

8.1.1. eval() 이란?
  • eval()은 문자열로 된 코드를 평가하고 수행한 후 결과값을 반환하는 함수이다.
  • eval('2 + 2') === 4
8.1.2. eval()의 단점

eval 함수는 동적으로 코드를 생성하고 실행하는 편리하고 쉬운 방법이지만 아래와 같은 여러 단점들이 있기 때문에 최대한 사용을 피하는 게 좋다.

  • eval 함수는 eval이 접근할 수 있는 scope내의 변수들을 너무 쉽게 변경시킬 수 있기 때문에 코드의 예측을 어렵게 한다.
  • 디버깅이 어렵다. (eval함수로 사용되는 코드는 줄번호가 없다.)
  • eval 함수는 최신 자바스크립트 엔진에 최적화되어있지 않기 때문에 매우 느리다.
  • eval 함수 사용이 보안을 취약하게 만들 가능성이 있다. (사용자 입력에 관한 보안 이슈가 있다.)
8.1.3. eval() 대신 사용하기
  • 동적으로 객체 속성에 접근할 때 속성 접근자를 사용하기

    eval( 'var result = obj.' + propName ); 대신 var result = obj[ propName ];

  • 짧은 코드를 평가하고 수행할 때 함수 생성자 또는 함수를 사용하기

    • eval 대신 함수 생성자 사용

      function looseJsonParse(obj){
          return eval(obj);
      }
      console.log(looseJsonParse(
         "{a:(4-1), b:function(){}, c:new Date()}"
      ))
      function looseJsonParse(obj){
          return Function('"use strict";return (' + obj + ')')();
      }
      console.log(looseJsonParse(
         "{a:(4-1), b:function(){}, c:new Date()}"
      ))
    • 문자열 대신 함수 사용

      setTimeout(" ... ", 1000); 대신 setTimeout(function() { ... }, 1000);

  • JSON 데이터를 다룰 때 JSON.parse를 이용하기

8.2. 느낀 점

eval 함수는 이번에 처음 알게 됐는데 어떤 상황에 어떤 방식으로 편리하게 쓸 수 있는지는 잘 모르겠지만, 단점이 많은 함수인 것 같아서 혹시 사용할 일이 있어도 최대한 다른 방식으로 문제를 해결해야겠다는 생각이 들었다. 하지만 eval 함수가 과거의 흔적(?)으로 생각보다 많은 곳에 사용돼있다고 하니, 이번 공부가 레거시 코드를 해석하거나 수정해야 할 일이 생겼을 때 유용할 것 같다.


9. 변수값을 출력할 때 null, undefined, is not defined로 출력되는 차이점은 무엇인가?

9.1. 설명

9.1.1. null

null 은 자바스크립트에서 일반적으로 어떤 객체 값의 '의도적인 없음'을 나타내는 값이다. 따라서 다음과 같은 경우를 가진 변수에 접근했을 때 null 이 출력된다.

  • 고의로 변수의 값이 '없음'을 표현하기 위해 변수에 직접 null 을 할당했을 때

    let value = null; // value is null
  • 특정 조건에 해당하는 객체의 값을 찾지 못했을 때 반환

    let value = 'abc'.match(/[0-9]/); // value is null
    let saveButton = document.getElementById("save"); // saveButton is null
9.1.2. undefined

undefined 는 일반적으로 값이 할당되지 않은 변수의 기본값으로 사용된다. 자바스크립트에서는 많은 경우에 undefined 가 출력되는데 대표적으로 다음과 같은 경우에 undefined 가 출력된다.

  • 선언만 되고 아직 초기값이 할당되지 않은 변수에 접근했을 때

    let value;
    console.log(value); // value is undefined
  • 함수에 정의된 매개변수에 인자가 들어오지 않는 경우

    function sum(val1, val2) {
      return val1 + val2; // val2 is undefined
    }
    
    sum(5);
  • 함수에서 어떤 값도 반환하지 않는 경우

    function sum(val1, val2) {
      let result = val1 + val2;
    }
    
    let result = sum(5, 5); // result is undefined
9.1.3. "x" is not defined

"x" is not defined 는 ReferenceError 타입의 하나로 전체 에러 메세지는 ReferenceError: "x" is not defined 이다. 존재하지 않는 변수를 어딘가에서 참조했을 때 나타나는 에러 메세지이다. 대표적으로 다음과 같은 경우에 이 에러 메세지를 출력한다.

  • 변수가 선언되지 않았을 때

    console.log(value); // ReferenceError: value is not defined
    let value;
  • 잘못된 scope에서 접근했을 때

    function numbers() {
      let num = 1;
      return num;
    }
    
    console.log(num); // ReferenceError: num is not defined.

9.2. 느낀 점

nullundefined 에 대해서 명확히 알게 되었고, 어떨 때 is not defined 라는 에러를 마주치는지도 알게 되어서 프로그램을 구현하며 생기는 문제를 좀 더 쉽게 해결할 수 있을 것 같다. 또, 변수를 선언한 후 최대한 초기값을 할당하고 사용하는 게 문제를 발생시킬 확률을 낮춰줄 수 있을 것 같다고 생각했다.


10. add(10)(2) //12 가 되도록 구현해보기

10.1. 설명

  • add 함수는 '다음 인자를 받는 함수'를 반환하는 함수이다.

  • add 함수에서 반환되는 함수는 입력받은 2개의 인자를 계산하고 반환한다.

  • 위의 내용을 코드로 구현하면 다음과 같다.

    function add(num1) {
      return function (num2) {
        return num1 + num2;
      }
    }
    
    const result = add(10)(2); // result is 12

    이처럼 add 함수에서 반환된 익명 함수에서 지역 scope를 벗어난 변수 num1에 접근하고 사용할 수 있는 이유는 closure 개념 때문이다. closure란, 어떤 함수가 생성되는 시점에 존재하는 execution context와 lexical environment를 포함하는 접근할 수 있는 모든 환경을 뜻한다.

  • 위의 코드를 arrow function으로 다음과 같이 간결하게 바꿀 수 있다.

    const add = num1 => num2 => num1 + num2;
    const result = add(10)(2); // result is 12

10.2. 느낀 점

이번 질문은 이미 예전에 pipe 함수를 통해 함수를 반환하는 함수를 연습해 본 적이 있어서 쉽게 해결할 수 있었다. 하지만 closure는 여러 번 본 개념임에도 불구하고 아는 것 같았지만 짧고 명확하게 설명하기가 어렵다고 느꼈다. closure와 관련 있는 개념들에 대해 기회가 될 때 좀 더 자세히 공부해보고 싶다.


11. 함수의 인자 개수와 파라미터가 일치하지 않으면 어떤 일이 생기는가 설명하기

11.1. 설명

11.1.1. 함수의 인자 개수가 파라미터보다 많을 때
  • 함수에 선언된 파라미터만큼만 인자를 받고 나머지는 무시된다.
  • 'arguments' 라는 객체를 사용하면 입력된 모든 인자에 접근할 수 있다.
  • 'arguments' 는 배열 같은 구조이지만 배열은 아니므로 배열 메소드를 사용할 수 없다.
  • Rest parameter는 배열이므로 'arguments' 대신 Rest parameter를 사용하면 배열 메소드를 사용하여 데이터를 편리하게 다룰 수 있다.
11.1.2. 함수의 인자 개수가 파라미터보다 적을 때
  • 함수에서 입력받은 인자와 대응되지 못한 파라미터는 값이 undefined로 할당된다.
  • 대응되지 못할 가능성이 있는 파라미터는 기본값을 설정해주는 게 좋다.

11.2. 느낀 점

원래 알고 있던 내용이지만 확실하게 정리할 수 있어서 좋았고, 가능한 함수의 파라미터는 받으려는 인자 개수와 맞춰서 선언하고 사용하는 게 좋을 것 같다고 생각했다. 또한, 받으려는 인자 개수의 변경 가능성이 있는 경우에는 arguments 객체보다는 ES6에서 추가된 Rest parameter를 사용하면 유용할 것 같다.


12. 함수의 반환 값이 없을 때 어떻게 되는가?

12.1. 설명

자바스크립트에서 함수는 항상 값을 반환한다. 보통 return 문을 이용하여 값을 반환하는데, return 문에는 다음과 같은 특징이 있다.

  • 함수 내부에서 return 문을 만나면 함수는 더 이상 실행되지 않고 종료된다.
  • 특정 값과 함께 return 문이 사용됐다면 함수는 그 값을 반환하며 종료한다.
  • return 문에 어떤 값도 주어지지 않고 사용됐다면 함수는 undefined를 반환하며 종료한다.

함수 안에 return 문이 사용되지 않은 경우에도 함수 내 모든 구문이 실행된 후 undefined를 반환하며 종료된다.

12.2. 느낀 점

함수의 반환 값이 없을 때 undefined를 반환하고, 특별한 값 없이 return만 사용해도 undefined를 반환하기 때문에 어떤 함수에서 특별히 반환할 값이 없다면 굳이 return 문을 사용하지 않아도 되겠다고 생각했다. 또, 자바스크립트에서 undefined는 보통 false로 처리되기 때문에 함수에서 아무런 반환 값이 없을 때 초기화되지 않은 변수와 마찬가지로 알아서 undefined를 반환해주는 게 편리한 것 같다고 생각했다.


13. 익명 함수는 무엇인가?

13.1. 설명

익명 함수란 영어로는 Anonymous functions라고 하며, '이름이 없는 함수'들을 말한다.

13.1.1. 익명 함수 표현의 예
  • 함수 표현식 (Function expression)

    const add = function (param1, param2) {
      return param1 + param2;
    }
  • 화살표 함수 (Arrow functions)

    const add = (param1, param2) => param1 + param2;
  • 즉시 실행 함수 (IIFE, Immediately Invoked Function Expression)

    (function () {
      console.log('IIFE');
    })();
13.1.2. 익명 함수의 특징
  • 익명 함수는 이름이 없기 때문에 짧고 간결하여 편리하게 사용할 수 있다.
  • 익명 함수는 재사용 가능성이 없는 일회성 함수를 표현할 때 유용하다.
  • 익명 함수는 보통 아주 짧고 간단한 함수나, 콜백 함수, 즉시 실행시킬 함수에 적당하다.
  • 익명 함수는 편리하지만 이름이 없기 때문에 디버깅이 어려울 수 있다.

13.2. 느낀 점

익명 함수를 어떤 경우에 쓰면 유용하게 사용할 수 있을지 알게 되었다. 특히 즉시 실행 함수는 주로 한 번만 실행될 외부 코드(라이브러리나 프레임워크와 같은)를 가져다 쓸 때 전역 네임스페이스를 오염시키지 않고 사용할 수 있기 때문에 유용하다는 것을 알 수 있었다. 그러나 익명 함수를 이유 없이 무분별하게 사용하게 될 경우 문제 발생 시 디버깅이 어려워질 수 있기 때문에 용도에 맞게 적절히 사용하는 게 좋을 것 같다.

About

Codesquad Level 2

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published