[Day 24] 연산자 더 알아보기 + 브라우저 측 Javascript

연산자 더 알아보기

표현식 (Expression)

  • 코드 중에 값으로 변환될 수 있는 부분
  • 표현식을 값으로 변환하기 위해 실제로 해당 표현식을 실행시키는 절차를 평가(evaluation) 이라고 한다.

단축 평가 (Short-circuit Evaluation)

  • 피연산자가 두 개 이상인 연산 중에, 값을 결정하기 위해 양쪽 피연산자 모두가 필요하지 않은 경우, 모두 연산하지 않고 필요한 연산만 수행한 후 결과값을 return 한다.

    false && expression	// false
    true || expression // true
      
    // expresion 부분은 연산하지 않는다. (연산할 필요가 없다.)
    
    • && 연산자와 || 연산자의 실제 동작 방식
      • && - 왼쪽 피연산자를 평가해서 falsy 이면 이 값을 바로 반환한다. 아니면 오른쪽 피연산자를 평가한 결과값을 반환한다.
      • || - 왼쪽 피연산자를 평가해서 truthy이면 이 값을 바로 반환한다. 아니면 오른쪽 피연산자를 평가한 결과값을 반환한다.
  • 단축 평가의 성질을 이용해 if 구문을 흉내낼 수 있다.

    // `func1`과 `func2`는 동일하게 동작합니다.
    function func1(arg) {
      if (!arg) {
        arg = 'hello';
      }
      console.log(arg)
    }
      
    function func2(arg) {
      arg = arg || 'hello';		
      // arg가 true면 arg = arg, false면 arg = 'hello'
      // ES2015에서 '기본 매개변수' 문법이 생긴 뒤로는 잘 쓰이지 않지만, 간혹 ES2015 미만 코드에서 보인다!
      console.log(arg);
    }
    

삼항 연산자 (Ternary Operator)

  • 삼항 연산자도 단축 평가와 마찬가지로 평가할 필요가 없는 부분은 평가하지 않는다.

  • if...else를 대신하는 용도로도 자주 사용된다.

증가/감소 연산자 (Increment/Decrement Operator)

  • ++ / -- 연산자는 피연산자의 값을 1 증가 / 1 감소시킨다.
    • ++ / -- 연산자를 피연산자 앞에 쓰면, 그 표현식은 값을 증가시키고 뒤의 결과값을 반환한다.
    • ++ / -- 연산자를 피연산자 뒤에 쓰면, 그 표현식은 값을 증가시키기 전의 피연산자를 그대로 반환한다.

할당 연산자 (Assignment Operator)

  • = , += , -= 등등의 연산자들이 모두 할당 연산자이다.
  • 할당 연산자에 대한 표현식의 결과값은 왼쪽 피연산자에 실제로 할당된 값 이다.

연산자 우선순위 (Operator Precedence)

  • 연산자 우선순위 MDN 문서
  • 같은 연산자를 연이어 사용한 경우가 아니라면, 코드 가독성을 위해 가장 높은 우선순위를 갖는 연산자인 괄호로 둘러싸 주는 것이 좋다.

연산자 결합 순서 (Operator Associativity)

  • 대부분의 경우 결합 순서가 명확히 눈에 보인다. (주로 좌 결합성)

  • 다만, 거듭제곱 연산자, 할당 연산자, 삼항 연산자우 결합성을 가진다는 사실은 예외이므로 기억해둬야 한다.

  • 결합 순서와 계산 순서는 다르다.

    // 거듭제곱 연산자 (오른쪽부터 평가)
    2 ** 2 ** 3; // 256
    2 ** (2 ** 3); // 256
      
    // 할당 연산자 (오른쪽부터 평가)
    let x, y, z;
    z = y = x = 1
    z = (y = (x = 1))
      
    // 삼항 연산자 (왼쪽부터 평가)
    a ? b : c ? d : e ? f : g
    a ? b : (c ? d : (e ? f : g))
    

