[JavaScript] 핵심 개념과 주요 문법

play·2022년 5월 17일
1

JaveScript

목록 보기
5/10
post-thumbnail

Chapter1. 원시 자료형과 참조 자료형

Chapter2. 스코프

2-1 스코프 & 스코프 규칙
2-2 변수 선언할 때 주의할 점

Chapter3. 클로저

Chapter4. ES6 주요 문법


Chapter1. 원시 자료형과 참조 자료형

원시 자료형(primitive data type): number, string, boolean과 같은 고정된 저장 공간을 차지하는 데이터
반면에 대량의 데이터를 다루기에 적합한 배열과 객체는 참조 자료형(reference data type)
데이터를 저장하는 방식에 따른 분류

학습목표

  • 원시 자료형(primitive data type)과 참조 자료형(reference data type)의 구분이 왜 필요한지에 대해서 영상을 보고 이해할 수 있다.
  • 원시 자료형과 참조 자료형의 차이를 이해하고, 각자 맞는 상황에서 사용할 수 있다.
  • 원시 자료형이 할당될 때는 변수에 값(value) 자체가 담기고, 참조 자료형이 할당될 때는 보관함의 주소(reference)가 담긴다는 개념을 코드로 설명할 수 있다.
  • 참조 자료형은 기존에 고정된 크기의 보관함이 아니라, 동적으로 크기가 변하는 특별한 보관함을 사용한다는 것을 이해할 수 있다.

📌 원시 자료형과 참조 자료형

원시 자료형(primitive data types)

객체가 아니면서 method를 가지지 않는 6 가지의 타입
: string, number, bigint, boolean, undefined, symbol, (null)

  • "하나"의 정보, 즉, 데이터를 담고 있다.
  • 데이터 저장소(메모리)의 용량이 제한되어 데이터 보관함 한 칸에 하나의 데이터만 넣을 수 있다.
  • 각 변수간에 원시타입 데이터를 복사할 경우에 데이터값이 복사되므로 기존 데이터에 영향이 가지 않는다.
  • 하나의 의미를 가지는 데이터이므로 보관함의 크기는 고정하는 게 합당하다. 어느 정도 일정한 크기의 데이터가 온다고 예상할 수 있기 때문이다.
  • 데이터 크기와는 관계 없이 하나의 데이터만
  • 값 자체에 대한 변경이 불가능(immutable)하지만, 변수에 다른 데이터를 할당할 수는 있다.

참조 자료형(reference data type)

배열([]), 객체({}), 함수(function(){})
대량의 데이터를 쉽게 다루기 위해

  • 변수를 할당할 때 변수에 값이 아닌 이 데이터가 저장되는 곳의 주소를 저장한다.
  • 주소를 복사하므로 복사한 데이터에서 원소를 변경하게 되면 주소 안의 데이터가 변경되는 것이므로 기존의 데이터에도 영향이 간다.
  • 여러개의 데이터를 관리하기 위해 heap이란 빈 공간을 만들어 사물함에 이름을 달아주고 값 대신 주소를 넣는다. 그 주소는 heap에 연결되어있다. 값을 찾을땐 사물함 안의 주소를 보고 heap에서 찾아서 반환한다. 이렇게 되면 원소를 빼거나 넣어도 주소지에서 처리하게 된다.
  • 값의 크기가 수시로 변하는 것을 처리하기 위해 참조 자료형은 heap이라는 별도의 메모리 저장 공간을 사용한다.

원시 자료형과 참조 자료형의 특징

  • 원시 자료형이 할당될 때에는 변수에 값(value) 자체가 담기고,
  • 참조 자료형이 할당될 때는 보관함의 주소(reference)가 담긴다.
    그래서 참조 자료형은 기존에 고정된 크기의 보관함이 아니라, 동적으로 크기가 변하는 특별한 보관함을 사용할 수 있다.

Chapter2. 스코프

학습목표

  • 스코프의 의미와 적용 범위를 이해한다.
  • 스코프의 주요 규칙을 이해한다.
  • 전역 스코프와 지역 스코프의 차이를 이해한다.
  • block scope와 function scope의 차이를 이해한다.
  • 변수 선언 키워드(let, const, var)와 스코프와의 관계를 설명할 수 있다.
  • 전역 객체가 무엇인지 설명할 수 있다.

📌 스코프

변수 접근 규칙에 따른 유효 범위.

변수에 접근할 수 있는 범위가 존재한다. 중괄호 안쪽에 변수가 선언되었는지, 바깥쪽에 선언되었는지의 여부가 중요하다. 이 범위를 스코프라고 한다.

  • 바깥쪽 스코프에서 선언한 변수는 안쪽 스코프에서 사용 가능하다
  • 반면, 안쪽에서 선언한 변수는 바깥족 스코프에서는 사용할 수 없다
  • 지역변수가 전역변수보다 우선순위가 높다.
  • 스코프 중첩이 가능하다.
  • 스코프가 위계적으로 겹칠 경우, 안쪽 스코프부터 바깥 스코프로 순차적인 스코프 체이닝이 일어난다.
  • 쉐도잉: 동일한 변수 이름으로 인해 바깥쪽 변수가 안쪽 변수에 의해 가려지는 현상

