Programming Languages

[JavaScript] Next Generation JavaScript : ES6

Sara.H 2020. 8. 7. 17:29

* ES6-8 까지는 대부분의 모던 브라우저에서 지원하지만, 오래된 브라우저에서는 ES5 로 변환해야 함. 

 

`let` and `const`

- const : 불변값 

- let : 가변값 

var name = 'jane'; 
var age = 23; 

name = 'jane miller'; 
console.log(name); //jane miller 가 출력된다. 

//ES6 
const name1 = 'jane smith'; 
let age1 = 24; //something that can mutate 
name1 = 'jane doe'; // Type Error !!! 

* const 와 let 은 block scoped 이지만, var 은 function scoped 이다. 

var 은 함수 안에서 if문 안에서 선언되었더라도 if 문 밖에서도 접근이 가능하다. 하지만 const 와 let 은 if 문 안에서 선언되었으면 그 밖에서는 사용이 불가능하다. (Created inside a block, cannot access from outside of the block.)

 

let i = 23; //바깥의 i 와 

for(let i = 0; i < 5; i++){ //for 조건 안의 i 는 다른 i 이다. 
...
}

 

Blocks and IIFEs (Immediately Invoked Functions Expressions)

{
  const a = 1; 
  let b = 2; 
  var c = 3; 
}

console.log(a + b); //error 위에 선언된것들 접근 불가 
console.log(c); // 3을 출력한다.

 

Strings in ES6

let firstName = 'john'; 
let lastName = 'Smith'; 
const yearOfBirth = 1990; 

function calAge(year){
  return 2016 - year; 
}

//ES6 Back ticks (플러스 사인 사용하지 않아도 됨.)
console.log(`This is ${firstName} ${lastName}. He is ${calcAge(yearOfBirth)} years old.`); 

const n = `${firstName} ${lastName}`; 
n.startsWith('J'); //returns boolean 
n.endsWith('th'); //returns boolean 
n.includes('Sm'); //returns boolean

firstName.repeat(5); //5번을 연속으로 출력한다. 
console.log(`${firstName} `.repeat(5)) //빈칸과 함께 다섯 번 출력 

 

Arrow functions : Basics 

const years = [1990, 1965, 1982, 1927]; 
var age5 = years.map(function(el){
	return 2016 - el; 
}); 
console.log(age5); 

//ES6 위의 함수와 같은 기능을 한다. function, return 키워드 X
const age6 = years.map(el => 2016 - el); 
const age61 = years.map(
	(el, index) => `Age element ${index + 1} : ${2016 - el}`
); 
console.log(age61); //스트링의 배열로 출력이 된다.

//한 줄 이상일 경우 {} 를 사용한다
const age62 = years.map((el, index) => 
	{
    	const now = new Date().getFullYear(); 
        const curAge = now - el; 
        return `Age element ${index + 1} ${curAge}`
    }
);

 

Arrow functions 2 

var box = {
	color : 'green', 
    position : 1, 
    clickMe : function(){
    
    //문제 해결을 위해 여기에 변수 선언 
    var self = this;
    	document.querySelector('.green').addEventListener('click', 
        	function(){
            //this 키워드는 함수 안에서 글로벌 객체를 가리키므로 undefined 로 나온다 
            	var str = 'This is box number' + this.position
                + ' and it is ' + this.color ; 
                //self.position, self.color 으로 접근함
                alert(str); 
            }
        )
    }
}
box.clickMe(); 

//ES6 
const box1 = {
	color : 'green', 
    position : 1, 
    clickMe : function() {
    	document.querySelector('.green').addEventListener(
        	'click', () => { //arrow 함수를 사용해서 this 키워드 문제를 해결 
            	var str = 'This is box number' + this.position
                + ' and it is ' + this.color ; 
             alert(str); 
            }
      	)
    }
}

const box2 = {
	color : 'green', 
    position : 1, 
    clickMe : () => { //여기를 arrow 함수로 바꾸면 다시 undefined 가 나옴
    	document.querySelector('.green').addEventListener(
        	'click', () => {
            	var str = 'This is box number' + this.position
                + ' and it is ' + this.color ; 
             alert(str); 
            }
      	)
    }
}

//추가 예시 
function Person(name){
	this.name = name; 
}

