다시는 실수하지 않을 JS 문법

0l0l·2021년 7월 24일
8

TIL

목록 보기
61/86
post-thumbnail

1. JS에서 가장 많이 발생하는 에러

에러가 발생하면 당황하지 않고 에러 메시지를 번역해보자.
가장 많이 발생하는 에러들이 있으니 나중에 아래의 에러들이 발생한다면 잘못된 코드를 이해하는데 도움될 것이다.

'a = undefined;' 인 경우를 전제로 다음과 같은 에러들을 살펴보자.

1-1. undefined 에러

undefined인 변수에 값을 읽을 수 없고(Cannot read), 값을 설정할 수 없다(Cannot set).

a.b;
Uncaught TypeError: Cannot read property 'b' of undefined at < anonymous >:1:3

a.c = 'abc';
Uncaught TypeError: Cannot set property 'c' of undefined at < anonymous >:1:3

⇒ b와 c 앞에 있는❗ 변수가 undefined라는 뜻!
(Error라고 가리키는 변수 '앞'에 있는 변수 a가 왜 undefined인지 이유를 찾아라!)

🔆Error 해결 방법🔆
undefined 에러가 발생했다고 문제 있는 변수가 항상 undefined라고 말할 수 없다.

if문으로 감싸거나 optional chaining을 사용해 확실히! undefined가 아닐 때만 동작이 실행되도록 한다.
에러가 발생하지 않게 안전하게 만들어 주는 것이다.
('a가 확실히 있다' = 'a가 undefined가 아니라는 것을 보장한다')

// a가 undefined이 아니면 true이기 때문에 괄호 안에 코드가 실행
if (a) { 
  // 실행문 a.b = ;
}

// optional chaining(?.) ← 최신 문법
// 변수 a가 undefined이면 다음으로 실행되지 않고 undefined 처리
const c = a?.b; // undefined

1-2. null 에러

위의 undefined 에러와 비슷한 경우이다.

a.b;
Uncaught TypeError: Cannot read property 'b' of null at < anonymous >:1:3

⇒ b 앞에 있는❗ 변수가 null이라는 뜻!

1-3. not a function 에러

a = { };
a.d( );
Uncaught TypeError: a.d is not a function at < anonymous >:1:3

⇒ 점(.) 앞에 변수 a를 console.log로 출력해서 a가 무엇인지 존재여부를 파악한다!
객체 a는 존재하는데 a 안에 메서드 d가 없다는 의미이다!
(만약, a가 존재하지 않는다면 undefined 에러가 발생한다.)

1-4. not defined 에러

e;
Uncaught ReferenceError: e is not defined at < anonymous >:1:1

간단하게 보면 let이나 const로 선언하지 않은 경우에 발생하는 에러이다.

또는 모듈시스템을 사용하는데 import를 하지 않은 경우이다.
'실무에서 자주 일어나는 에러'인데 다른 라이브러리를 이미 가져와 사용한 줄 알고 변수를 자유롭게 사용할 때 발생한다.

⇒ 변수를 선언하거나 import 해주기! 예약어 잊지말기~

// (예) jquery라는 라이브러리를 가져오는 코드
const e = require('jquery');
import e from 'jquery';

// 위의 코드로 이미 가져왔다고 생각하고 바로 변수 사용하여 에러 발생
e; // Error;

2. 화살표 함수를 이용한 비동기 코드 한 줄로 작성하기

문제 없이 잘 작성한 타이머 함수, 이벤트리스너 함수는 다음과 같다.
실수로 잘못 작성하는 코드와 비교해 잘못된 이유를 생각해보자.

// 1초 뒤에 실행되는 비동기 코드
setTimeout(() => {
  console.log('hello');
}, 1000);

setTimeout(function() {
  console.log('hello');
}, 1000);

// click할 때마다 실행되는 이벤트 함수
document.addEventListener('click', () => {
  console.log('hello');
});

나를 포함한 대부분의 초보자들이 실수💥하는 코드!! 주의깊게 살펴보기!

틀렸음을 자각하지 못하고 잘못 줄여 작성한 코드 예시
※ 절대 따라하지 마시오!🚫

setTimeout(console.log('hello'), 1000); // hello (실행하자마자 바로 출력)

document.addEventListener('click', console.log('hello')); // hello
// ↪ 실행하자마자 바로 출력되고, click 이벤트는 적용조차 되지 않음

이렇게 실행되는 이유는 인자 안에 자리를 착각해서 발생한 실수이다.
함수 자리에 함수가 아닌 다른 것을 집어 넣었기 때문이다.
(타이머의 첫 번째 인자와 이벤트리스너의 두 번째 인자에 ○○○을 넣어버렸다!?)

여기서 질문!! 🙋‍♀️🙋‍♂️
과연, console.log()는 함수인가? 아닌가!

함수가 아니다... 함수의 '호출'이다.
즉, 함수의 '리턴값'으로 대체한다고 생각하자. (⇦ must 이해!x100)