스코프의 종류

1. 블록 스코프(block scope

중괄호를 기준으로 범위가 구분됨.

  • 같은 함수여도, 화살표 함수를 사용하면 블록 스코프로 취급됨.

2. 함수 스코프(function scope)

function 키워드가 등장하는 함수 선언식 및 함수 표현식은 함수 스코프를 만든다.

var / let / const

var

  • 블록 스코프를 무시하고 함수 스코프만 따른다. (이전 방식)
  • 그러나 화살표 함수의 블록 스코프는 무시하지 않는다.

let 키워드 사용이 권장됨.

  • 블록 단위로 스코프를 구분했을 때, 훨씬 더 예측 가능한 코드를 작성할 수 있다.
  • var 키워드는 블록 스코프의 규칙을 무시하므로 재선언을 해도 에러를 내지 않는다. = 버그 유발
  • var로 선언한 전역 변수가 windoew 기능을 덮어씌워서 내장 기능을 사용할 수 없게 만들 수 있다.
  • 그러므로 let으로 변수 선언하는 것을 권장
  • 또한 let 키워드는 재선언을 방지

const

  • 변하지 않는 값, 곧 상수(constant)를 정의할 때 사용
  • let 키워드와 동일하게 블록 스코프를 따름.
  • 재할당 불가. 값을 새롭게 할당할 일이 없다면 const 사용 권장
  • 값을 재할당하는 경우 TypeError를 냄.

📌 변수 선언할 때 주의할 점

  • var로 선언된 전역 변수 및 전역 함수는 window 객체에 속하게 된다.
  • 전역 변수는 가장 바깥 스코프에 정의한 변수다. 따라서 어디서든 접근이 가능하다. 이는 다른 함수 혹은 로직에 의해 의도되지 않은 변경이 발생할 수 있다.(부수 효과 side effect)
  • 전역 변수를 최소화하는 게 좋다.
  • let, const를 주로 사용해라.
  • 선언 키워드(var, let, const)없이 변수를 할당하지 마라. 선언없이 변수를 할당하면, 해당 변수는 var로 선언한 전역변수처럼 취급된다.
  • Strict Mode : 브라우저가 보다 엄격하게 작동하도록 만들어 "선언 없는 변수 할당"의 경우도 Strict Mode는 에러로 판단한다.
    js 파일 상단에 'use strict' 라고 입력하면 됨 (따옴표 포함)

Chapter3. 클로저

"외부 함수의 변수에 접근할 수 있는 내부 함수"

"함수와 함수가 선언된 어휘적(lexical) 환경의 조합을 말한다. 이 환경은 클로저가 생성된 시점의 유효 범위 내에 있는 모든 지역 변수로 구성된다."

학습목표

  • 클로저 함수의 정의와 특징에 대해서 이해할 수 있다.
  • 클로저가 갖는 스코프 범위를 이해할 수 있다.
  • 클로저를 이용해 유용하게 쓰이는 몇 가지 패턴을 이해할 수 있다.

📌 클로저

1. 함수를 리턴하는 함수.

  • 함수의 함수가 선언된 어취적 환경의 조합
    함수 내에서 다른 함수(내부 함수)가 리턴이 되면, 이 함수를 클로저 함수라고 부르고, 외부 함수에 있는 변수에 접근 가능

2. 리턴하는 함수에 의해 스코프(변수의 접근 범위)가 구분됨

  • 클로저의 핵심은 스코프를 이용해 변수의 접근 범위를 닫는(closure; 폐쇄)데에 있다. 따라서 함수를 리턴하는 것만큼 변수가 선언된 곳이 중요

외부 함수의 변수에 접근 가능한 내부 함수

📌 클로저 활용

1. 데이터를 보존하는 함수

  • 일반적인 함수는 함수 실행이 끝나고 나면 함수 내부의 변수를 사용할 수 없다.

  • 그러나 클로저는 외부 함수의 실행이 끝나도 외부 함수 내 변수가 메모리 상에 저장된다. (어휘적 환경을 메모리에 저장하기 때문)

  • 클로저는 특정 데이터를 시코프 안에 가두어 둔 채로 계속 사용할 수 있게 해준다.

const tagMaker = tag => content => `<${tag}>${content}</${tag}>`

const divMaker = tagMaker('div');
dovMaker('hello') // '<div>hello</div>'
divMaker('codestates') // '<div>codestates</div>'

const anchorMaker = tagMaker('a')
anchorMaker('go') // '<a>go</a>'
anchorMaker('urclass') // '<a>urclass</a>'

정보의 접근 제한

클로저 모듈 패턴

클로저를 이용해 내부 함수를 단 하나만 리턴하는 것에 그치지 않고, 객체를 담아 여러 개의 내부 함수를 리턴하도록 만들 수 있다.

  • '외부 스코프에선 내부 스코프의 변수에 접근할 수 없다'는 규칙에 의해 어떤 경우에도 value는 직접 수정이 불가능하다.
  • 대신 리턴하는 객체가 제공하는 메서드를 통해 value값을 간접적으로 조작할 수 있다.
  • 이렇게 캡슐화(정보의 접근 제한)를 함으로써 변수 value를 makeCounter함수로 보존해서 전역 변수로 인한 side effect를 방지할 수 있다.

모듈화

함수 재사용성을 극대화하여 함수 하나를 완전히 독립적인 부품 형태로 분리하는 것.
클로저를 통해 데이터와 메서드를 같이 묶어서 다룰 수 있다. 즉, 클로저는 모듈화에 유리하다


Chapter4. ES6 주요 문법

📌 spread/rest 문법

spread 문법

문자열, 배열 요소를 "펼쳐"주는 문법
주로 배열을 풀어서 인자로 전달하거나, 배열을 풀어서 각각의 요소로 넣을 때 사용한다.
기존 배열을 변경하지 않는다(immutable)

function sum(x, y, z) {
  return x + y + z;
}
const numbers = [1, 2, 3];

sum(...numbers) // 6 

rest 문법

파라미터를 배열의 형태로 받아서 사용할 수 있다.
남아있는 모든 인자를 하나의 배열에 담는다.
파라미터 개수가 가변적일때 유용함

function sum(...theArgs) {
  return theArgs.reduce((previous, current) => {
    return previous + current;
  });
}

sum(1,2,3) // 6
sum(1,2,3,4) // 10

배열에서 사용하기

spread 문법은 배열에서 효과적

1. 배열 합치기

let parts = ['shoulders', 'knees'];
let lyrics = ['head', ...parts, 'and', 'toes'];

// ['head', 'shoulders', 'knees', 'and', 'toes']
let arr1 = [0, 1, 2];
let arr2 = [3, 4, 5];
arr1 = [...arr1, ...arr2];  // 참고: spread 문법은 기존 배열을 변경하지 않으므로(immutable), arr1의 값을 바꾸려면 새롭게 할당해야 합니다.

// [0, 1, 2, 3, 4, 5]

2. 배열 복사

let arr = [1, 2, 3];
let arr2 = [...arr]; // arr.slice() 와 유사
arr2.push(4);  // 참고: spread 문법은 기존 배열을 변경하지 않으므로(immutable), arr2를 수정한다고, arr이 바뀌지 않습니다.

// arr = [1, 2, 3] , arr2 [1, 2, 3, 4]

객체에서 사용하기

let obj1 = { foo: 'bar', x: 42 };
let obj2 = { foo: 'baz', y: 13 };

let clonedObj = { ...obj1 };
let mergedObj = { ...obj1, ...obj2 };

// 질문: clonedObj와 mergedObj의 값은 각각 무엇인가요?
// {foo: 'bar', x: 42} , {foo: 'baz', x: 42, y: 13}

함수에서 나머지 파라미터 받아오기

function myFun(a, b, ...manyMoreArgs) {
  console.log("a", a);
  console.log("b", b);
  console.log("manyMoreArgs", manyMoreArgs);
}

myFun("one", "two", "three", "four", "five", "six");

// 질문: 콘솔은 순서대로 어떻게 찍힐까요?
// a one
// b two
// manyMoreArgs (4) ['three', 'four', 'five', 'six']

전개구문
Rest 파라미터

📌 구조 분해 할당

spread 문법을 이용하여 값을 해체한 후, 개별 값을 변수에 새로 할당하는 과정

분배 후 새 변수에 할당

1. 배열
const [a, b, ...rest] = [10, 20, 30, 40, 50];

// 질문: a, b, rest는 각각 어떤 값인가요?
// 10, 20, [30, 40, 50]
2. 객체
const {a, b, ...rest} = {a: 10, b: 20, c: 30, d: 40}
// 질문: a, b, rest는 각각 어떤 값인가요?
// 10, 20, {c: 30, d: 40}
  • 객체에서 구조 분해 할당을 사용하는 경우, 선언(const, let, var)과 함께 사용하지 않으면 에러가 발생할 수 있다

유용한 예제 : 함수에서 객체 분해

function whois({displayName: displayName, fullName: {firstName: name}}){
  console.log(displayName + " is " + name);
}

let user = {
  id: 42,
  displayName: "jdoe",
  fullName: {
      firstName: "John",
      lastName: "Doe"
  }
};

whois(user) 

구조 분해 할당

profile
블로그 이사했습니다 🧳

0개의 댓글