우선 ECMAScript6 공식 홈페이지는 아래와 같다.
위 페이지를 보면 알겠지만 지금은 우리에게 익숙하고 당연한 것들이 상당히 많은데 자세히 알아보자.
Constants
다시 할당할 수 없는 변수 const의 추가
Scoping
블록{}범위 변수 let, const의 추가
기존 함수의 스코프를 블록{}범위 함수로 변경
//es6 => 하지만 블록{}으로만 감싸주어도 지역스코프의 함수로 선언 가능
{
function foo () { return 1 }
foo() === 1
{
function foo () { return 2 }
foo() === 2
}
foo() === 1
}
// es5 => 지역스코프의 함수로 선언하기 위해 ()로 감싸고 호출하는 코드를 작성해야 됬었다.
(function () {
var foo = function () { return 1; }
foo() === 1;
(function () {
var foo = function () { return 2; }
foo() === 2;
})();
foo() === 1;
})();
Arrow Functions
화살표 함수의 추가로 훨씬 더 가독성이 올라가게 되었다.
//es6
odds = evens.map(v => v + 1)
pairs = evens.map(v => ({ even: v, odd: v + 1 }))
nums = evens.map((v, i) => v + i)
//es5
odds = evens.map(function (v) { return v + 1; });
pairs = evens.map(function (v) { return { even: v, odd: v + 1 }; });
nums = evens.map(function (v, i) { return v + i; });
화살표 함수는 lexical this를 따른다. => 화살표 함수는 (한번쓰고 버리는게 화살표함수)본인이 가지고 있는 this가 없다. 화살표 함수외에 다른 함수는 this가 있어서 참조할 수 있는데. 그렇다면 화살표함수안에서 this를 찍으면 무엇을 참조할까? 상위 scope의 this를 참조한다. lexical의 의미가 내가 속한 scope가 참조하는 상위 scope. 그러므로 화살표 함수는 lexical this를 따른다.
javascript에서 this란 생성자 함수안에서 앞으로 생성될 인스턴스를 가르키는 식별자이다.
this 바인딩은 this와 this의 대상이 되는 인스턴스를 연결해주는 과정이다.
참고로 javascript에서의 this와 node.js에서의 this는 다른 의미를 가진다.
Extended Parameter Handling
함수의 매개변수에 default value를 설정하려면 함수안에서 별도로 설정 해줘야 했지만
es6에서는 그럴 필요가 없이 매개변수에다가 바로 할당 해 놓으면 된다.(어디서 본 것은 같은데 굉장히 낯설다.) 아래 예시를 보자.
Default Parameter Values
//es6
function f (x, y = 7, z = 42) {
return x + y + z
}
f(1) === 50
//es5
function f (x, y, z) {
if (y === undefined)
y = 7;
// var y = y || 7 로도 쓸 수 있다.
if (z === undefined)
z = 42;
// var z = z || 42 로도 쓸 수 있다.
return x + y + z;
};
f(1) === 50;
단일 매개변수로 나머지 인자를 다룰 수 있다.
Rest Parameter
//es6
function f (x, y, ...a) {
return (x + y) * a.length
}
f(1, 2, "hello", true, 7) === 9
//es5
function f (x, y) {
var a = Array.prototype.slice.call(arguments, 2);
//Rest Parameter 보다 위의 내용이 더 새로워 보인다.
return (x + y) * a.length;
};
f(1, 2, "hello", true, 7) === 9;
배열이나 문자열(iterable collection)의 요소들을 문자그대로의 요소나 함수의 개별 매개변수로 분산시키는 것이 가능하게 되었다.
문장으로 적으면 복잡해 보이지만 예시로 보면 오히려 쉽다.
Spread Operator
//es6
var params = [ "hello", true, 7 ]
var other = [ 1, 2, ...params ] // [ 1, 2, "hello", true, 7 ]
function f (x, y, ...a) {
return (x + y) * a.length
}
f(1, 2, ...params) === 9
var str = "foo"
var chars = [ ...str ] // [ "f", "o", "o" ]
//es5
var params = [ "hello", true, 7 ];
var other = [ 1, 2 ].concat(params); // [ 1, 2, "hello", true, 7 ]
function f (x, y) {
var a = Array.prototype.slice.call(arguments, 2);
return (x + y) * a.length;
};
f.apply(undefined, [ 1, 2 ].concat(params)) === 9;
var str = "foo";
var chars = str.split(""); // [ "f", "o", "o" ]
Template Literals
문자열에 대하여 조금더 직관적인 표현이 가능하게 해주는 Template Literal의 등장
Template Literal은 `${}`(${}안에)자바스크립트 표현식을 사용가능하게 했다.
Extended Literals
2진수와 8진수를 parseInt()함수의 도움없이 바로 사용할 수 있게끔 했다.
이로 인해서 Octal Error가 strict 모드에서 발생하게 되었는데 관련자료는 아래와 같다.
//es6
0b111110111 === 503
0o767 === 503
//es5
parseInt("111110111", 2) === 503;
parseInt("767", 8) === 503;
Enhanced Object Properties
객체에서 속성과 값이 같을 경우 줄여서 쓸 수 있다.
Property Shorthand
//es6
var x = 0, y = 0
obj = { x, y }
//es5
var x = 0, y = 0;
obj = { x: x, y: y };
또한 속성 이름을 객체 안에서 계산되어 정의될 수 있도록 하였다.(처음 보는 듯 하다.)
//es6
let obj = {
foo: "bar",
[ "baz" + quux() ]: 42
}
//es5
var obj = {
foo: "bar"
};
obj[ "baz" + quux() ] = 42;
일반 함수와 생성자 함수 모두 객체의 속성 정의 시 메서드 표기법을 지원하게 되었다.
obj = {
foo (a, b) {
…
},
bar (x, y) {
…
},
*quux (x, y) {
…
}
}
obj = {
foo: function (a, b) {
…
},
bar: function (x, y) {
…
},
// quux: no equivalent in ES5 => 생성자 함수가 ES5에는 없다.
…
};
Destructuring Assignment
유용한 구조분해할당 또한 es6에서 등장하게 되었는데
배열을 개별 변수로 직관적이고 유연하게 분해할 수 있게 도와준다.
Swapping variables 변수 교환 역시 하나의 구조 분해 할당 식에서 가능하게 되었다고 한다.
(구조분해할당이 없었으면 두값을 교환하기 위해 임시 변수가 필요했다고 한다.)
아래 예시를 보면 이해하기 쉬울 것이다.
Array Matching & Swapping variables
//es6
var list = [ 1, 2, 3 ]
var [ a, , b ] = list
[ b, a ] = [ a, b ]
console.log(a) // 3
console.log(b) // 1
//es5
var list = [ 1, 2, 3 ];
var a = list[0], b = list[2];
var tmp = a; a = b; b = tmp;
객체를 개별 변수로 직관적이고 유연하게 분해할 수 있게 도와준다.
Object Matching, Shorthand
//es6
var { op, lhs, rhs } = getASTNode()
//es5
var tmp = getASTNode();
var op = tmp.op;
var lhs = tmp.lhs;
var rhs = tmp.rhs;
//코드가 얼마나 짧아지는지 예시를 보면 알 수 있다.
중첩된 객체 또한 개별 변수로 직관적이고 유연하게 구조화가 가능하다.
Object Matching, Deep Matching
//es6
var { op: a , lhs: { op: b } , rhs: c } = getASTNode ( )
//es5
var tmp = getASTNode ( ) ;
변수 a = tmp . op ;
var b = tmp . 좌 . op ;
var c = tmp . rhs ;
구조분해할당에서도 기본값 설정이 가능하다.
Object and Array Matching, Default Values
//es6
var obj = { a: 1 }
var list = [ 1 ]
var { a, b = 2 } = obj
var [ x, y = 2 ] = list
//es5
var obj = { a: 1 };
var list = [ 1 ];
var a = obj.a;
var b = obj.b === undefined ? 2 : obj.b;
var x = list[0];
var y = list[1] === undefined ? 2 : list[1];
함수의 호출 중에 배열과 객체를 개별 매개변수로 직관적이고 유연하게 구조화 할 수 있다.
이 부분은 react에서 부모 component가 자식 component로 props를 넘겨줄때 자주 보았다.
Parameter Context Matching
//es6
function f ([ name, val ]) {
console.log(name, val)
}
function g ({ name: n, val: v }) {
console.log(n, v)
}
function h ({ name, val }) {
console.log(name, val)
}
f([ "bar", 42 ])
g({ name: "foo", val: 7 })
h({ name: "bar", val: 42 })
//es5
function f (arg) {
var name = arg[0];
var val = arg[1];
console.log(name, val);
};
function g (arg) {
var n = arg.name;
var v = arg.val;
console.log(n, v);
};
function h (arg) {
var name = arg.name;
var val = arg.val;
console.log(name, val);
};
f([ "bar", 42 ]);
g({ name: "foo", val: 7 });
h({ name: "bar", val: 42 });
선택적으로 기본값이 있는 Fail-soft 구조분해가 가능하다.
fail-soft가 무슨 말인가?
Destructuring is also fail-soft, meaning that values not found return undefined instead of an error
즉, value가 찾아지지 않을때 error대신에 undefined를 반환하는 것을 말한다.
그러고보니 fail-soft '연약한 실패' 용어를 만드는 자바스크립트 개발자들도 재밌다는 생각이 든다.
출처: https://www.benmvp.com/blog/learning-es6-destructuring/
//es6
var list = [ 7, 42 ]
var [ a = 1, b = 2, c = 3, d ] = list
a === 7
b === 42
c === 3
d === undefined
//list에 0번째, 1번째자리가 정해져있지 않으면 각각 a는 1, b는 2가된다는 말이고
//2번째 줄에서 2번째, 3번째에 해당하는 요소가 없기 때문에 c는 3으로 기본값이 정해지고,
//d의 경우는 3번째 줄에서도 정의되지 않았기에 undefined가 되는 것이다.
//fail-soft의 개념으로 다시 설명하자면 d의 경우 해당하는 값이 없기 때문에 error 대신 undefined를 반환하는 것이다.
//es5
var list = [ 7, 42 ];
var a = typeof list[0] !== "undefined" ? list[0] : 1;
var b = typeof list[1] !== "undefined" ? list[1] : 2;
var c = typeof list[2] !== "undefined" ? list[2] : 3;
var d = typeof list[3] !== "undefined" ? list[3] : undefined;
a === 7;
b === 42;
c === 3;
d === undefined;
Modules
namespace pollution없이 모듈에서 값 내보내기/가져오기를 지원한다.
(개인적으로는 전역 스코프에 선언되지 않아서 충돌의 위험이 없다라고 해석을 했습니다. )
namespace pollution이 무슨 말인가?
It means that something is misplaced. In programming that means that code that should really live in separate namespaces is added to a common namespace (in some cases the global namespace).
뭔가 잘못된 위치에 있는 것을 의미하며 별도의 네임스페이스에 있어야하는 코드가 공통 네임스페이스에 있는 것을 의미한다.
Basically, namespaces' main function is to categorize code, and both static and non static code must be defined in a namespace somewhere.
네임스페이스이 주요기능은 코드를 분류하는 것이며 어떤 코드(정적, 비정적 코드)든 네임스페이스 어딘가에 정의되어 있어야 한다.
출처: https://stackoverflow.com/questions/22903542/what-is-namespace-pollution
namespace란?
The namespace axis indicates all the nodes that are in scope for the context node. In this case, the context node must be an element node.
출처 : https://developer.mozilla.org/ko/docs/Web/XPath/Axes/namespace
즉, 종합하자면 JavaScript는 함수 오버로딩을 지원하지 않기에 동일한 이름을 가진 두 함수가 사용되면 함수가 로드되는 순서에 따라 한 함수가 다른 함수를 재정의 하게됩니다.(충돌) namespace pollution은 이러한 충돌의 원인이 되기에 전역 네임스페이스에 모든 것을 추가하지 않도록 주의해야한다라는 것.
(네임스페이스를 scope라고 이해하고 이를 바탕으로 모든 글들을 읽었습니다. 다른 분들은 어떻게 해석하실런지 궁금하네요! 아시면 댓글 부탁드립니다.)
namespace pollution에 대한 예시와 좋은 해결방법을 제시하는 reference :
https://www.tutorialspoint.com/how-to-avoid-namespace-pollution-in-javascript
//es6
// lib/math.js
export function sum (x, y) { return x + y }
export var pi = 3.141593
// someApp.js
import * as math from "lib/math"
console.log("2π = " + math.sum(math.pi, math.pi))
// otherApp.js
import { sum, pi } from "lib/math"
console.log("2π = " + sum(pi, pi))
//es5
// lib/math.js
LibMath = {};
LibMath.sum = function (x, y) { return x + y };
LibMath.pi = 3.141593;
// someApp.js
var math = LibMath;
console.log("2π = " + math.sum(math.pi, math.pi));
// otherApp.js
var sum = LibMath.sum, pi = LibMath.pi;
console.log("2π = " + sum(pi, pi));
기본으로 export되는 것을 표시할 수 있고 다른 값들을 혼합하여 표시 할 수 있다.
Default & Wildcard
//es6
// lib/mathplusplus.js
export * from "lib/math"
export var e = 2.71828182846
export default (x) => Math.exp(x)
// someApp.js
import exp, { pi, e } from "lib/mathplusplus"
console.log("e^{π} = " + exp(pi))
Classes
class를 통해 객체 정의하고 이 객체를 new 키워드를 통해 생성을 할 수 있게 되었다.
(ECMA에서 설명하기로는 객체지향스타일로 상용구 없이 class를 정의할 수 있게 되었다고 표현한다.)
//es6
class Shape {
constructor (id, x, y) {
this.id = id
this.move(x, y)
}
move (x, y) {
this.x = x
this.y = y
}
}
//es5
var Shape = function (id, x, y) {
this.id = id;
this.move(x, y);
};
Shape.prototype.move = function (x, y) {
this.x = x;
this.y = y;
};
extends, constructor, super를 통해 상용구 없이 객체의 속성과 메소드의 상속이 가능해 졌다.
참고로 mdn에서 extends, constructor, super는 아래와 같이 표현된다.
The extends keyword is used in class declarations or class expressions
to create a class as a child of another class.
The constructor method is a special method of a class for creating and initializing an object of that class.
The super keyword is used to access and call functions on an object's parent.
(this keyword를 쓰려면 반드시 contructor안에서 super가 사용되어야한다. )
예시는 아래와 같다.
//es6
class Rectangle extends Shape {
constructor (id, x, y, width, height) {
super(id, x, y)
this.width = width
this.height = height
}
}
class Circle extends Shape {
constructor (id, x, y, radius) {
super(id, x, y)
this.radius = radius
}
}
//es5
var Rectangle = function (id, x, y, width, height) {
Shape.call(this, id, x, y);
this.width = width;
this.height = height;
};
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;
var Circle = function (id, x, y, radius) {
Shape.call(this, id, x, y);
this.radius = radius;
};
Circle.prototype = Object.create(Shape.prototype);
Circle.prototype.constructor = Circle;
static 키워드는 클래스의 정적 메서드를 정의한다.
정적 메서드는 클래스의 인스턴스 없이 호출이 가능하며 클래스가 인스턴스화되면 호출할 수 없다.
출처: https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Classes/static
Static Members
//es6
class Rectangle extends Shape {
…
static defaultRectangle () {
return new Rectangle("default", 0, 0, 100, 100)
}
}
class Circle extends Shape {
…
static defaultCircle () {
return new Circle("default", 0, 0, 100)
}
}
var defRectangle = Rectangle.defaultRectangle()
var defCircle = Circle.defaultCircle()
Getter와 Setter가 원래는 prototype안에서만 사용이 가능했는데 이제는 class안에서도 직접적으로 사용할 수 있게 되었다.
여기서 getter와 setter를 알지 못하기에 짚고 넘어가려고 한다.
출처: https://ko.javascript.info/property-accessors
get은 인수가 없는 함수로, 프로퍼티를 읽을 때 동작하고
set은 인수가 하나인 함수로, 프로퍼티에 값을 쓸 때 호출된다. 값이 매개변수로 오게 되는데 예시를 보면 이해하기 쉽다.
let user = {
name: "John",
surname: "Smith",
get fullName() {
return `${this.name} ${this.surname}`;
}
};
alert(user.fullName); // John Smith
//get과 set을 접근자 프로퍼티(accessor property)라고 부르는데
//get으로 함수를 지정한 경우에는 객체 밖에서 일반 프로퍼티처럼 접근할 수 있게 된다.
//기 정의한 것 처럼 프로퍼티를 읽을 때 실행 된다.
let user = {
set fullName(value) {
[this.name, this.surname] = value.split(" ");
}
};
user.fullName = "Alice Cooper";
alert(user.name); // Alice
alert(user.surname); // Cooper
// set은 인수가 하나인 함수로, 프로퍼티에 값을 할당 할 때 호출된다.
Symbol Type
객체 속성의 식별자로 사용될 수 있는 고유하고 변경할 수 없는 데이터 형식(원시 데이터 형의 일종)이 추가되었다,
Symbol은 디버깅 목적으로만 사용된다.
Symbol("foo") !== Symbol("foo")
const foo = Symbol()
const bar = Symbol()
typeof foo === "symbol"
typeof bar === "symbol"
let obj = {}
obj[foo] = "foo"
obj[bar] = "bar"
JSON.stringify(obj) // {}
Object.keys(obj) // []
Object.getOwnPropertyNames(obj) // []
Object.getOwnPropertySymbols(obj) // [ foo, bar ]
위의 설명을 읽어도 이해가 안되고 왜 써야하는지 납득이 되지 않아서 조금 더 조사를 했다.
Symbol()로 호출 할 때마다 다른 모든 기호와 다른 새로운 고유한 기호를 얻게 된다고 한다.
Symbol()에 매개변수를 전달할 수 있고 Symbol()의 기호 설명으로 사용할 수 있다고한다.
Symbol은 객체의 key로 사용될 수 있다. 그러나 getOwnPropertynames, for in 같은 메소드로는 접근할 수 없고
getOwnPropertySymbols()를 통해서만 Symbol로 된 key에 접근할 수 있다.
다른 것과 같은 기호가 없이 때문에 종종 속성 간의 이름 충돌을 피하기 위해
혹은 사용자가 의도적으로든 인지하지 않고든 덮어쓸 수 없는 속성을 추가하기 위해 사용한다고 한다.
쉽게 말하자면 실수로(이미 있는 메서드를 인식하지 못하고 같은 이름의 메소드를 추가하는) 존재하는 객체의 key값이 변경될 수 있으므로 symbol을 통하여 유일한 값을 정의해 추가한다면 만약의 상황을 대비할 수 있는 것이다.
Iterators
객체에서 반복 동작을 사용자가 지정할 수 있도록 iterable 프로토콜을 지원한다. 또한 값 시퀀스(유한 또는 무한)를 생성하기 위해 iterator 프로토콜을 지원한다. 마지막으로, 반복 가능한 개체의 모든 값에 대해 반복할 수 있는 연산자를(for ~ of) 편리하게 제공한다.
iterable이란 반복 가능한 객체이고 Symbol.iterator 속성에 특별한 형태의 함수가 들어있다.
즉 객체의 Symbol.iterator속성에 특정 형태의 함수가 들어있으면,
이를 Iterable이라고 부르는 것이고 해당 객체는 iterable protocol을 만족한다고 말한다.
iterable 객체를 만들어내는 생성자에는 다음과 같은 종류가 있다.
- String
- Array
- TypedArray
- Map
- Set
어떤 객체가 iterable이면 for ~ of, spread연산자, 구조분해할당을 사용할 수 있다.
출처: https://helloworldjavascript.net/pages/260-iteration.html
Iterable protocol을 만족하려면, Symbol.iterator 속성에 저장되어 있는 함수는 iterator 객체를 반환해야 한다.
Iterator 객체는 다음과 같은 특징이 있다.
- Iterator는 next라는 메소드를 갖는다.
- next 메소드는 다음 두 속성을 갖는 객체를 반환한다.
- value : 현재 순서의 값을 나타냄
- done : 반복이 모두 끝났는지를 나타냄
위 조건을 iterator protocol이라고 한다.
출처: https://helloworldjavascript.net/pages/260-iteration.html
어떤 객체든 iterable protocol을 구현하기만 하면 iterable이 될 수 있고, 이 iterable을 만드는 방법에는 generator 함수를 이용하는 방법(Generators에서 소개)과 next메소드 안에서 return(done과 value)을 지정해주는 방법이 있다.
여기서는 generator가 아닌 next메소드 안에서 return을 지정해주는 방법으로 한번 예시를 들어보겠다.
//es6
let fibonacci = {
[Symbol.iterator]() {
let pre = 0, cur = 1
return {
next () {
[ pre, cur ] = [ cur, pre + cur ]
return { done: false, value: cur }
}
}
}
}
for (let n of fibonacci) {
if (n > 1000)
break
console.log(n)
}
Generators
위 Iterator를 다루면서 Iterable 객체를 위한 방법으로 Generator를 잠시 언급했었다.
Iterable을 생성하기 위해서는 Iterable protocol을 만족해야하고,
Iterable protocol을 만족하기 위해서는 객체의 Symbol.Iterator속성에 특별한 함수가 있어야 한다.
Generator 함수를 호출하면 객체가 생성되는데, 이 객체는 iterable protocol을 만족한다. 즉, Symbol.iterator 속성을 갖고 있다.
Generator 함수 안에서는 yield라는 특별한 키워드를 사용할 수 있다. Generator 함수 안에서 yield 키워드는 return과 유사한 역할을 하며, iterable의 기능을 사용할 때 yield 키워드 뒤에 있는 값들을 순서대로 넘겨준다.
출처: https://helloworldjavascript.net/pages/260-iteration.html
Map/Set
Map은 값들을 매핑하기 위한 새로운 데이터 구조로 간단한 키와 값을 서로 연결시켜 저장하며
저장된 순서대로 각 요소들을 반복적으로 접근할 수 있도록 한다.
for ~ of로 Map객체에 저장되어 있는 각 요소들을 [키, 값]형태의 배열로 반복적으로 반환해줄 수 있다.
var sayings = new Map();
sayings.set("dog", "woof");
sayings.set("cat", "meow");
sayings.set("elephant", "toot");
sayings.size; // 3
sayings.get("fox"); // undefined
sayings.has("bird"); // false
sayings.delete("dog");
for (var [key, value] of sayings) {
console.log(key + " goes " + value);
}
// "cat goes meow"
// "elephant goes toot"
Set은 수학에서의 집합과 같은 개념으로 중복되지 않는 요소들이 모이는 data-structure이다.
Set의 특징은 예시를 보면서 살펴보자.
let s = new Set()
s.add("hello").add("goodbye").add("hello")
s.size === 2 //동일한 값을 여러번 넣어도 값이 추가되지 않는다.(치환된다)
s.has("hello") === true //has로 고유값의 존재 여부를 확인이 가능하다.
for (let key of s.values()) // insertion order
console.log(key)
set은 고유값을 얻어야 할 때, 빠르게 Look up을 해야 할 때, 순서가 상관없을 때 사용해야 한다.
Typed Arrays
네트워크 프로토콜, 암호화 알고리즘, 파일 형식 조작 등을 구현하기 위한 임의의 바이트 기반 데이터 구조 지원
// ES6 class equivalent to the following C structure:
// struct Example { unsigned long id; char username[16]; float amountDue }
class Example {
constructor (buffer = new ArrayBuffer(24)) {
this.buffer = buffer
}
set buffer (buffer) {
this._buffer = buffer
this._id = new Uint32Array (this._buffer, 0, 1)
this._username = new Uint8Array (this._buffer, 4, 16)
this._amountDue = new Float32Array(this._buffer, 20, 1)
}
get buffer () { return this._buffer }
set id (v) { this._id[0] = v }
get id () { return this._id[0] }
set username (v) { this._username[0] = v }
get username () { return this._username[0] }
set amountDue (v) { this._amountDue[0] = v }
get amountDue () { return this._amountDue[0] }
}
let example = new Example()
example.id = 7
example.username = "John Doe"
example.amountDue = 42.0
New Built-In Methods
Object.assign(dest, src1, src2)
[ 1, 3, 4, 2 ].find(x => x > 3) // 4
[ 1, 3, 4, 2 ].findIndex(x => x > 3) // 2
"foo".repeat(3)
"hello".startsWith("ello", 1) // true
"hello".endsWith("hell", 4) // true
"hello".includes("ell") // true
Number.isNaN(NaN) === true
Number.isFinite(Infinity) === false
Number.isSafeInteger(42) === true
Number.isSafeInteger(9007199254740992) === false
console.log(0.1 + 0.2 === 0.3) // false ???
console.log(Math.abs((0.1 + 0.2) - 0.3) < Number.EPSILON) ???
Number.EPSILON 속성(property)은 Number 형으로 표현될 수 있는 1과 1보다 큰 값 중에서 가장 작은 값의, 차입니다.
출처: https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Number/EPSILON
console.log(Math.trunc(42.7)) // 42 정수 부분으로 자르고 소수 부분을 완전히 삭제
console.log(Math.trunc( 0.1)) // 0
console.log(Math.trunc(-0.1)) // -0
console.log(Math.sign(7)) // 1 어떤 수의 부호를 반환
console.log(Math.sign(0)) // 0
console.log(Math.sign(-0)) // -0
console.log(Math.sign(-7)) // -1
console.log(Math.sign(NaN)) // NaN
Promises
Promise는 프로미스가 생성될 때 꼭 알 수 있지는 않은 값을 위한 대리자로, 비동기 연산이 종료된 이후의 결과값이나 실패 이유를 처리하기 위한 처리기를 연결할 수 있도록 합니다. 프로미스를 사용하면 비동기 메서드에서 마치 동기 메서드처럼 값을 반환할 수 있습니다. 다만 최종 결과를 반환하지는 않고, 대신 프로미스를 반환해서 미래의 어떤 시점에 결과를 제공합니다.
출처: https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise
function msgAfterTimeout (msg, who, timeout) {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(`${msg} Hello ${who}!`), timeout)
})
}
msgAfterTimeout("", "Foo", 100).then((msg) =>
msgAfterTimeout(msg, "Bar", 200)
).then((msg) => {
console.log(`done after 300ms:${msg}`) // done after 300ms: Hello Foo! Hello Bar!
})
Promise.all(iterable)
iterable 내의 모든 프로미스가 이행한 뒤 이행하고, 어떤 프로미스가 거부하면 즉시 거부하는 프로미스를 반환합니다. 반환된 프로미스가 이행하는 경우 iterable 내의 프로미스가 결정한 값을 모은 배열이 이행 값입니다. 반환된 프로미스가 거부하는 경우 iterable 내의 거부한 프로미스의 이유를 그대로 사용합니다. 이 메서드는 여러 프로미스의 결과를 모을 때 유용합니다.
function fetchAsync (url, timeout, onData, onError) {
…
}
let fetchPromised = (url, timeout) => {
return new Promise((resolve, reject) => {
fetchAsync(url, timeout, resolve, reject)
})
}
Promise.all([
fetchPromised("http://backend/foo.txt", 500),
fetchPromised("http://backend/bar.txt", 500),
fetchPromised("http://backend/baz.txt", 500)
]).then((data) => {
let [ foo, bar, baz ] = data
console.log(`success: foo=${foo} bar=${bar} baz=${baz}`)
}, (err) => {
console.log(`error: ${err}`)
})
Meta-Programming
Proxy 객체는 기본적인 동작(속성 접근, 할당, 순회, 열거, 함수 호출 등)의 새로운 행동을 정의할 때 사용한다.
let target = {
foo: "Welcome, foo"
}
let proxy = new Proxy(target, {
get (receiver, name) {
console.log('receiver', receiver)
console.log('name', name)
return name in receiver ? receiver[name] : `Hello, ${name}`
}
})
proxy.foo === "Welcome, foo"
proxy.world === "Hello, world"
//receiver {foo: 'Welcome, foo'}
//name foo
//receiver {foo: 'Welcome, foo'}foo: "Welcome, foo"[[Prototype]]: Object
//name world
//true
proxy.foo === "Welcome, foo"
//true
proxy.world === "Hello, world"
//true
receiver의 경우 target 그 자체를 반환했고, name은 proxy 인스턴스의 속성을 반환했다.
Internationalization & Localization
Intl 객체는 각 언어에 맞는 문자비교, 숫자, 시간, 날짜비교를 제공하는, ECMAScript 국제화 API다.
Intl.Collator콜레이터 생성자. 콜레이터 객체는 각 언어에 맞는 문자열 비교를 가능하게 해준다.
// in German, "ä" sorts with "a"
// in Swedish, "ä" sorts after "z"
var list = [ "ä", "a", "z" ]
var l10nDE = new Intl.Collator("de")
var l10nSV = new Intl.Collator("sv")
l10nDE.compare("ä", "z") === -1
l10nSV.compare("ä", "z") === +1
console.log(list.sort(l10nDE.compare)) // [ "a", "ä", "z" ]
console.log(list.sort(l10nSV.compare)) // [ "a", "z", "ä" ]
Intl.DateTimeFormat각 언어에 맞는 시간과 날짜 서식을 적용할 수 있는 객체의 생성자.
var l10nEN = new Intl.DateTimeFormat("en-US")
var l10nDE = new Intl.DateTimeFormat("de-DE")
l10nEN.format(new Date("2015-01-02")) === "1/2/2015"
l10nDE.format(new Date("2015-01-02")) === "2.1.2015"
Intl.NumberFormat각 언어에 맞는 숫자 서식을 적용할 수 있는 객체의 생성자.
var l10nEN = new Intl.NumberFormat("en-US")
var l10nDE = new Intl.NumberFormat("de-DE")
l10nEN.format(1234567.89) === "1,234,567.89"
l10nDE.format(1234567.89) === "1.234.567,89"
var l10nUSD = new Intl.NumberFormat("en-US", { style: "currency", currency: "USD" })
var l10nGBP = new Intl.NumberFormat("en-GB", { style: "currency", currency: "GBP" })
var l10nEUR = new Intl.NumberFormat("de-DE", { style: "currency", currency: "EUR" })
l10nUSD.format(100200300.40) === "$100,200,300.40"
l10nGBP.format(100200300.40) === "£100,200,300.40"
l10nEUR.format(100200300.40) === "100.200.300,40 €"
출처: https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Intl
'JavaScript' 카테고리의 다른 글
Detail of prototype in Javascript (0) | 2021.10.06 |
---|---|
[번역] Introduction to Promises in JavaScript 자바스크립트에서의 promise 소개 (0) | 2021.09.18 |
[번역] prototypes in JavaScript 자바스크립트에서의 프로토타입 (0) | 2021.09.17 |
모든 자바스크립트 파일을 브라우저에서 한 번에 로딩 할 때의 문제점과 그 해결([번역]How to load JavaScript properly) (1) | 2021.09.13 |
[요약] What the heck is the event loop anyway? 이벤트 루프란 무엇인가? (0) | 2021.09.04 |