Ecma Script란?
javascript라는 브라우저를 위한 표준 규정표라고 생각하면 된다.
즉 javascript를 사용하는 데 있어서 이렇게 사용하면 된다. 혹은 이런 알고리즘은 이러한 문법으로 코드를 짜야 한다라고
정해둔 표준인 것이다.
그리고 es6란 가장 최근 기준의 표준인 것이다.
ecma script를 이해하려면 javascript의 탄생에 대해서 약간 이해하고 넘어가면 좋다.
애초에 script언어가 탄생했을 때는 정해진 규정이 없다보니 통일성이 없어서, 개발자들이 하나의 언어를 위해 모든 문법들과
해당 사항 등을 공부해야 하는 번거로움이 있었다.
그러다 통일된 표준을 만들어야 하는 필요성을 느껴 생긴 것이 ecma script라고 생각하면 된다.
몇 년전, es4 즉, 네번째 개정에서 표준에 대한 가장 큰 변화가 있었고, 그 이후에는 일부 사항만 변화되었다.
ES6의 주요 문법들
Scope(유효범위)
전체적인 코드 내에서 변수가 영향을 미치는 범위이다.
전역변수란 함수같은 어떠한 괄호 범위 내가 아니라, 코드 전체에서 선언된 변수로 코드 전체에 영향을 미친다.
scope에 대한 이야기를 하면 자연스레 JS의 변수에 대한 설명도 추가적으로 진행되어야 한다.
es6로 개정 전에는, var 변수만 존재했다. 해당 변수는 재선언이 가능할 뿐 아니라, 호이스팅이 가능하다는 특징을 지니고 있다.
호이스팅이란 원래 변수가 선언되고 난 이후에, 그 변수에 대해서 사용할 수 있는데,
선언 순서에 상관 없이, 코드 작성 위로도 영향범위가 미치는 경우이다.
var 변수가 바로 호이스팅이 가능하며, JS의 유연한 사용성을 설명해주기도 한다.
또한 var변수는 function 함수 내에서만 유효하며, 다른 괄호범위나 for문 등의 내에서만 선언되면 전역변수로 작용한다.
여기서 let과 const 변수가 생기면서, 호이스팅에 대해서 엄격한 기준이 생겼다.
또한, let은 변수 선언이 된 이후에, 재선언이 가능하여 변수의 값을 변경하는 것이 가능하지만,
const는 불가능하여, 실제 사용 목적에 따라서 변수 선언을 달리하여, 오류를 줄일 수 있게 되었다.
가령 실제 코드를 작성하다보면 많이 사용하게 될 경우인데, 전역 변수로서 하나의 변수를 선언하고 난 이후에, for이나 함수를 통해 해당 값을 변수없이 그냥 선언하여 값을 변경해주려고 하는 경우가 있다.
이런 경우에는 const로 변수 선언해주면 안된다.
하지만 코드가 길어질 경우, 차후에 중복되어 변수가 선언될 경우를 방지하기 위해 const를 사용해야 할 수도 있다.
Arrow Function
기존의 function 함수형태를 좀 더 간단하게 사용할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
//사용 전
function sayHello(name) {
console.log('Hello', name);
}
setTimeout(function() {
console.log('Loaded')
}, 2000);
list.forEach(function(item) {
console.log(item);
});
function hi(input){
return input*2;
}
//사용 후
sayHello = name => console.log('Hello', name);
setTimeout(() => console.log('Loaded'), 2000);
list.forEach(item => console.log(item));
var hi = input => input*2;
|
cs |
삼항연산자
if문을 좀 더 간단하게 표현한 것이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
//사용 전
const x = 20;
let answer;
if (x > 10) {
answer = 'greater than 10';
} else {
answer = 'less than 10';
}
//사용 후
const answer = x > 10 ? 'greater than 10' : 'less than 10';
//만약에 결과 값의 문장이(return 문장) 여러 줄일 경우,
//사용 전
const x = 20;
let answer;
if (x > 10) {
answer = 'greater than 10';
return answer + "true"
} else {
answer = 'less than 10';
return answer + "false"
}
//사용 후
const answer = x > 10 ? (
answer = 'greater than 10',
return answer + "true"
) : (
answer = 'less than 10',
return answer + "false"
);
//else 구문이 없거나, 삼항연산자로 가독성이 떨어지는 경우에는 굳이 삼항연산자를
//사용하는 것보다 기존대로 코드를 작성하는 것이 좋다.
|
cs |
for..of문 & for...in문
배열 혹은 객체 내에서 반복문을 돌때
1
2
3
4
5
6
7
8
|
//사용 전
for (let i = 0; i < allImgs.length; i++)
//사용 후
//1) object 내에서 반복문 돌릴경우 : for in 사용
for (let i in object)
//2) array 내에서 반복문 돌릴 경우 : for of 사용
for (let i of array)
|
cs |
객체 내의 변수 사용하기
1
2
3
4
|
const list = { name = 'a', item='b'}
const {name, item} = list
console.log(name, item)
//a , b가 콘솔창에 찍히게 된다.
|
cs |
Default Parameter
함수 선언문 자체에서 기본값을 지정해 줄 수 있는 방법이다.
1
2
3
4
5
|
volume = (l, w = 3, h = 4 ) => (l * w * h);
volume(2) //output: 24
// input 변수 l의 경우에 기본값을 지정해 주지 않았으므로,
//volume(2)의 의미는 변수 l자리에 2를 입력했다는 의미이다.
//만약에, w나 h에 함수 내에서 별도로 변수를 지정해주면, 기본값말고 지정해준 값이 입력된다.
|
cs |
Template literal
백틱(``)과 ${}를 활용하여, String과 변수가 혼합된 코드를 더 편하게 작성할 수 있다.
1
2
3
4
5
6
7
8
|
//사용 전
const welcome = 'You have logged in as ' + first + ' ' + last + '.'
const db = 'http://' + host + ':' + port + '/' + database;
//사용 후
const welcome = `You have logged in as ${first} ${last}`;
const db = `http://${host}:${port}/${database}`;
|
cs |
Spread Operator / Rest Parameter
Rest Parameter을 활용하여, Spread Operator( 전개연산자)가 가능하다.
Rest Parameter
보통 변수가 따로 정해지지 않았을때,
함수 내에서 arguments를 사용하여 따로 정의하지 않고도 변수를 활용한 코드 작성이 가능하다.
1
2
3
|
function(…args){
var a = args[0];
}
|
cs |
Rest Parameter로도 가능하다.
=> 꼭 ‘…args’ 변수가 아니어도 된다. rest parameter의 경우
넣고자 하는 변수 명 앞의 ‘…(온점세개)’ 중요하다. 가령 ‘function(…num)’ 의 경우와 같다.
이 때, arguments로 사용해주면, 해당 변수에 forEach 메소드 사용이 불가하다.
하지만 Rest Parameter로 사용해주면 forEach 메소드 사용이 가능하다.
Spread Operator
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
//사용 전
// joining arrays
const odd = [1, 3, 5];
const nums = [2 ,4 , 6].concat(odd);
// cloning arrays
const arr = [1, 2, 3, 4];
const arr2 = arr.slice()
//사용 후
// joining arrays
const odd = [1, 3, 5 ];
const nums = [2 ,4 , 6, ...odd];
console.log(nums); // [ 2, 4, 6, 1, 3, 5 ]
// cloning arrays
const arr = [1, 2, 3, 4];
const arr2 = [...arr];
|
cs |
this 키워드
호출되는 함수가 실행될 때, this가 있다면, 이 키워드가 가르키는 특정 객체에 대해서 함수가 실행 될 것이다.
1. global
일반적으로 코드 전체에서 선언된 변수나, 일반 function내에서 선언된 this 키워드는 window를 가르킨다.
2. Method 호출
객체.메소드()형태로 this 키워드가 선언될 때, 여기서 this는 객체를 가르킨다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
let counter1 = {
value: 0,
increase: function() {
this.value++
// 메소드 호출을 할 경우, this는 counter1을 가리킵니다
},
decrease: function() {
this.value--
},
getValue: function() {
return this.value
}
}
counter1.increase()
counter1.increase()
counter1.increase()
counter1.decrease()
counter1.getValue() // 2
function makeCounter() {
return {
value: 0,
increase: function() {
this.value++
// 메소드 호출을 할 경우, this는 makeCounter 함수가 리턴하는 익명의 객체입니다
},
decrease: function() {
this.value--
},
getValue: function() {
return this.value;
}
}
}
let counter1 = makeCounter()
counter1.increase()
counter1.getValue() // 1
let counter2 = makeCounter()
counter2.decrease()
counter2.decrease()
counter2.getValue() // -2
|
cs |
3. new 키워드를 통한 생성자 호출
객체지향적인 성격을 지닌 JS를 사용할 때, 프로토타입과 인스턴스 생성을 많이하게 될 것이다.
차후에 공부하게 될 프로토타입 및 더 나아가서 리액트 컴포넌트를 공부하며서 계속 등장할 개념이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
class Counter {
constructor() {
this.value = 0; // 생성자 호출을 할 경우, this는 new 키워드로 생성한 Counter의 인스턴스입니다
}
increase() {
this.value++
}
decrease() {
this.value--
}
getValue() {
return this.value
}
}
let counter1 = new Counter() // 생성자 호출
counter1.increase()
counter1.getValue() // 1
|
cs |
4. call, apply, bind
call, apply
함수(func)의 메소드들이다.
.call, .apply 호출은 명시적으로 this를 지정해서 실행하고 싶을 때 사용한다. 첫번째 인자가 항상 this값이 되어야 한다.
즉 첫번째 인자로, 함수가 불러올 때 this로 명시해서 가지고 오고 싶은 인자를 집어넣으면 된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
//call과 apply는 기능은 유사하나, 사용법이 다를 뿐
function foo() {
return 'bar'
}
foo(1,2,3) //<-여기서 1,2,3은 인자이다.
foo.call(null,1,2,3)
foo.apply(null,[1,2,3])
//call은 넣고자 하는 인자들을 this 다음에 나열하고,
//apply는 this뒤에 배열의 형태로 집어 넣는다.
//예제
// null을 this로 지정합니다. Math는 생성자가 아니므로 this를 지정할 필요가 없습니다.
Math.max.apply(null, [5,4,1,6,2]) // 6
// spread operator의 도입으로 굳이 apply를 이용할 필요가 없어졌습니다.
Math.max(...[5,4,1,6,2]) // 6
//다음은 prototype을 빌려 실행하는 예제를 보여주고 있습니다.
//예제
// '피,땀,눈물'을 this로 지정합니다.
''.split.call('피,땀,눈물', ',')
// 다음과 정확히 동일한 결과를 리턴합니다.
'피,땀,눈물'.split(',')
let allDivs = document.querySelectorAll('div');
// NodeList라는 유사 배열입니다.
// allDivs를 this로 지정합니다.
[].map.call(allDivs, function(el) {
return el.className
})
// allDivs는 유사 배열이므로 map 메소드가 존재하지 않는다.
// 그러나, Array prototype으로부터 map 메소드를 빌려와
//this를 넘겨 map을 실행할 수 있습니다.
//객체 지향 프로그래밍에서 찾아볼 수 있는 예제
function Product(name, price) {
this.name = name
this.price = price
}
function Food(name, price) {
Product.call(this, name, price)
// 인자가 많으면 Product.apply(this, arguments) 가 더 유용합니다.
this.category = 'food'
}
let cheese = new Food('feta', 5000)
// cheess는 Food이면서 Product입니다.
|
cs |
bind
.bind는 .call과 유사하게 this 및 인자를 바인딩하나, 당장 실행하는 것이 아닌 바인딩된 함수에 대해 값을 단순히 리턴한다.
첫번째 인자는 this, 두번째 인자부터는 필요한 파라미터를 전달합니다.
fn.bind(this값, 인자1, 인자2, ...)
*bind의 실제 사용 사례
case 1: 이벤트 핸들러
이벤트 핸들러에서 이벤트 객체 대신 다른 값을 전달하고자 할 때
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
|
//예제1
<button id="btn">클릭하세요</button>
let btn = document.querySelector('#btn')
// 추후 이벤트에 의해 불리게 될 함수에서, this는 {hello: 'world'}가 됩니다.
btn.onclick = handleClick.bind({ hello: 'world'})
function handleClick() {
console.log(this)
}
//예제2
//bind 사용전
<div id="target"></div>
let target = document.querySelector('#target')
let users = ['김코딩', '박해커', '최초보']
users.forEach(function(user) {
let btn = document.createElement('button')
btn.textContent = user
btn.onclick = handleClick
target.appendChild(btn)
});
function handleClick() {
console.log(this)
}
//위와 같이 코드를 작성하면, 동적으로 생성되는 각각의 버튼을 클릭하면 button 엘리먼트 자체가 콘솔에 표시될 것.
//이 때 bind를 이용해 출력하고 싶은 값을 this로 넘기거나, 혹은 인자로 보낼 수 있다.
//bind 사용후
//Solution 1:
let target = document.querySelector('#target')
let users = ['김코딩', '박해커', '최초보']
users.forEach(function(user) {
let btn = document.createElement('button')
btn.textContent = user
btn.onclick = handleClick.bind(user)
target.appendChild(btn)
});
function handleClick() {
console.log(this)
}
//Solution 2:
let target = document.querySelector('#target')
let users = ['김코딩', '박해커', '최초보']
users.forEach(function(user) {
let btn = document.createElement('button')
btn.textContent = user
btn.onclick = handleClick.bind(null, user)
// 굳이 this를 이용하지 않더라도 인자로 넘길 수도 있다.
target.appendChild(btn)
});
function handleClick(user) {
console.log(user)
}
|
cs |
case 2: setTimeout
setTimeout은 시간 지연을 일으킨 후 함수를 비동기적으로 실행하게 하는 함수이다. 이 함수는 명시적으로 항상 window 객체를 this 바인딩하는 특징이 있다. 그래서 다음과 같은 문제 상황이 발생할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
//예제
class Rectangle {
constructor(width, height) {
this.width = width
this.height = height
}
getArea() {
return this.width * this.height
}
printArea() {
console.log('사각형의 넓이는 ' + this.getArea() + ' 입니다')
}
printSync() {
// 즉시 사각형의 넓이를 콘솔에 표시합니다
this.printArea()
}
printAsync() {
// 1초 후 사각형의 넓이를 콘솔에 표시합니다
setTimeout(this.printArea, 2000)
}
}
let box = new Rectangle(40, 20)
box.printSync() // '사각형의 넓이는 800 입니다'
box.printAsync() // 에러 발생!
//에러를 통해 this가 Rectangle의 인스턴스가 아니라는 것을 확인할 수 있다.
Uncaught TypeError: this.getArea is not a function
at printArea (<anonymous>:12:36)
printAsync() {
// 1초 후 사각형의 넓이를 콘솔에 표시합니다
setTimeout(this.printArea.bind(this), 2000)
}
|
cs |
Closure
외부함수의 변수에 접근할 수 있는 내부변수이다.
즉 외부함수에서 사용된 변수가 내부함수에도 똑같이 사용되고 있다면 그 내부함수는 closure이다.
scope 체인과 연관된 개념이다. 즉 선언된 변수가 영향을 미치는 범위와 연관된 개념인 것이다.
1
2
3
4
5
6
7
8
9
10
|
function outer(){
var a =1;
function inner(){
console.log(a)
}
inner();
}
outer();
}
|
cs |
'Programming Language > JS&TS' 카테고리의 다른 글
JavaScript_동기&비동기(이벤트 루프) (2) | 2021.02.11 |
---|---|
JS - 객체지향 프로토타입 (2) | 2021.02.04 |
Javascript와 Node의 차이점을 정리해보자 (1) | 2021.01.21 |
JS 변수 선언 방식_ let, var, const의 차이 (0) | 2021.01.21 |
Typescript 이해하기 (0) | 2020.11.23 |