WEB개발

[ES6] ES6문법

wooyeon06 2024. 7. 31. 12:39

 

1. let, var, const

 

대부분의 문제는 전역 변수로 인해 발생한다. 전역 변수는 간단한 애플리케이션의 경우, 사용이 편리하다는 장점이 있지만 불가피한 상황을 제외하고 사용을 억제해야 한다.

전역 변수는 유효 범위(scope)가 넓어서 어디에서 어떻게 사용될 것인지 파악하기 힘들며, 비순수 함수(Impure function)에 의해 의도하지 않게 변경될 수도 있어서 복잡성을 증가시키는 원인이 된다. 따라서 변수의 스코프는 좁을수록 좋다.

 

# var, let, const 차이점 5가지

 

1. 중복선언 가능 여부

2. 재할당 가능 여부

3. 변수 스코프 유효범위

4. 전역객체 프로퍼티 여부

 

  VAR LET CONST
중복선언 가능 여부 가능 불가능 불가능
재할당 가능 여부 가능 가능 불가능
변수 스코프 유효범위 함수 레벨 스코프
(function-level scope)

if문, for문, while문, try/catch 문 등의 코드 블럭{ ... } 내부에서 var로 선언된 변수를 전역 변수로 간주한다.
let, cost : 블록 레벨 스코프(block-level scope)

let, const는 함수 내부는 물론, if문이나 for문 등의 코드 블럭{ ... } 에서 선언된 변수도 지역변수로 취급한다.


전역객체 프로퍼티 여부 var로 선언된 변수는 전역객체(브라우저 환경의 경우 window)의 프로퍼티다.


var a = 10; 
console.log(window.a);
// 10 

console.log(a); 
// 10

let, const : let/const 로 선언된 변수는 전역객체 프로퍼티가 아니다.

 

 


 

2. 배열, Object Spread

JavaScript에서 배열과 객체의 스프레드 연산자(...)를 활용하는 예제

 

const originalArray = [1, 2, 3, 4];
const copiedArray = [...originalArray];

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


const obj1 = {
    "key1" : "value1"
}

const obj2 = {
    "key1" : "change Value",
    "key2" : "value2"
}

const copyObj = {...obj1, ...obj2}
console.log(copyObj) // { key1: 'value1', key2: 'value2' }

 

3. map, filter, foreach

1)  map

 

  • 파라미터:
    • callback: 배열의 각 요소에 대해 호출되는 함수입니다. 이 함수는 다음과 같은 인자를 받습니다:
      • currentValue (필수): 현재 처리 중인 배열 요소.
      • index (선택): 현재 처리 중인 배열 요소의 인덱스.
      • array (선택): map 메서드를 호출한 배열.
  • 반환값: 변형된 요소들로 구성된 새로운 배열.

 

const people = [
    { name: "Alice", age: 25 },
    { name: "Bob", age: 30 },
    { name: "Charlie", age: 35 },
];
const names = people.map((person) => person.name);

console.log(names); // ['Alice', 'Bob', 'Charlie']

 

 

2) filter

 

  • 파라미터:
    • callback: 배열의 각 요소에 대해 호출되는 함수입니다. 이 함수는 다음과 같은 인자를 받습니다:
      • currentValue (필수): 현재 처리 중인 배열 요소.
      • index (선택): 현재 처리 중인 배열 요소의 인덱스.
      • array (선택): filter 메서드를 호출한 배열.
  • 반환값: 조건을 만족하는 요소들로 구성된 새로운 배열. 조건을 만족하지 않는 요소는 포함되지 않습니다.

 

const people = [
    { name: "Alice", age: 25 },
    { name: "Bob", age: 17 },
    { name: "Charlie", age: 30 },
];
const adults = people.filter((person) => person.age >= 18);

console.log(adults);
// [ { name: 'Alice', age: 25 }, { name: 'Charlie', age: 30 } ]

 

 

