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

예진·2022년 9월 6일
0

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

원시자료형(primitive data type) : 고정된 저장 공간을 차지하는 데이터
참조 자료형(reference data type) : 대량의 데이터를 다루기에 적합

1. 원시 자료형

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

- 원시 자료형이 할당될 때는 변수에 값(value) 자체가 담긴다.
- 변수에는 데이터의 크기와 관계없이 데이터는 하나의 정보를 담는다.
- 원시 값을 갖는 변수를 다른 변수에 할당하면 원시 값 자체가 복사되어 전달된다. ( 기존 데이터 영향 x )
- 값 자체에 대한 변경이 불가능(immutable)하지만, 변수에 다른 데이터 할당하는 것은 가능하다. => 한 번 생성된 원시 자료형은 읽기 전용(read only) 값이다.

2. 참조 자료형

: 원시 자료형이 아닌 모든 것
array[], object{}, function(){}

- 참조 자료형이 할당될 때는 메모리 공간의 주소(reference)값 이 담긴다.
- 하나의 데이터가 아닌 여러 데이터를 담는다.
- 참조 값을 갖는 변수를 다른 변수에 할당하면 주소값이 복사되어 전달된다.
- 기존에 고정된 크기의 저장 공간이 아닌, 동적으로 크기가 변하는 특별한 저장 공간(heap)을 사용한다.
- 주소를 복사(공유)하여 복사한 데이터에서 원소를 변경하면, 주소 안에 있는 데이터도 변경된다. (기존 데이터 영향 o)
- 참조 자료형은 값 자체에 대한 변경이 가능한 값(mutable value)이다.


🔥 스코프

스코프(Scope) : 변수의 유효범위

1. 스코프와 주요 규칙

- 변수 접근 범위

let username = 'User';
if (username) {
  let message = `Hello, ${username}!`;
  console.log(message);  // Hello, User!
}

console.log(message);  // ReferenceError

블록 : 중괄호 안쪽에 변수가 선언되었는지, 바깥에 변수가 선언되었는지

let greeting = 'Hi';
function greetSomeone() {
  let firstName = 'User';
  return greeting + ' ' + firstName;
}

console.log(greetSomeone());  // Hi User
console.log(message);  // ReferenceError

함수 : 함수 안에서 변수가 선언되었는지, 바깥에 변수가 선언되었는지

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

  • 안쪽 스코프에서 바깥쪽 스코프로는 접근할 수 있지만 반대는 불가능하다.
    전역 스코프(Global scope) : 가장 바깥의 스코프 <-> 지역 스코프(Local scope)

  • 지역 변수는 전역 변수보다 더 높은 우선 순위를 가진다.

  • 스코프는 중첩이 가능하다.

2. 변수 선언과 스코프

- 스코프의 종류

블록 스코프 (block scope)

  • 중괄호({})로 둘러싼 범위

  • 화살표 함수( => {} )로 둘러싼 범위
    ( 같은 함수여도 화살표 함수를 사용하면 블록 스코프로 취급 )

함수 스코프 (function scope)

  • 함수(function{})로 둘러싼 범위

- 변수를 정의하는 방법

  • var 키워드
    블록 스코프를 무시하고, 함수 스코프를 따른다.
    ( 화살표 함수의 블록 스코프는 무시하지 않는다.)
    재선언을 해도 에러를 내지 않는다.

  • let 키워드
    블록 스코프를 따르며, 재선언을 방지한다.

  • const 키워드
    블록 스코프를 따르며, 재할당이 불가능하다.
    변하지 않는 값, 상수(constant)를 정의할 때 사용한다.
    값의 변경을 최소화하여 보다 안전하다.
    ( 값을 새롭게 할당할 일이 없다면, const 키워드 사용 권장한다. )

var 보다 let, const 키워드를 사용하는 것이 좋다.

3. 변수 선언할 때 주의할 점

선언 키워드(var, let, const) 없이 변수를 할당하지 말아야 한다.
=> 선언 없이 변수를 할당하면, 해당 변수는 var로 선언한 전역 변수처럼 취급된다.
Strict Mode : 문법적으로 실수할 수 있는 부분들을 에러로 판단한다.
'use strict' : js 파일 상단에 코드를 적어주면 안전하게 코드 작성 가능하다.