console.log( )의 리턴값은 undefined이기 때문에
console.log('hello')가 먼저 실행되고 나서, undefined가 된다.
즉, document.addEventListener('click', undefined); 라고 볼 수 있다.
반면에 console.log는 함수로, 함수 자리인 인자에 들어가도 유효하다!😲

document.addEventListener('click', ( ) => { });
우리가 자주 쓰는 형식의 코드에서 () => {}함수이기 때문에, 함수 자리에 맞게 들어간 것이다.
(() => {}() 형태가 함수 호출을 의미한다.)

3. 화살표 함수 한 줄로 줄이기

화살표 함수에서 중괄호( { )return이 연달아 붙어있으면 생략할 수 있다. (예약어 return을 생략하는 형태는 다양함)

return을 생략하는 경우와 어떤 종류의 괄호를 작성해야 하는지 서로 혼동하는 경우가 빈번하게 발생한다.

// ⚠ 화살표 함수의 기본 형태
const add = (a, b) => {
  return a + b;
}

// 한 줄로 작성(상동 코드)
const add = (a, b) => a + b;
const add = (a, b) => (a + b) // 참고: 리턴값에서 소괄호 여러개 작성 가능

화살표 함수 기본 형태와 return을 생략하고 한 줄로 작성한 코드를 혼동하여 다음과 같은 실수를 범한다.
함수가 undefined이기 때문에 파라미터를 전달해 함수를 호출해도 값이 출력되지 않는다.
중괄호를 생각하지 않고 무작정 return을 생략하지 말자!

// (중괄호와 return 생략은) 잘못된 코드
const add = (a, b) => {
  a + b
}; // undefined

add(1, 2); // undefined

※ 시작은 화살표 함수의 기본 형태이므로 원형을 기준으로, return 생략 가능 여부와 괄호 종류를 정하자.

화살표 함수( '( ) =>' )에서 중괄호와 return은 '함께 생략' 가능하다! (둘 중 하나만 생략 불가❌)

  • 중괄호( { } )로 감싸준다면 return을 사용하여 리턴값 작성
  • 소괄호( ( ) )로 감싸준다면 return을 생략하고 리턴값 작성

4. 객체 안에 속성 접근 방법

  • 점(.)을 이용
  • 대괄호([ ])를 이용 (유의!😲)
const a = {};

a.b; = 'hello;
a['b']; // "hello"

// 속성이 undefined인 경우 (Error 발생)
a[b]; // Uncaught ReferenceError: b is not defined at ..

// 속성이 undefined이 아닌 경우
const b = 'c';
a[b]; // undefined

점으로 접근할 때는 따옴표 생각하지 않아도 되기 때문에 사용하는데 어려움이 적다.

대괄호를 사용할 때,
객체 안에 속성인 '문자열 값' 자체에 접근한다면 따옴표('')로 감싸줘야 한다.
또는 변수를 가리킨다면 따옴표 없이 작성해야 한다.

만약, 객체 안에 속성을 접근하려는데 대괄호 안에 따옴표 없이 작성했다면 Error가 발생하거나 undefined이 출력된다.
undefined이 출력되는 경우속성명과 동일한 변수가 미리 선언 되어 있는 경우(객체의 속성과는 무관)이므로 잘못됐음을 인지하기 어려워 더욱 주의👀해야 한다!!

// 예시1️⃣
person = {};
person.name = 'brian';
let name = '삐롱이'; // 속성명과 동일한 변수 선언

person['name']; // "brian" (문자열)
person[name]; // undefined (변수)
// 예시2️⃣
const score = {
  one: 1,
  two: 2,
  three: 3
}

// 객체 속성 추가
score['four'] = 4; // score.four = 4; 와 동일

// 객체 속성 접근
score[four]; // undefined (변수 four)
score['four']; // 4 (문자열 값)

// 객체 속성 수정
score.one = 5;
score; // {one: 5, two: 2, three: 3, four: 4}

score['two'] = 222;
score; // {one: 5, two: 222, three: 3, four: 4}

score[three] = 3333; // Uncaught ReferenceError: three is not defined..

// 속성으로 착각할 수 있는 변수 접근 방법
let five = 'one'; // undefined (score 객체 안에 one 속성값 5를 할당받음)
score.five; //❌ undefined (객체 안에 속성이 추가된 것이 아님)
score[five]; //⭕ 5 (five는 변수이기 때문에 '따옴표 없이' 접근 가능)
score; // {one: 5, two: 2, three: 3, four: 4} (원상태 유지)

'문자열 값'과 '변수'를 구분하여 정리하면,

  • 객체 안에 있는 속성에 접근/추가/수정은 문자열이므로 따옴표를 사용! (ex. developer['name'])
  • 변수를 가리키려면 따옴표 없이 접근! (ex. developer[name])

(참고 링크: 제로초 토크-초보자들이 자주 실수하는 기본 문법)

profile
천방지축 빙글빙글

0개의 댓글