ES6 문법

최정은·2021년 1월 11일
0

JavaScript

목록 보기
4/9

let, const

이 둘은 유사하지만 재정의가 가능하냐 아니냐에 따라 사용이 달라진다.

상수 형식으로 재정의가 불가능한 변수는 const, 재정의가 가능한 변수는 let을 붙인다.

let과 const는 블록 스코프

function test() {
  let a = 'hi';

  if(true){
    let a = 'bye';
    console.log(a); // 'bye'
  }
  console.log(a); //'hi'
}

test();

var는 함수 스코프이다. **반면 let과 const는 블록 스코프**이기 때문에 if, while, for, function 등에서 사용하는 중괄호 안에서만 스코프 범위가 유효하다.

블록 스코프인 if문 안에선 a에 대입된 'bye'가 출력되지만 if문 밖에선 'hi'가 출력된다. if 블록에서 대입된 'bye'는 해당 블록에서만 유용하고 이를 벗어나면 사라지게 된다.

여기서 우리는 let이 블록 스코프인것을 알 수 있다.

var를 이용한 반복문의 문제점을 해결하기 위해 '블록 스코프'인 let을 사용한다.

또한 블록의 외부에서 선언된 변수명을 블록 내부에서도 사용할 수 있다!

  let name = 'jeong';
  console.log(name); //jeong

  if(name === 'jeong'){
    let name = 'eun';
    console.log(name); //eun
  }

  console.log(name); //jeong

let과 const의 호이스팅

var와 같이 let과 const도 호이스팅이 된다! 다만, 출력되는 값이 다른데

  console.log(name); //ReferenceError

  let name = 'jeong';

var는 undefined가 출력되지만 let과 const는 참조 에러가 발생한다. 변수가 정의된 위치와 호이스팅 된 위치 사이에 변수를 이용하려하면 에러가 발생한다. 이때의 구간을 임시적 사각지대(Temporal Dead Zone)이라 한다.

템플릿 문자열