Person.prototype.myFriends = fucntion(friends){
	var arr = friends.map(function(el){
    	return this.name + ' is friends with ' + el;
    }.bind(this)); //bind this 를 해서 this 문제를 해결한다
    console.log(arr); 
}

var friends = ['a', 'b', 'c']; 
new Person('John').myFriends(friends); 
//위의 this.name 이 출력되지 않음. this 는 글로벌 객체를 가리킴!

//ES6 버전 
Person.prototype.myFriends = fucntion(friends){
	const arr = friends.map((el) => 
     	`${this.name} is friends with ${el}`; 
    );
    console.log(arr);
}

 

Destructuring 

var john = ['John', 26]; 
var name = john[0]; 
var age = john[1]; 

//위 처럼 매 번 따로 변수에 담아서 해체하면 귀찮음 
//ES6
const [name6, year6] = ['John', 26]; 
console.log(name6); 

const obj = {
	firstName : 'John', 
    lastName : 'Smith'
}; 
const {firstName, lastName} = obj; //해체하기 
console.log(firstName); //출력 가능 

const {firstName : a, lastName : b} = obj; 
console.log(a); //다른 이름 할당해서 출력하기도 가능 

function cal(year){
	const age = new Date().getFullYear() - year; 
    return [age, 65 - age]; 
}

const [age2, retirement] = cal(1990); 
console.log(age2); //이렇게 바로 함수에서 반환받을 수 도 있음 

 

Arrays

const boxes = document.querySelectorAll('.box'); 

//ES5 
var boxesArr5 = Array.prototype.slice.call(boxes); 
boxesArr5.forEach(function(cur){
	cur.style.backgroundColor = 'dodgerblue'; 
})

//ES6 
const boxesArr6 = Array.from(boxes); //배열로 변환 
boxesArr6.forEach(
	(cur) => cur.style.backgroundColor = 'dodgerblue'
)

//loop over an array 
//ES5 
for(var i = 0; i < boxesArr5.length; i++){
	if(boxesArr5[i].className === 'box blue'){
    	continue; 
    }
    boxesArr5[i].textContent = 'I changed to blue'
}

//ES6 
for(const cur of boxesArr6){ //for ... of 를 사용 
	if(cur.className.includes('blue')){ //includes 를 사용해서 좀 더 개성 
    	continue; 
    }
    cur.textContent = 'I changed to blue'
}

//배열에서 요소 찾기 
//ES5 
var ages = [12, 23, 43, 11, 76, 3]; 
var full = ages.map(function(cur){
	return cur >= 18; 
})
var idx = full.indexOf(true);
console.log(ages[idx]); //찾기가 힘들다 ... 

//ES6 
//콜백 함수로 인덱스를 찾기 
const idx1 = ages.findIndex(cur => cur >= 18); //조건에 맞는 요소의 인덱스를 찾는다
console.log(ages.find(cur => cur >= 18)); //찾은 요소를 반환해준다

 

The Spread Operator 

function addFourAges(a, b, c, d){
	return a + b + c + d; 
}
var sum1 = addFourAges(18, 20, 23, 11); 
console.log(sum1); 

//배열 전체를 인자로 넘겨주려면?

//ES5
var ages = [10, 23 ,12, 11]; 
var sum2 = addFourAges.apply(null, ages); //배열을 갖고 요소들을 이용해서 함수 호출 
console.log(sum2); 

//ES6 
const max3 = addFourAges(...ages); //배열을 요소들로 쪼갠다 
console.log(max3); 

const arr1 = [ ... ]
const arr2 = [ ... ]
const bigArr = [...arr1, ...arr2, 'element']; //여러개를 해체할수도 있다 
//중간에 요소를 추가해도 됨 

 

Rest Parameters

* 여러개의 개별 값들을 받아서 배열로 변환한다. 

//ES5 
function isFullAge(){
	console.log(arguments); //특별 변수, 모든 함수에서 사용 가능 
    var argsArr = Array.prototype.slice.call(arguments); 
    argsArr.forEach(
    	function(cur){
        	console.log(2016 - cur) >= 18); 
        }
    ); //배열로 바꾸기 위해 귀찮은 작업 해야함
}

isFullAge(1990, 1222, 1212); //변수들의 배열 같은게 출력됨 (배열인건 아님)