값을 비교하는 여러 가지 방법

  • 두 값이 같은지 비교하는 방법
    • ==, !=
    • ===, !==
    • Object.is
  1. 추상적 동일성 (Abstract Equality)

    • == 연산자는 두 피연산자의 타입이 다를 때는 타입을 변환한 후 비교한다.

    • null check를 할 때에는 == 연산자가 주로 사용된다.

      • nullundefined 두 값을 동일한 것으로 취급한다.
      • nullundefined를 이 두 값을 제외한 다른 값과 비교했을 때 항상 결과값이 false가 된다.
      null == undefined; // true
           
      null == 0; // false
      null == ''; // false
      undefined == false; // false
      undefined == NaN; // false
      
  2. 엄격한 동일성 (Strict Equality)

    • ===, !== 연사자는 두 피연산자의 타입이 다른 경우 무조건 false를 반환한다.

    • number 타입에 대한 비교에서의 예외

      // `===` 연산에서, `NaN`은 number 타입의 **모든** 값과 다릅니다. 이는 자기 자신에 대해서도 마찬가지입니다.
      NaN === NaN; // false
      Number.isNaN(NaN);	// true
           
      // `0`과 `-0`은 서로 다른 값이지만, `===` 연산은 이 둘을 같은 것으로 취급합니다.
      0 === -0; // true
      
  3. Object.is

    • Object.is 정적 메소드는 두 인수가 정말 같은 값인지를 검사한다.

    • 예외

      Object.is(NaN, NaN); // true
      Object.is(0, -0); // false
      

펼침 연산자 (Spread Syntax)

  • Spread 연산자를 사용하면 배열(or 객체)을 다른 배열(or 객체)에 쉽게 삽입할 수 있다.
  1. 배열

    const arr1 = [3, 4];
    const arr2 = [1, 2, ...arr1, 5]; // [1, 2, 3, 4, 5]
       
    // 이전에는 같은 작업을 하기 위해 `Array.prototype.concat` 메소드를 사용했습니다.
    [1, 2].concat(arr1).concat([5]) // [1, 2, 3, 4, 5]
    
    • 삽입하면서 복사가 일어날 때 얕은 복사 를 한다.
    • 함수 호출 시에도 Spread 문법을 사용할 수 있다. 이 때 배열의 모든 요소를 함수의 인수로 넘긴다.
  2. 객체

    • 객체에 대해서 Spread 문법을 사용할 때는 자기 자신의(own) 열거 가능한(enumerable) 속성만을 복사한다.

      const obj1 = {prop: 1};
      const obj2 = {...obj1};
           
      // 이전에는 같은 작업을 하기 위해 `Object.assign` 정적 메소드를 사용했습니다.
      Object.assign({}, obj1);
      
    • 객체에 같은 이름의 속성이 존재한다면 나중에 선언된 속성의 값으로 덮어쓴다.

    • 이 문법은 ES2018에 추가된 기능이라 아직은 브라우저 호환성이 완벽하지 않기 때문에 Babel 플러그인 또는 TypeScript 등의 트랜스파일러를 사용해야 한다.