3) foreach

 

  • 파라미터:
    • callback: 배열의 각 요소에 대해 호출되는 함수입니다. 이 함수는 다음과 같은 인자를 받습니다:
      • currentValue (필수): 현재 처리 중인 배열 요소.
      • index (선택): 현재 처리 중인 배열 요소의 인덱스.
      • array (선택): forEach 메서드를 호출한 배열.
  • 반환값: undefined. forEach는 값을 반환하지 않습니다.
const people = [
    { name: "Alice", age: 25 },
    { name: "Bob", age: 30 },
    { name: "Charlie", age: 35 },
];
people.forEach((person) => (person.age += 1));

console.log(people);
// [ { name: 'Alice', age: 26 }, { name: 'Bob', age: 31 }, { name: 'Charlie', age: 36 } ]

 

 

 

4. Destructuring array, object

ES6(ECMAScript 2015)에서 도입된 배열 비구조화 할당(Destructuring Assignment)은 배열의 요소를 변수에 쉽게 할당할 수 있는 기능을 제공합니다

 

Ddestructuring Array

 

const numbers = [1, 2, 3, 4, 5];
const [first, second, , fourth] = numbers;

console.log(first);  // 1
console.log(second); // 2
console.log(fourth); // 4

 

const numbers = [1, 2, 3, 4, 5];
const [first, second = 4, ...rest] = numbers; //seconds default 4

console.log(first);  // 1
console.log(second); // 2
console.log(rest);   // [3, 4, 5]

 

 

Destructuring Object

 

const person = {
  name: 'Alice',
  age: 25
};

const { name: personName, age: personAge } = person;

console.log(personName); // 'Alice'
console.log(personAge);  // 25

 

 

const user = {
  id: 1,
  profile: {
    name: 'Alice',
    age: 25
  },
  location: {
    city: 'Wonderland',
    country: 'USA'
  }
};

const { 
  profile: { name: userName, age: userAge }, 
  location: { city: userCity } 
} = user;

console.log(userName); // 'Alice'
console.log(userAge);  // 25
console.log(userCity); // 'Wonderland'

 

 

 

5.  Collections

1)  WeakSet, Set

 

  • 메모리 관리: Set은 객체가 참조되고 있는 한 해당 객체를 유지하지만, WeakSet은 객체에 대한 강한 참조를 가지지 않으며, 다른 참조가 없으면 가비지 컬렉터에 의해 삭제됩니다.

  • 사용 용도: Set은 모든 해시 가능한 객체를 저장할 수 있는 반면, WeakSet은 약한 참조가 가능한 객체들만 저장 가능합니다

 

 

import weakref

class MyClass:
    def __init__(self, name):
        self.name = name
    
    def __repr__(self):
        return f"MyClass({self.name})"

obj1 = MyClass("a")
obj2 = MyClass("b")

# WeakSet 예시
my_weakset = weakref.WeakSet()
my_weakset.add(obj1)
my_weakset.add(obj2)

print(my_weakset)  # 출력: WeakSet([MyClass(a), MyClass(b)])

# obj1에 대한 참조를 제거하면 WeakSet에서도 자동으로 제거됨
del obj1
print(my_weakset)  # 출력: WeakSet([MyClass(b)])

 

 

6. ArrowFunction

- 함수 본문이 한 줄이면 중괄호 {}와 return 키워드를 생략할 수 있습니다.

 

- this 바인딩

    Arrow Function의 가장 큰 차이점 중 하나는 this 바인딩입니다.

  • 전통적인 함수: this는 함수가 호출되는 방식에 따라 동적으로 결정됩니다.
  • Arrow Function: this는 정적으로 정의되며, 함수가 선언된 위치에서 상속됩니다. 즉, Arrow Function은 this를 현재 스코프의 this로 고정합니다.
//기존
function() {
	this => window
}

function() {}.bind(this);
this => obj



//컨텍스트가 유지됨arrow function
() => {
	this => obj
}

 

 