//ES6 
//함수를 호출하면 바로 배열로 변환함
function isFullAge2(limit, ...years){
	console.log(years); //배열이 출력됨 
    years.forEach(
    	console.log(cur => (2016 - cur) >= limit)
    ); 
}
isFullAge2(18, 1990, 1992, 1994); //18 is the limit 

 

Default Parameters 

//ES5
function SmithPerson(firstName, lastName){

	if(lastName === undefined){
    	lastName = 'Smith'; 
    }
    //이런식으로 default 를 처리해 주어야 함 
	
	this.firstName = firstName; 
    this.lastName = lastName; 
}

var john = new SmithPerson('John'); //꼭 모든 매개변수를 다 넘겨주지 않아도 된다. 
//다 넘겨주지 않으면 그냥 undefined 가 됨. 

//ES6 
function SmithPerson(firstName, lastName = 'Smith'){
	... //바로 매개변수 쪽에서 기본 값을 설정할 수 있음 
}

 

Maps

const question = new Map(); //비어있는 맵 구조 
question.set('question', 'What is the official name of the latest major JS version?'); 
//key 와 value 를 지정할 수 있다. 
question.set(1, 'ES5'); 
question.set(2, 'ES6'); 
question.set(3, 'ES2015'); 
question.set('correct', 3); 
question.set(true, 'Correct Answer'); 
question.set(false, 'Wrong, please try again'); 

//하나의 맵에 여러개의 자료타입을 섞을 수 있음 
console.log(question.get('question'));
console.log(question.size); //맵의 사이즈를 반환한다. 

//요소를 제거할 수 있음 
question.delete(3); //키 값이 3인 요소를 삭제한다. 

if(question.has(4)){
	question.delete(4); //키가 4인것이 있으면 삭제한다. 
}

//question.clear(); //모든 요소들을 삭제한다. 

//loop 를 돌릴 수 도 있음 
question.forEach(
	(value, key) => {
    	console.log(`This is ${key} and it is set to ${value}`)
    }
); 

for(let [key, value] of question.entries()){ 
//entries 를 호출해서 desctructuring 을 사용 
    //key 가 숫자인것만 출력 해보자 
    if(typeof(key) === 'number'){
    	console.log(`Answer ${key} : ${value}`); 
    }
}

const ans = parseInt(prompt('Write the correct answer')); 
const result = question.get(ans === question.get('correct')); 
//결과에 맞는 string 을 회수할 수 있다. 
console.log(result); 

 

Classes 

var Person5 = function(name, yob, job){
	this.name = name; 
    this.yob  = yob; 
    this.job = job; 
}

Person5.prototype.calculateAge = function(){
	var age = new Date().getFullYear - this.yob; 
    console.log(yob); 
}

var john = new Person5('asdf', 1990, 'teacher'); 

//ES6
class Person6{
	constructor(name, yob, job){
      this.name = name; 
      this.yob  = yob; 
      this.job = job;
    }
    
    calculateAge = () => {
    	//... 함수를 추가한다. 
    }
    
    static greeting(){
    	console.log('Hello'); 
    }
}

Person6.greeting(); //스태틱 함수를 호출하는 방법 

 

Classes with Subclasses 

//위의 Person5 를 상속받는 Athlete5 를 작성 
//생성자를 만들고 
var Athlete5 = function(name, yob, job, olympicGames, medals){
	Person5.call(this, name, yob); 
    this.olympicGames = olympicGames; 
    this.medals = medals; 
}

//프로토타입을 연결한다. 
Athlete5.prototype = Object.create(Person5.prototype); 
var jj = new Athlete('jj', 1990, 'swimmer', 3, 10);

//상속받은 함수를 사용할 수 있다. 
jj.calculateAge(); 

//하위클래스에 메서드를 따로 정의하기 
Athlete5.wonMedal = function(){
	this.medals++; 
    console.log(this.medals); 
}

//ES6 
class Athlete6 extends Person6{
	constructor(name, yob, job, og, medals){
    	super(name, yob, job); 
        this.og = og; 
        this.medals = medals; 
    }
    
    wonMedal(){
    	this.medals++; 
        console.log(this.medals); 
    }
}

const jja = new Athlete6('jja', 1990, 'swimmer', 3, 5); 
jja.wonMedal(); 
jja.calculateAge();