분해대입 (Destructuring Assignment)

  • 배열과 객체 안에 들어있는 값을 쉽게 추출해낼 수 있는 문법 (ES2015)
  1. 배열의 분해대입

    • 변수의 선언과 동시에 배열의 요소를 해당 변수에 대입

      const [a, b, c] = [1, 2, 3];
           
      console.log(a, b, c); // 1 2 3
      
    • 요소의 순서와 일치하는 변수가 좌측 목록에 없으면, 해당 요소는 무시

      // 여기서 `2`, `4`는 무시됩니다.
      const [a, , c] = [1, 2, 3, 4];
           
      console.log(a, c); // 1 3
      
    • 이미 선언된 변수에 대해서도 분해대입 가능

      let a, b;
      [a, b] = [1, 2];
           
      console.log(a, b); // 1 2
      
    • 중첩된 배열에 대해서도 분해대입 가능

      const [a, b, [c, d]] = [1, 2, [3, 4]];
           
      console.log(a, b, c, d); // 1 2 3 4
      
    • 배열의 나머지를 새로운 배열로 만들고 싶을 때도 분해대입 사용 가능

      const [a, b, ...c] = [1, 2, 3, 4, 5];
           
      console.log(c); // [3, 4, 5]
      
  2. 객체의 분해대입

    • 주로 이런 형태로 사용된다.

      const {a, b} = {a: 1, b: 2};
           
      console.log(a, b); // 1 2
      
    • 배열과 객체가 함께 중첩되어 있는 경우에도 분해대입 가능

    • 객체의 나머지 속성으로 새로운 객체를 만들고 싶다면 배열에서와 마찬가지로 ... 을 붙여주면 된다. (ES2018 문법이라 브라우저 호환성이 떨어진다.)

  3. 분해대입의 기본값

    • 분해대입 시, 만약 좌측 변수의 위치에 해당하는 값이 우측의 배열 혹은 객체에 존재하지 않으면 그곳에는 대입이 일어나지 않는다.

    • 이 때, 좌측 변수에 기본으로 대입될 값을 미리 지정해둘 수 있다.

      // `c` 위치에는 대입될 값이 없으므로, 기본값인 `3`이 대신 사용됩니다.
      let [a, b, c = 3] = [1, 2];
           
      console.log(c); // 3
      
  4. 매개변수에서의 분해대입

    function func({prop, array: [item1, item2, item3 = 4]}) {
      console.log(prop);
      console.log(item1);
      console.log(item2);
      console.log(item3);
    }
       
    // 1, 2, 3, 4가 차례대로 출력됩니다.
    func({prop: 1, array: [2, 3]});
    
    // 매개변수에서 객체를 분해대입하는 코드가 많이 쓰이고 있다.
       
    function func1(name, age, address, country) {
       
    }
       
    // 특정 매개변수의 역할을 바로 알아보기 어렵고, 인자의 순서를 바꾸면 안된다.
    func1('신창선', 28, '성북구', '대한민국')
       
    function func2({name, age, address, country}) {
      // ...
    }
       
    // 매개변수의 역할을 쉽게 알 수 있고, 순서를 바꿔서 써도 상관이 없다.
    func2({
      name: '신창선', 
      age: 28, 
      address: '성북구',
      country: '대한민국'
    })
    

브라우저 측 Javascript

API (Application Programming Interface)

  • 애플리케이션을 프로그래밍할 수 있는 접점

DOM API

트리

  • 여러 데이터가 계층 구조 안에서 서로 연결된 형태를 나타낸다.
  • 용어
    • 노드(node)
    • 자식 노드(child node)
    • 부모 노드(parent node)
    • 뿌리 노드(root node)
    • 잎 노드(leaf node)
    • 조상 노드(ancestor node)
    • 자손 노드(descendant node)
    • 형제 노드(sibling node)

요소 선택하기

  • document.querySelector(selector) - CSS 선택자를 통해 단일 요소 가져오기
  • document.querySelectorAll(selector) - CSS 선택자를 통해 여러 요소 가져오기
  • el.querySelector(selector) - CSS 선택자를 통해 단일 자식 요소 가져오기
  • el.closest(selector) - 엘리먼트의 조상 중에 CSS 선택자와 일치하는 가장 가까운 조상 요소 가져오기
  • el.matches(selector) - 해당 요소가 CSS 선택자와 일치하는지 검사하기 (return true / false)

요소 내용 조작하기

  • el.textContent - 요소 본문을 가져오거나 변경할 때 사용하는 속성 (텍스트)
  • el.innerHTML - 요소 본문을 가져오거나 변경할 때 사용하는 속성 (HTML)
    • 사용자로부터 입력받은 텍스트를 innerHTML에 대입해서는 절대로 안된다. (Cross-site Scripting (XSS) 해킹 공격의 우려가 있다.)

요소 어트리뷰트 조작하기

  • el.hasAttribute(attrName) - 어트리뷰트가 있는지 검사하기
  • el.getAttribute(attrName) - 어트리뷰트의 값 가져오기
  • el.setAttribute(attrName, attrValue) - 어트리뷰트 설정하기
  • el.removeAttribute(attrName) - 어트리뷰트 삭제하기

요소 클래스 조작하기

  • el.classList.add(className, ...) - 클래스 추가
    • 이미 존재하는 클래스는 더 이상 붙이지 않는다.
  • el.classList.remove(className, ...) - 클래스 삭제
  • el.classList.contains(className) - 클래스 포함 여부 검사

인라인 스타일 조작하기

  • el.style - 요소의 인라인 스타일을 읽고 쓸 때 사용하는객체. camelCase 사용
    • el.style.backgroundColor = '#000000' - 요소의 배경색을 검은색으로 변경

댓글남기기