7. Object.create(),  Object.assign()

Object.create()

 

  • 객체를 생성하면서 프로토타입을 명시적으로 설정할 수 있음.
  • 상속을 구현할 때 유용하게 사용됨.
  • 새롭게 생성된 객체는 프로토타입 체인을 통해 상위 객체의 속성과 메서드에 접근할 수 있음.

 

const parentObj = {
  greet() {
    return 'Hello!';
  }
};

// parentObj를 프로토타입으로 하는 새로운 객체를 생성
const childObj = Object.create(parentObj);

console.log(childObj.greet());  // 출력: 'Hello!' (상속된 메서드)
console.log(Object.getPrototypeOf(childObj) === parentObj);  // true (프로토타입 확인)

 

Object.assign()

Object.assign을 사용할 때, 소스 객체가 여러 개인 경우 오른쪽에 있는 소스 객체의 속성이 왼쪽에 있는 소스 객체의 속성을 덮어쓰게 됩니다. 따라서 나중에 나오는 소스 객체의 속성이 우선순위를 갖습니다.

 

 

  • 대상 객체에 속성을 복사하는 데 사용되며, 대상 객체를 반환합니다.

  • 얕은 복사(Shallow copy)를 수행하므로, 중첩된 객체의 경우 참조가 복사됩니다.

  • 여러 개의 출처 객체를 사용할 수 있으며, 동일한 키를 가진 속성이 여러 출처 객체에 있을 경우 마지막 객체의 값이 우선됩니다.

 

const target = { a: 1 };
const source1 = { b: 2 };
const source2 = { c: 3, a: 4 };

// target에 source1과 source2의 속성을 복사
Object.assign(target, source1, source2);

console.log(target);  // 출력: { a: 4, b: 2, c: 3 }

 

 


 

8. module export, import

모듈 시스템을 통해 코드의 재사용성과 유지보수성을 높이는 방법입니다. 이를 통해 하나의 파일에서 정의한 변수를 다른 파일에서 사용할 수 있게 됩니다.

 

1)  기본적인 export와 import

모듈 파일: math.js (내보내는 파일)

이 파일에서 함수와 변수를 내보냅니다.

 

 
// math.js

// 함수 정의
export function add(a, b) {
  return a + b;
}

// 변수 정의
export const PI = 3.14159;

 

 

다른 파일에서 import: app.js (가져오는 파일)

math.js에서 내보낸 함수를 다른 파일에서 가져와서 사용할 수 있습니다.

 

// app.js

// add 함수와 PI 변수를 가져오기
import { add, PI } from './math.js';

console.log(add(2, 3));  // 출력: 5
console.log(PI);  // 출력: 3.14159

 

2)  default export

모듈에서는 하나의 기본값을 내보낼 수 있는데, 이 때는 default 키워드를 사용합니다. default로 내보낸 값은 {} 없이 바로 import할 수 있습니다.

 

모듈 파일: mathDefault.js

 

// mathDefault.js

// 기본 내보내기 (default export)
export default function subtract(a, b) {
  return a - b;
}
 

 

 

default로 내보낸 값은 중괄호 {} 없이 import할 수 있습니다.

 

// appDefault.js

// subtract 함수를 가져오기 (기본 내보내기)
import subtract from './mathDefault.js';

console.log(subtract(5, 2));  // 출력: 3

 

3. 이름 변경(as) 사용하여 가져오기

export 또는 import할 때 이름을 변경할 수 있습니다.

모듈 파일: mathRename.js

 

// mathRename.js

export function multiply(a, b) {
  return a * b;
}

export const constant = 42;​
 

 

다른 파일에서 import 이름 변경

 

// appRename.js

// 이름 변경하여 가져오기
import { multiply as mult, constant as answer } from './mathRename.js';

console.log(mult(4, 5));  // 출력: 20
console.log(answer);  // 출력: 42

 