window 객체 ( 브라우저에만 존재 )
: 브라우저의 창(window)을 대표하는 객체 + 전역 영역을 담고있다.
함수 선언식으로 함수를 선언하거나 var로 전역 변수를 만들면, window 객체에서도 동일한 값을 찾을 수 있다.

전역 변수 : 어디서든 접근 가능한 변수
- 부수 효과(side effect) : 로직에 의해 의도되지 않은 변경 발생 가능하므로 전역 변수를 최소화하는 것이 좋다.


🔥 클로저

함수와 함수가 선언된 어휘적(lexical) 환경의 조합을 말하며,
이 환경은 클로저가 생성된 시점의 유효 범위 내에 있는 모든 지역 변수로 구성된다.
( 클로저의 함수는 어디에서 호출되느냐와 무관하게 선언된 함수 주변 환경에 따라 접근할 수 있는 변수가 정해진다. )
=> 클로저는 자신이 생성될 때의 환경(Lexical environment)을 기억하는 함수이다.

1. 클로저 함수의 특징

함수를 리턴하는 함수

const adder = x => y => x + y;  // 함수의 호출 두 번 발생
adder(5)(7);  // 12

typeof adder(5);  // 'function' => 리턴값이 함수의 형태

adder(5);  // y => x + y => 리턴값이 함수의 형태

const adder = x => y => x + y;
// 위와 동일하게 작동하는 코드
const adder = function (x) {
  return function (y) {  // => 리턴값이 함수의 형태
    return x + y;
  }
}

외부 함수와 내부 함수

리턴하는 함수에 따라 스코프(변수의 접근 범위)가 구분된다.

const adder = function (x) {
  return function (y) {
    return x + y;
  }
}

=> 내부 함수는 외부 함수에 선언된 변수에 접근이 가능하다. ( 그 반대는 x )

2. 클로저의 활용

데이터를 보존하는 함수

외부 함수의 실행이 끝나더라도, 외부 함수 내 변수를 사용할 수 있다.
( 클로저 함수는 어휘적 환경을 메모리에 저장하기 때문 )
=> 함수 내에 데이터를 보존해두고 사용 가능하다.

const add = function (x) {
  return function (y) {
    return x + y;
  }
}

const add5 = add(5);  // 함수 실행이 끝나도 5라는 값 사용 가능
add5(5);  // 10
add5(10);  // 15

정보의 접근 제한

클로저 모듈 패턴
내부 함수를 하나만 반환하지 않고, 객체에 담아 여러 개의 내부 함수를 반환하도록 한다.

const counter = () => {
  let value = 0;
  
  return {  // increase, decrease, getValue 내부 함수를 여러 개 만들 수 있다
    increase: () => {
      value += 1
    },
    decrease: () => {
      value -= 1
    },
    getValue: () => value
	}
}

const counter1 = counter();
counter1  // {increase: ƒ, decrease: ƒ, getValue: ƒ}

=> counter를 실행해 변수에 담아서 counter 함수는 increase, decrease, getValue 메서드를 포함한 객체 하나를 반환한다.

정보의 접근 제한 (캡슐화)
: "외부 스코프에서 내부 스코프의 변수에 접근할 수 없다"는 규칙 때문에 값을 직접 수정하는 것 불가능 ( 대신 반환하는 객체가 제공하는 메서드를 통해 값을 간접적으로 조작 )
클로저를 통해 불필요한 전역 변수 사용을 줄이고, 스코프를 이용해 값을 보다 안전하게 다룰 수 있다.

모듈화

: 함수 재사용성을 극대화하여 함수 하나를 독립적인 부품의 형태로 분리하는 것
( 클로저를 통해 데이터와 메서드를 같이 묶어서 다룰 수 있다. )

재활용 가능한 함수

// 위 코드 작성되어 있다고 가정하고 아래 코드 작성
const counter1 = counter();
counter1.increase();
counter1.increase();
counter1.decrease();
counter1.getValue();  // 1

const counter2 = counter();
counter2.decrease();
counter2.decrease();
counter2.increase();
counter2.getValue();  // -1

counter1 과 counter2의 value는 서로 영향을 주지 않고, 각각의 값 보존 가능

+ 모듈 : 하나의 기능을 온전히 수행하기 위한 모든 코드를 가지고 있는 코드 모음 ( 다른 모듈에 의존적이지 않고 독립적이어야 함 )
=> 특정 데이터를 다른 코드의 실행으로부터 보호해야할 때 용이함