백틱(`)을 이용해서 문자열을 사용하는 것이다.

백틱을 이용해서 문자열 안에 변수를 사용할 수 있게 되었다.

var string = num1 + '+' num2 + '=' + result; // 템플릿 문자열 아닌 경우

const string2 = `${num1}+${num2}=${result}`; // 템플릿 문자열인 경우

템플릿 문자열이 아닌 경우엔 변수를 사용할때 마다 문자열 사용을 중단하고 +를 통해 변수와 문자열을 연결시켰다.

백틱을 이용해서 문자열 안에도 변수를 사용할 수 있게 되었다.

객체 리터럴

ES6 이전의 객체는 다음과 같이 정의할 수 있었다.

var sayHi = function(){
	console.log('Hi');
}

var es = 'ES';
var oldObject = {
	sayHello = function(){
		console.log('Hello');
	},
	sayHi: sayHi
}

oldObject[es+'6'] = 'wow';

oldObject.sayHi();
oldObject.sayHello();
console.log(oldObject.ES6);

ES6부터 다음과 같이 정의가 가능하다.

var sayHi = function(){
	console.log('Hi');
}

var es = 'ES';
var newObject = {
	sayHello(){
		console.log('Hello');
	},
	sayHi,
	[es+'6'] = 'fantastic';
}

newObject.sayHi();
newObject.sayHello();
console.log(newObject.ES6);
  • 객체 메서드에 함수를 연결할 때 콜론과 function 없이 연결이 가능하다.
  • sayHi: sayHi 와 같은 중복되는 이름의 변수는 하나만 적으면 된다.
  • 객체의 속성을 동적으로 생성이 가능하다. 이전엔 객체 리터럴 밖에서 [es + 6]으로 생성이 가능했지만 이젠 안에서도 생성이 가능하다.

화살표 함수

화살표 함수는 =>를 이용해서 함수를 만든다. 또한 화살표 함수는 항상 익명 함수로만 사용할 수 있다.

  • 표현식의 결과 값을 반환하는 표현식 본문(expression bodies)
  • 상태 블럭 본문(statement block bodies)
const numbers = [2, 4, 6, 8];

//Expression Bodies
const odd = numbers.map(number => number + 1);
const nums = numbers.map((number, index) => number + index);

//Statement Block Bodies
nums.forEach((num) => {
	if (num % 5 === 0){
		fives.push(num);
	}
})

this가 존재하지 않는다

또한 this가 없다는 점에서 일반 함수와 다르다. 일반 함수에선 자신을 호출하는 객체를 가리키는 dynamic this가 변화되는 반면, 화살표 함수는 상위 스코프를 가리키는 lexical this를 가진다.

때문에 현재 범위에서 존재하지 않는 this를 화살표 함수의 바로 바깥 범위에서 this를 찾게 된다.

var bob = {
	'name': 'jeong',
	'friends': ['John', 'Brain'],
	printFriend(){
		this.friends.forEach(function(friend){
			console.log(this.name + 'knows' + friend);
		}.bind(this))
	}
}

위의 printFriend 함수를 다음과 같이 바꿀 수 있다.

this.friends.forEach((friend) => {
	console.log(this.name + 'knows' + friend);
})

arguments가 존재하지 않는다

일반적인 함수에는 arguments 프로퍼티가 존재한다. 하지만 화살표 함수에는 존재하지 않는다.

const test1 = function(){
    console.log(arguments);
}
test1(1,2,3,4,5); // [1,2,3,4,5]

const test2 = () => {
	console.log(arguments);
}
test2(1,2,3,4,5); //ReferenceError: arguments is not defined

대신 화살표 함수에선 rest 파라미터를 반드시 사용해야한다. (spread 문법 이용)

const test = (...args) => {
    console.log(args);
}

test(1,2,3,4,5); //[1,2,3,4,5]

여기서 arguments와 args의 차이는 arguments는 유사배열이고 args는 배열이다.

화살표 함수를 사용하면 안되는 경우

화살표 함수는 Lexical this를 지원하므로 콜백 함수로 사용되기 좋다. 하지만 다음과 같은 상황들에선 화살표 함수를 사용하면 오히려 혼란을 줄 수 있다.

메소드

화살표 함수로 메소드를 정의하는 것은 피해야한다.

const person = {
	name: 'jeong',
	sayHi: () => console.log(`Hi ${this.name}`)
}

person.sayHi(); // this.name은 undefined

화살표 함수의 this는 항상 상위 스코프의 this를 가리키니 이때는 전역 객체의 window를 가리키게된다. 따라서 화살표 함수를 메소드로 정의하는것은 바람직하지 않다.

만약 사용하고싶다면 아래와 같이 사용이 가능하다.

sayHi(){
	console.log(`Hi ${this.name}`);
}

prototype

화살표 함수로 객체의 메소드를 정의하였을때와 같은 문제가 발생한다. 따라서 prototype 메소드로는 일반 함수를 사용하자.

생성자 함수

화살표 함수는 생성자 함수로 사용할 수 없다. 생성자 함수는 prototype 프로퍼티를 가지는데 prototype 프로퍼티가 가리키는 프로토타입 객체의 constructor를 사용한다.

하지만 화살표 함수는 prototype 프로퍼티를 가지고 있지 않다.

const Test = () => {};

console.log(Test.hasOwnProperty('prototype')); //false

const test = new Test(); // TypeError: Test is not a constructor

addEventListener 함수의 콜백 함수

addEventListener 함수의 콜백 함수를 화살표 함수로 정의하면 this가 전역 객체 window를 가리킨다.

let button = document.querySelector('button');

button.addEventListener('click', () => {
	console.log(this === window); // true
	this.innerHTML = 'Clicked button';
});

따라서 addEventListener 함수의 콜백 함수 내에서 this를 사용하려할땐 일반 함수로 사용하는 것이 좋다. 일반 함수로 정의된 addEventListener 함수의 콜백 함수 내부의 this는 이벤트 리스너에 바인딩된 요소를 가리킨다.

let button = document.querySelector('button');

button.addEventListener('click', () => {
	console.log(this === button); // true
	this.innerHTML = 'Clicked button';
});

비구조화 할당

객체나 배열에서 속성 혹은 요소를 꺼내올때 사용한다.

const [a, , c] = [1, 2, 3];
const obj = {
	name: 'jeong',
	age: 24,
	status: {
		count1: 5
	}
}

const {name, age, status: {count1}} = obj;

매개변수 기본값

ES6는 매개변수 기본값을 사용하여 함수 내에서 인수 체크 및 초기화를 간단하게 할 수 있다.

매개변수 기본값은 매개변수에 인수를 전달하지 않았을 경우에만 유효하다.

function sum(x = 0, y = 0){
	return x + y;
}

console.log(sum(1));     // 1
console.log(sum(1, 2));  // 3

Rest 파라미터

매개변수 이름 앞에 점 3개 ... 를 붙여서 정의한 매개변수를 말한다. 함수에 전달된 인수들의 목록을 배열로 전달한다.

function sum(...rest){
	console.log(rest); //[1, 2, 3, 4]
}

sum(1,2,3,4);

Rest 파라미터 이름 그대로 먼저 선언된 파라미터에 할당된 인수를 제외한 나머지 인수들이 모두 배열에 담겨 할당된다. 따라서 Rest 파라미터는 항상 맨 마지막에 있어야한다.

function sum(a, b, ...rest){
	console.log(a); // 1
	console.log(b); // 2
	console.log(rest); // [3, 4]
}

sum(1, 2, 3, 4);

Spread 문법

Spread 문법은 대상을 개별 요소로 분리한다. Spread 문법 대상은 이터러블해야한다.

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

// 문자열은 이터러블이다. 
console.log(...'Hello'); //H e l l o

// Map과 Set은 이터러블이다.
console.log(...new Map([['a', '1'], ['b', '2']]));  // [ 'a', '1' ] [ 'b', '2' ]
console.log(...new Set([1, 2, 3]));  // 1 2 3

// 이터러블이 아닌 일반 객체는 Spread 문법의 대상이 될 수 없다.
console.log(...{ a: 1, b: 2 });
// TypeError: Found non-callable @@iterator

참고

0개의 댓글