4. 전체 모듈을 가져오기

import * as 구문을 사용하면 모듈 전체를 하나의 객체로 가져와서 사용할 수 있습니다.

 

모듈 파일: mathAll.js

 

// mathAll.js

export function divide(a, b) {
  return a / b;
}

export const PI = 3.14159;
 

 

다른 파일에서 전체 모듈 가져오기

 

// appAll.js

// 모듈 전체를 math라는 객체로 가져오기
import * as math from './mathAll.js';

console.log(math.divide(10, 2));  // 출력: 5
console.log(math.PI);  // 출력: 3.14159

 

5. export 여러 방식

 

모듈 파일에서 한 번에 내보내기

 

// mathMultiple.js

// 함수와 변수를 미리 정의한 후 한 번에 내보내기
function square(a) {
  return a * a;
}

const E = 2.718;

export { square, E };
 

 

다른 파일에서 가져오기

 

// appMultiple.js

// square 함수와 E 상수를 가져오기
import { square, E } from './mathMultiple.js';

console.log(square(3));  // 출력: 9
console.log(E);  // 출력: 2.718​

 

 

요약:

  • export: 모듈에서 함수나 변수를 내보낼 때 사용.
    • 기본 내보내기(default export): export default 키워드 사용.
    • 명명된 내보내기(named export): export 키워드 사용.
  • import: 다른 파일에서 내보낸 값을 가져올 때 사용.
    • 기본 가져오기(default import): 중괄호 없이 가져옴.
    • 명명된 가져오기(named import): 중괄호 {}를 사용하여 가져옴.
    • import * as 구문을 통해 모듈 전체를 객체로 가져올 수 있음.

 


 

 

9. proxy

 

Proxy 객체는 기본 동작을 가로채고, 이를 수정하거나 확장할 수 있게 해주는 기능을 제공합니다.

 

예를 들어, 객체의 속성을 읽거나, 쓰거나, 삭제하는 등의 기본 동작을 가로채서 자신만의 로직을 실행할 수 있습니다. 이 기능을 활용하면 객체의 동작을 동적으로 변경하거나, 디버깅 및 로깅, 유효성 검사 등을 수행할 수 있습니다.

 

const target = {
  message: "Hello, World!"
};

const handler = {
  get: function (obj, prop) {
    if (prop === "message") {
      return obj[prop].toUpperCase();  // 메시지를 대문자로 변환
    }
    return obj[prop];
  },
  set: function (obj, prop, value) {
    if (prop === "message") {
      if (value.length > 10) {
        throw new Error("메시지는 10자 이내여야 합니다.");
      }
    }
    obj[prop] = value;
    return true;  // 설정이 성공했음을 나타냄
  }
};

const proxy = new Proxy(target, handler);

console.log(proxy.message);  // 출력: HELLO, WORLD!
proxy.message = "Hi";  // 정상적으로 값이 할당됨
console.log(proxy.message);  // 출력: HI

proxy.message = "This message is too long";  // 오류 발생

 

 

deleteProperty 트랩

 

const target = {
  a: 10,
  b: 20
};

const handler = {
  deleteProperty(target, prop) {
    if (prop === "a") {
      throw new Error("a 속성은 삭제할 수 없습니다.");
    }
    delete target[prop];
    return true;
  }
};

const proxy = new Proxy(target, handler);

delete proxy.b;  // 성공적으로 삭제
console.log(proxy.b);  // 출력: undefined

delete proxy.a;  // Error: a 속성은 삭제할 수 없습니다.

 

has 트랩: in 연산자 가로채기

 

const target = {
  name: 'Alice',
  age: 25
};

const handler = {
  has(target, prop) {
    if (prop === 'age') {
      return false;  // age 속성은 존재하지 않는 것처럼 보이게 함
    }
    return prop in target;
  }
};

const proxy = new Proxy(target, handler);

console.log('name' in proxy);  // true
console.log('age' in proxy);   // false