🔥 ES6(ECMA Script6) 주요 문법

ECMA Script: Ecma International이 ECMA-262 기술 규격에 따라 정의하고 있는 표준화된 스크립트 프로그래밍 언어, 자바스크립트를 표준화하기 위해 만들어졌다.

1. spread/rest 문법

spread 문법 (Spread Syntax, ...)

: 대상을 개별 요소로 분리, 대상은 이터러블(문자열, 배열...)이어야 한다.

  • 주로 배열을 풀어서 인자로 전달하거나 배열을 풀어서 각각의 요소로 넣을 때 사용한다.
function sum(x, y, z) {
  return x + y + z;
}

const numbers = [1, 2, 3];

sum(...numbers) // 6

rest 문법 (Rest Syntax, Rest Parameter)

: 함수의 마지막 매개변수 앞에 ...를 붙여 사용한다. 반드시 함수 정의의 마지막 매개변수여야 한다.

  • 남아있는 모든 인자를 하나의 배열에 담는다.
  • 파라미터를 배열의 형태로 받아서 사용한다.
  • 파라미터 개수가 가변적일 때 유용하다.
function sum(...theArgs) {
  return theArgs.reduce((previous, current) => {
    return previous + current;
  });
}

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

배열에서 사용하기

  1. 배열 합치기
let parts = ['shoulders', 'knees'];
let lyrics = ['head', ...parts, 'and', 'toes'];

console.log(lyrics);  // ['head', 'shoulders', 'knees', 'and', 'toes']

spread 문법은 기존 배열을 변경하지 않으므로(immutable), arr1의 값을 바꾸려면 새롭게 할당해야 합니다.

let arr1 = [0, 1, 2];
let arr2 = [3, 4, 5];

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

console.log(arr);  // [1, 2, 3]
console.log(arr2);  // [1, 2, 3, 4]

객체에서 사용하기

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

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

console.log(clonedObj);  // {foo: 'bar', x: 42}
console.log(mergedObj);  // {foo: 'baz', x: 42, y: 13}

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

function myFun(a, b, ...manyMoreArgs) {
  console.log("a", a);  // a one
  console.log("b", b);  // b two
  console.log("manyMoreArgs", manyMoreArgs);  // manyMoreArgs ['three', 'four', 'five', 'six']
}

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

2. 구조 분해 할당(destructing)

spread 문법을 이용하여 값을 해체한 후(배열이나 객체의 속성을 해체하여), 개별 값을 변수에 담을 수 있게 하는 JavaScript 표현식

분해 후 새 변수에 할당

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

console.log(a);  // 10
console.log(b);  // 20
console.log(rest);  // [ 30, 40, 50 ]
  1. 객체
    객체에서 구조 분해 할당을 사용하는 경우,
    선언(const, let, var)과 함께 사용하지 않으면 에러 발생할 수 있다.
const { a, b, ...rest } = { a: 10, b: 20, c: 30, d: 40 };

console.log(a);  // 10
console.log(b);  // 20
console.log(rest);  // { c: 30, d: 40 }

+ 선언 없는 할당
: 구조 분해를 통해 변수의 선언과 분리하여 변수에 값을 할당할 수 있다.

var a, b;
({a, b} = {a: 1, b: 2});

console.log(a);  // 1
console.log(b);  // 2

- 함수에서 객체 분해

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

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

whois(user);

3. 화살표 함수(arrow function)

: 함수표현식으로 함수 정의할 때, function 키워드 대신 화살표(=>)를 사용한다.
=> 함수표현식으로 함수를 정의할 때보다 간략하게 함수를 정의할 수 있다.

  • 매개변수가 한 개일 때, 소괄호() 생략 가능
// 아래 코드 모두 동일하게 동작
const arrow = x => { return x + x }

const arrow = (x) => { return x + x }
  • 함수 코드 블록 내부가 하나의 문으로 구성되어 있다면 중괄호{} 생략 가능 (코드 블록 내부의 문이 값으로 평가될 수 있으면 return 키워드 생략 가능)
// 아래 코드 모두 동일하게 동작
const arrow = x => x + x

const arrow => x => { return x + x }

const arrow = function (x) {
  return x + x;
}
profile
😊

0개의 댓글