์ด๋…ธ๋ฒ ์ด์…˜์บ ํ”„/์ง€์‹์Œ“๊ธฐ

JavaScript์˜ ES๋ž€?, ES5/ES6 ๋ฌธ๋ฒ• ์ฐจ์ด

๐Ÿ๐Ÿ๋ฆผ 2022. 8. 12. 12:16

๐ŸŸจJavaScript


๐Ÿ”ป JavaScript์˜ ES๋ž€?

1996๋…„์— ECMA(European Computer Manufacturers Association) International์ด๋ผ๋Š” ํ‘œ์ค€ ์กฐ์ง์€ ๋ชจ๋“  โ€‹โ€‹๋ธŒ๋ผ์šฐ์ € ๊ณต๊ธ‰์—…์ฒด๊ฐ€ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋Š” ECMAScript(ES)๋ผ๋Š” ํ‘œ์ค€ ์‚ฌ์–‘์„ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  Javascript๋Š” ES์˜ ๊ฐ€์žฅ ์ž˜ ์•Œ๋ ค์ง„ ๊ตฌํ˜„์ด๋ฉฐ ActionScript(Macromedia/Adobe Systems)์™€ JScript(Microsoft)๋Š” ES์˜ ๋‹ค๋ฅธ ๊ตฌํ˜„์ž…๋‹ˆ๋‹ค.

ES์˜ ๋ฒ„์ „ ๋ชฉ๋ก:

ํ˜„์žฌ๊นŒ์ง€ ES๋Š” 9๊ฐœ์˜ ๋ฒ„์ „์„ ์ถœํŒํ–ˆ์œผ๋ฉฐ ์ตœ์‹  ๋ฒ„์ „(9๋ฒˆ์งธ ๋ฒ„์ „)์€ 2018๋…„์— ์ถœํŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

  • ES1 1997
  • ES2 1998
  • ES3 1999
  • ES4 ํฌ๊ธฐ
  • ES5 2009
  • ES6 2015
  • ES7 2016
  • ES8 2017
  • ES9 2018

ECMA Script์˜ ์ฒ˜์Œ ์„ธ ๊ฐ€์ง€ ๋ฒ„์ „(ES1, ES2, ES3)์€ ๋งค๋…„ ์—…๋ฐ์ดํŠธ๋˜๋Š” ๋ฐ˜๋ฉด, ES4๋Š” ์ •์น˜์  ๋ถˆ์ผ์น˜๋กœ ์ธํ•ด ์ถœ์‹œ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. 10๋…„ ํ›„, ES5๋Š” ๊ฒฐ๊ตญ ๋ช‡ ๊ฐ€์ง€ ์ถ”๊ฐ€ ๊ธฐ๋Šฅ๊ณผ ํ•จ๊ป˜ ์ถœ์‹œ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.


๐Ÿ”ปES5/ES6 ๋ฌธ๋ฒ• ์ฐจ์ด

ECMAScript 5(ES5P) ECMAScript 6(ES6)
ECMA ์Šคํฌ๋ฆฝํŠธ๋Š” Ecma International์—์„œ ์ •์˜ํ•œ ์ƒํ‘œ ๋“ฑ๋ก๋œ ์Šคํฌ๋ฆฝํŒ… ์–ธ์–ด ์‚ฌ์–‘์ž…๋‹ˆ๋‹ค. ๊ฐ™์€ ๊ฒƒ์˜ ๋‹ค์„ฏ ๋ฒˆ์งธ ํŒ์€ ES5๋กœ ์•Œ๋ ค์ ธ ์žˆ์Šต๋‹ˆ๋‹ค. ECMA ์Šคํฌ๋ฆฝํŠธ๋Š” Ecma International์—์„œ ์ •์˜ํ•œ ์ƒํ‘œ ๋“ฑ๋ก๋œ ์Šคํฌ๋ฆฝํŒ… ์–ธ์–ด ์‚ฌ์–‘์ž…๋‹ˆ๋‹ค. ๊ฐ™์€ ๊ฒƒ์˜ ์—ฌ์„ฏ ๋ฒˆ์งธ ํŒ์€ ES6์œผ๋กœ ์•Œ๋ ค์ ธ ์žˆ์Šต๋‹ˆ๋‹ค. 
2009๋…„์— ๋„์ž…๋˜์—ˆ์Šต๋‹ˆ๋‹ค. 2015๋…„์— ๋„์ž…๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
๋ฌธ์ž์—ด, ์ˆซ์ž, ๋ถ€์šธ, null ๋ฐ ์ •์˜๋˜์ง€ ์•Š์€ ๊ธฐ๋ณธ ๋ฐ์ดํ„ฐ ์œ ํ˜•์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.  ES6์—๋Š” JavaScript ๋ฐ์ดํ„ฐ ์œ ํ˜•์— ๋ช‡ ๊ฐ€์ง€ ์ถ”๊ฐ€ ์‚ฌํ•ญ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๊ณ ์œ  ๊ฐ’์„ ์ง€์›ํ•˜๊ธฐ ์œ„ํ•ด ์ƒˆ๋กœ์šด ๊ธฐ๋ณธ ๋ฐ์ดํ„ฐ ์œ ํ˜• '๊ธฐํ˜ธ'๋ฅผ ๋„์ž…ํ–ˆ์Šต๋‹ˆ๋‹ค.
var ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ณ€์ˆ˜๋ฅผ ์ •์˜ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ํ•œ ๊ฐ€์ง€๋ฟ์ž…๋‹ˆ๋‹ค. let ๋ฐ const ๋ณ€์ˆ˜๋ฅผ ์ •์˜ํ•˜๋Š” ๋‘ ๊ฐ€์ง€ ์ƒˆ๋กœ์šด ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค.
ES6์— ๋น„ํ•ด ์„ฑ๋Šฅ์ด ๋‚ฎ์Šต๋‹ˆ๋‹ค. ES5๋ณด๋‹ค ์„ฑ๋Šฅ์ด ๋†’์Šต๋‹ˆ๋‹ค.
๊ฐ์ฒด ์กฐ์ž‘์€ ES5์—์„œ ์‹œ๊ฐ„์ด ๋งŽ์ด ๊ฑธ๋ฆฝ๋‹ˆ๋‹ค. ๊ฐ์ฒด ์กฐ์ž‘์€ ES6์—์„œ ์‹œ๊ฐ„์ด ๋œ ๊ฑธ๋ฆฝ๋‹ˆ๋‹ค.
ES5์—์„œ function ๋ฐ return ํ‚ค์›Œ๋“œ๋Š” ๋ชจ๋‘ ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ํ™”์‚ดํ‘œ ํ•จ์ˆ˜๋Š” ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ•˜๊ธฐ ์œ„ํ•ด function ํ‚ค์›Œ๋“œ๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์€ ES6์— ๋„์ž…๋œ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค.
ES6๋ณด๋‹ค ๋” ๋„“์€ ๋ฒ”์œ„์˜ ์ปค๋ฎค๋‹ˆํ‹ฐ ์ง€์›์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ES5๋ณด๋‹ค ์ ์€ ๋ฒ”์œ„์˜ ์ปค๋ฎค๋‹ˆํ‹ฐ ์ง€์›์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

ECMAScript 6 ์— ์ถ”๊ฐ€๋œ ๊ธฐ๋Šฅ

Arrows

Arrows(ํ™”์‚ดํ‘œ) ํ•จ์ˆ˜๋Š” => ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•˜๋Š” ์ถ•์•ฝํ˜• ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. C#, Java 8, CoffeeScript์˜ ํ•ด๋‹น ๊ธฐ๋Šฅ๊ณผ ๋ฌธ๋ฒ•์ ์œผ๋กœ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค. Arrows๋Š” ํ‘œํ˜„์‹์˜ ๊ฒฐ๊ณผ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ‘œํ˜„์‹ ๋ณธ๋ฌธ(expression bodies)๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์ƒํƒœ ๋ธ”๋Ÿญ ๋ณธ๋ฌธ(statement block bodies)๋„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ผ๋ฐ˜ ํ•จ์ˆ˜์˜ ์ž์‹ ์„ ํ˜ธ์ถœํ•˜๋Š” ๊ฐ์ฒด๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” dynamic this์™€ ๋‹ฌ๋ฆฌ arrows ํ•จ์ˆ˜๋Š” ์ฝ”๋“œ์˜ ์ƒ์œ„ ์Šค์ฝ”ํ”„(lexical scope)๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” lexical this๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค.

var evens = [2, 4, 6, 8,];

// Expression bodies (ํ‘œํ˜„์‹์˜ ๊ฒฐ๊ณผ๊ฐ€ ๋ฐ˜ํ™˜๋จ)
var odds = evens.map(v => v + 1);   // [3, 5, 7, 9]
var nums = evens.map((v, i) => v + i);  // [2, 5, 8, 11]
var pairs = evens.map(v => ({even: v, odd: v + 1})); // [{even: 2, odd: 3}, ...]

// Statement bodies (๋ธ”๋Ÿญ ๋‚ด๋ถ€๋ฅผ ์‹คํ–‰๋งŒ ํ•จ, ๋ฐ˜ํ™˜์„ ์œ„ํ•ด์„  return์„ ๋ช…์‹œ)
nums.forEach(v => {
  if (v % 5 === 0)
    fives.push(v);
});

// Lexical this
// ์ถœ๋ ฅ๊ฒฐ๊ณผ : Bob knows John, Brian
var bob = {
  _name: "Bob",
  _friends: ["John, Brian"],
  printFriends() {
    this._friends.forEach(f =>
      console.log(this._name + " knows " + f));
  }
}

printFriends() ํ•จ์ˆ˜์˜ ์„œ๋ธŒ๋ฃจํ‹ด์€ ๋‹ค์Œ๊ณผ ๋ฌธ๋ฒ•์ƒ ๋™์ผํ•˜๊ฒŒ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

this._friends.forEach(function (f) {
    console.log(this._name + " knows " + f));
}.bind(this));

 

Classes

ES6 ํด๋ž˜์Šค๋Š” ํฌ๋กœํ† ํƒ€์ž… ๊ธฐ๋ฐ˜ ๊ฐ์ฒด์ง€ํ–ฅ ํŒจํ„ด์„ ๋” ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋Œ€์ฒด์žฌ์ž…๋‹ˆ๋‹ค. ํด๋ž˜์Šค ํŒจํ„ด ์ƒ์„ฑ์„ ๋” ์‰ฝ๊ณ  ๋‹จ์ˆœํ•˜๊ฒŒ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์–ด์„œ ์‚ฌ์šฉํ•˜๊ธฐ๋„ ํŽธํ•˜๊ณ  ์ƒํ˜ธ์šด์šฉ์„ฑ๋„ ์ฆ๊ฐ€๋ฉ๋‹ˆ๋‹ค.

class SkinnedMesh extends THREE.Mesh {
  constructor(geometry, materials) {
    super(geometry, materials);

    this.idMatrix = SkinnedMesh.defaultMatrix();
    this.bones = [];
    this.boneMatrices = [];
    //...
  }
  update(camera) {
    //...
    super.update();
  }
  get boneCount() {
    return this.bones.length;
  }
  set matrixType(matrixType) {
    this.idMatrix = SkinnedMesh[matrixType]();
  }
  static defaultMatrix() {
    return new THREE.Matrix4();
  }
}

 

Enhanced Object Literals

ES6์—์„œ ๊ฐ์ฒด ๋ฆฌํ„ฐ๋Ÿด์€ ์„ ์–ธ๋ฌธ์—์„œ ํ”„๋กœํ† ํƒ€์ž… ์„ค์ •, foo: foo ์„ ์–ธ์„ ์œ„ํ•œ ๋‹จ์ถ• ํ‘œ๊ธฐ๋ฒ•, ๋ฉ”์„œ๋“œ ์ •์˜, super ํด๋ž˜์Šค ํ˜ธ์ถœ ๋ฐ ๋™์  ์†์„ฑ๋ช…์„ ์ง€์›ํ•˜๋„๋ก ํ–ฅ์ƒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ์— ๋”ฐ๋ผ ๊ฐ์ฒด ๋ฆฌํ„ฐ๋Ÿด ๋ฐ ํด๋ž˜์Šค ์„ ์–ธ์ด ๋” ๋ฐ€์ ‘๋˜์–ด์ ธ, ๊ฐ์ฒด๊ธฐ๋ฐ˜ ์„ค๊ณ„๊ฐ€ ๋” ํŽธ๋ฆฌํ•ด์กŒ์Šต๋‹ˆ๋‹ค.

var obj = {
    // __proto__
    __proto__: theProtoObj,

    // ‘handler: handler’์˜ ๋‹จ์ถ• ํ‘œ๊ธฐ
    handler,

    // Methods
    toString() {
     // Super calls
     return "d " + super.toString();
    },

    // Computed (dynamic) property names
    [ 'prop_' + (() => 42)() ]: 42
};

 

Template Strings

Template Strings(ES6 ๋ถ€ํ„ฐ๋Š” Template literals๋ผ ๋ถ€๋ฆ„)๋Š” ๋ฌธ๋ฒ•์ ์œผ๋กœ ๋” ํŽธํ•˜๊ฒŒ string์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” Perl, Python ๋“ฑ์˜ ๋ฌธ์ž์—ด ๋ณด๊ฐ„(string interpolation)๊ณผ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค. Tagged template literals๋Š” ์ธ์ ์…˜ ๊ณต๊ฒฉ ๋ฐฉ์–ด ํ˜น์€ ๋ฌธ์ž์—ด๋กœ ๋ถ€ํ„ฐ ์ƒ์œ„ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ์ฒด ์žฌ์กฐ๋ฆฝ ๋“ฑ์„ ์œ„ํ•ด string ์ƒ์„ฑ์„ ์ปค์Šคํ„ฐ๋งˆ์ด์ง•์ด ๊ฐ€๋Šฅํ•˜๊ฒŒ๋” ํ•ด์ค๋‹ˆ๋‹ค.

// Basic literal string creation
`In JavaScript '\n' is a line-feed.`

// Multiline strings
`In JavaScript this is
 not legal.`

// String interpolation
var name = "Bob", time = "today";
`Hello ${name}, how are you ${time}?`

// Construct an HTTP request prefix is used to interpret the replacements and construction
POST`http://foo.org/bar?a=${a}&b=${b}
     Content-Type: application/json
     X-Credentials: ${credentials}
     { "foo": ${foo},
       "bar": ${bar}}`(myOnReadyStateChangeHandler);

 

Destructuring

Destructuring๋Š” ๋ฐฐ์—ด๊ณผ ๊ฐ์ฒด์— ํŒจํ„ด ๋งค์นญ์„ ํ†ตํ•œ ๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. Destructuring๋Š” ํ• ๋‹น ์‹คํŒจ์— ์œ ์—ฐํ•˜๋ฉฐ, ์‹คํŒจ ์‹œ undefined ๊ฐ’์ด ์ž๋™ํ• ๋‹น ๋ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ foo["bar"]์™€ ๊ฐ™์ด ๊ฐ์ฒด์˜ ์†์„ฑ ๊ฐ’๋„ ์ž๋™์œผ๋กœ ๊ฒ€์ƒ‰ํ•˜์—ฌ ๋ฐ”์ธ๋”ฉํ•ด์ค๋‹ˆ๋‹ค.

// list matching
var [a, , b] = [1,2,3];

// object matching
var { op: a, lhs: { op: b }, rhs: c }
       = getASTNode()

// object matching ๋‹จ์ถ• ํ‘œ๊ธฐ
// binds `op`, `lhs` and `rhs` in scope
var {op, lhs, rhs} = getASTNode()

// parameter์—์„œ๋„ ์‚ฌ์šฉ ๊ฐ€๋Šฅ
function g({name: x}) {
  console.log(x);
}
g({name: 5})

// Fail-soft destructuring
var [a] = [];
a === undefined;

// Fail-soft destructuring with defaults
var [a = 1] = [];
a === 1;

 

Default + Rest + Spread

ํŒŒ๋ผ๋ฏธํ„ฐ์— ๊ธฐ๋ณธ ๊ฐ’์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

function f(x, y=12) {
  // y is 12 if not passed (or passed as undefined)
  return x + y;
}
f(3) // 15

๊ฐ€๋ณ€์ธ์ž๋ฅผ ์‚ฌ์šฉ๊ฐ€๋Šฅํ•˜๋ฉฐ, ๋ฐฐ์—ด๋กœ ์น˜ํ™˜์‹œ์ผœ ์ค๋‹ˆ๋‹ค. Rest parameters๋Š” arguments ๋ณด๋‹ค ์ง๊ด€์„ฑ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

function f(x, ...y) {
  // y is an Array ["hello", true]
  return x * y.length;
}
f(3, "hello", true) // 6

ํ•จ์ˆ˜ ํ˜ธ์ถœ ์‹œ ๋ฐฐ์—ด์„ ์ผ๋ จ์˜ ์ธ์ž์— ๋‚˜๋ˆ„์–ด ์ฃผ์ž…์‹œ์ผœ ์ค๋‹ˆ๋‹ค.

function f(x, y, z) {
  return x + y + z;
}
// Pass each elem of array as argument
f(...[1,2,3]) // 6

 

Let + Const

๋ธ”๋ก ์œ ํšจ ๋ฒ”์œ„๋ฅผ ๊ฐ–๋Š” ์ƒˆ๋กœ์šด ๋ณ€์ˆ˜ ์„ ์–ธ ๋ฐฉ๋ฒ•์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. let์€ var์™€ ์œ ์‚ฌํ•˜๊ฒŒ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค. const๋Š” ์žฌํ• ๋‹น ๋ฐ ์žฌ์„ ์–ธ์ด ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

function f() {
  {
    let x;
    {
      // okay, block scoped name
      const x = "sneaky";
      // error, const
      x = "foo";
    }
    // error, already declared in block
    let x = "inner";
  }
}

var์˜ ์œ ํšจ ๋ฒ”์œ„๋Š” ์ „์ฒด ์™ธ๋ถ€ ํ•จ์ˆ˜๊นŒ์ง€์ด์ง€๋งŒ let์€ ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•œ ๋ธ”๋ก๊ณผ ๊ทธ ๋‚ด๋ถ€ ๋ธ”๋ก๋“ค์—์„œ ์œ ํšจํ•ฉ๋‹ˆ๋‹ค.

function varTest() {
    var x = 31;
    if (true) {
        var x = 71;  // same variable!
        console.log(x);  // 71
    }
    console.log(x);  // 71
}

function letTest() {
    let x = 31;
    if (true) {
        let x = 71;  // different variable
        console.log(x);  // 71
    }
    console.log(x);  // 31
}
function varTest() {
    if (true) {
        var x = 71;
        console.log(x);  // 71
    }
    console.log(x);  // 71
}

function varTest() {
    let x = 71;
    if (true) {
        console.log(x);  // 71
    }
    console.log(x);  // 71
}

function varTest() {
    if (true) {
        let x = 71;
        console.log(x);  // 71
    }
    console.log(x);  // Uncaught ReferenceError: x is not defined
}

 

Iterators + For…Of

Iterator ๊ฐ์ฒด๋Š” CLR์˜ IEnumerable ํ˜น์€ Java์˜ Iterable์ฒ˜๋Ÿผ ์‚ฌ์šฉ์ž ์ •์˜์˜ ๋ฐ˜๋ณต์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค. for..of ๋ฐ˜๋ณต๋ฌธ์ด ES6์—์„œ ์ถ”๊ฐ€ ๋˜์—ˆ์œผ๋ฉฐ for..in ๋ฐ˜๋ณต๋ฌธ๊ณผ ๋‹ฌ๋ฆฌ iterator ๊ธฐ๋ฐ˜์˜ ์ปฌ๋ ‰์…˜ ์ „์šฉ ๋ฐ˜๋ณต๋ฌธ์ž…๋‹ˆ๋‹ค. for in ๋ฐ˜๋ณต๋ฌธ๊ณผ์˜ ์ฐจ์ด์ ์€ for in vs for of 503๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

let fibonacci = {
    [Symbol.iterator]() {
        let pre = 0, cur = 1;

        return {
            next() {
                [pre, cur] = [cur, pre + cur];
                return { done: false, value: cur }
            }
        }
    }
}

for (var n of fibonacci) {
    // truncate the sequence at 1000
    if (n > 1000)
        break;
    console.log(n); // 1, 2, 3, 5, 8, ...987
}

Iteration์€ ์•„๋ž˜์˜ duck-type ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•ฉ๋‹ˆ๋‹ค.

interface IteratorResult {
    done: boolean;
    value: any;
}
interface Iterator {
    next(): IteratorResult;
}
interface Iterable {
    [Symbol.iterator](): Iterator
}

 

Generators

Generators๋Š” function*์™€ yield ํ‚ค์›Œ๋“œ๋ฅผ ์ด์šฉํ•˜์—ฌ iterator ์„ ์–ธ์„ ๋‹จ์ˆœํ•˜๊ฒŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋„์™€์ค๋‹ˆ๋‹ค. function*๋กœ ์„ ์–ธํ•œ ํ•จ์ˆ˜๋Š” Generator ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. Generators๋Š” iterator์˜ ํ•˜์œ„ ํƒ€์ž…์ด๋ฉฐ next์™€ throw ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ฉ”์„œ๋“œ๋“ค๋กœ ์ธํ•ด yield ํ‚ค์›Œ๋“œ๋กœ ๋ฐ˜ํ™˜๋œ ๊ฐ’์€ ๋‹ค์‹œ generator์— ์ฃผ์ž…๊ฑฐ๋‚˜ ์˜ˆ์™ธ์ฒ˜๋ฆฌ๋ฅผ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์ฐธ๊ณ : ํ•ด๋‹น ํ‚ค์›Œ๋“œ๋Š” ๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ‘await’ ๊ฐ™์€ ๊ธฐ๋Šฅ์ด ๊ฐ€๋Šฅํ•˜๊ฒŒ๋” ๊ธฐ๋ฐ˜์ด ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ES7์˜ await ์ œ์•ˆ์„œ 67๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

var fibonacci = {
    [Symbol.iterator]: function*() {
        var pre = 0, cur = 1;
        for (;;) {
            [pre, cur] = [cur, pre + cur];
            yield cur;
        }
    }
}

for (var n of fibonacci) {
    // truncate the sequence at 20
    if (n > 20)
        break;
    console.log(n); // 1, 2, 3, 5, 8, 13
}
function* gen(){
  yield* ["a", "b", "c"];
}

var a = gen();

a.next(); // { value: "a", done: false }
a.next(); // { value: "b", done: false }
a.next(); // { value: "c", done: false }
a.next(); // { value: undefined, done: true }

generator ์ธํ„ฐํŽ˜์ด์Šค๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. 

interface Generator extends Iterator {
    next(value?: any): IteratorResult;
    throw(exception: any);
}

 

Unicode

์™„์ „ํ•œ ์œ ๋‹ˆ์ฝ”๋“œ๋ฅผ ์ง€์›ํ•˜๊ธฐ ์œ„ํ•ด ๋ฌธ์ž์—ด์— ์ƒˆ๋กœ์šด ์œ ๋‹ˆ์ฝ”๋“œ ๋ฆฌํ„ฐ๋Ÿด๊ณผ ์ •๊ทœํ‘œํ˜„์‹์— u ๋ชจ๋“œ๊ฐ€ ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ 21๋น„ํŠธ ํ˜•์‹๊นŒ์ง€ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ์‹ ๊ทœ API๊ฐ€ ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด ์ถ”๊ฐ€๋œ ๊ธฐ๋Šฅ์€ JavaScript๋กœ ๊ธ€๋กœ๋ฒŒ ์•ฑ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋„๋ก ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

// same as ES5.1
"๐ ฎท".length == 2

// new RegExp behaviour, opt-in ‘u’
"๐ ฎท".match(/./u)[0].length == 2

// new form
"\u{20BB7}" == "๐ ฎท"  == "\uD842\uDFB7"

// new String ops
"๐ ฎท".codePointAt(0) == 0x20BB7

// for-of iterates code points
for(var c of "๐ ฎท") {
    console.log(c); // ๐ ฎท
}

 

Modules

์–ธ์–ด ์ฐจ์›์—์„œ ์ปดํฌ๋„ŒํŠธ ์ •์˜๋ฅผ ์œ„ํ•œ ๋ชจ๋“ˆ์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ์œ ๋ช…ํ•œ JavaScript ๋ชจ๋“ˆ ๋กœ๋”๋“ค(AMD, CommonJS)์˜ ํŒจํ„ด์„ ์ ์šฉ์‹œ์ผฐ์Šต๋‹ˆ๋‹ค. ๋Ÿฐํƒ€์ž„ ๋™์ž‘์€ ํ˜ธ์ŠคํŠธ์— ์ •์˜๋œ ๊ธฐ๋ณธ ๋กœ๋”์— ์˜ํ•ด ์ •์˜๋ฉ๋‹ˆ๋‹ค. ๋ฌต์‹œ์  ๋น„๋™๊ธฐ ํ˜•ํƒœ๋กœ ์š”๊ตฌ๋˜๋Š” ๋ชจ๋“ˆ๋“ค์ด ์ •์ƒ์ ์œผ๋กœ ๋กœ๋“œ๋˜๊ธฐ ์ „๊นŒ์ง€ ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

// lib/math.js
export function sum(x, y) {
    return x + y;
}
export var pi = 3.141593;
// app.js
import * as math from "lib/math";
console.log("2π = " + math.sum(math.pi, math.pi)); // 2π = 6.283186
// otherApp.js
import {sum, pi} from "lib/math";
console.log("2π = " + sum(pi, pi)); // 2π = 6.283186

export default์™€ export * ๋ฌธ๋ฒ•๋„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

// lib/mathplusplus.js
export * from "lib/math";
export var e = 2.71828182846;
export default function(x) {
    return Math.log(x);
}
// app.js
import ln, {pi, e} from "lib/mathplusplus";
console.log("2π = " + ln(e)*pi*2);

 

Module Loaders

Module Loaders๋Š” ๋‹ค์Œ์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

  • ๋™์  ๋กœ๋”(Dynamic loading)
  • ์ƒํƒœ ๊ฒฉ๋ฆฌ(State isolation)
  • ์ „์—ญ ๋„ค์ž„์ŠคํŽ˜์ด์Šค ๊ฒฉ๋ฆฌ(Global namespace isolation)
  • ์ปดํŒŒ์ผ ํ›…(Compilation hooks)
  • ์ค‘์ฒฉ ๊ฐ€์ƒํ™”(Nested virtualization)

๊ธฐ๋ณธ์œผ๋กœ ์‚ฌ์šฉํ•  ๋ชจ๋“ˆ ๋กœ๋”๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๋กœ๋”๋ฅผ ์ƒˆ๋กœ ์ƒ์„ฑํ•˜์—ฌ ๊ฒฉ๋ฆฌ๋˜๊ฑฐ๋‚˜ ์ œํ•œ๋œ ๋งฅ๋ฝ์—์„œ ์ฝ”๋“œ๋ฅผ ๋กœ๋“œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

// ๋™์  ๋กœ๋”ฉ – ‘System’ is default loader
System.import('lib/math').then(function(m) {
    console.log("2π = " + m.sum(m.pi, m.pi));
});

// ์‹คํ–‰ ์ƒŒ๋“œ๋ฐ•์Šค ์ƒ์„ฑ – new Loaders
var loader = new Loader({
    global: fixup(window) // replace ‘console.log’
});
loader.eval("console.log('hello world!');");

// ๋ชจ๋“ˆ ์บ์‹œ ์ง์ ‘ ์กฐ์ž‘
System.get('jquery');
System.set('jquery', Module({$: $})); // WARNING: not yet finalized

Map + Set + WeakMap + WeakSet

์ผ๋ฐ˜ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์œ„ํ•œ ํšจ์œจ์ ์ธ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. WeakMap๊ณผ WeakSet๋Š” ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜๋กœ ๋ถ€ํ„ฐ ์ž์œ ๋กญ๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค. ์ด๋“ค ๋‚ด ์ €์žฅ๋œ ๊ฐ์ฒด์— ๋‹ค๋ฅธ ์ฐธ์กฐ๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ, garbage collection ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

// Sets
var s = new Set();
s.add("hello").add("goodbye").add("hello");
s.size === 2;
s.has("hello") === true;

// Maps
var m = new Map();
m.set("hello", 42);
m.set(s, 34);
m.get(s) == 34;

// Weak Maps
var wm = new WeakMap();
wm.set(s, { extra: 42 });
wm.size // undefined (์‚ฌ์šฉ๋œ ๊ณณ์ด ์—†๊ธฐ ๋•Œ๋ฌธ)

// Weak Sets
var ws = new WeakSet();
ws.add({ data: 42 });
wm.size // undefined (์‚ฌ์šฉ๋œ ๊ณณ์ด ์—†๊ธฐ ๋•Œ๋ฌธ)

 

Proxies

ํ”„๋ก์‹œ(Proxy)๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ˜ธ์ŠคํŠธ ๊ฐ์ฒด์— ๋‹ค์–‘ํ•œ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜์—ฌ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. interception, ๊ฐ์ฒด ์ถ”์ƒํ™”, ๋กœ๊น…/์ˆ˜์ง‘, ๊ฐ’ ๊ฒ€์ฆ ๋“ฑ์— ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

// Proxying a normal object
var target = {};
var handler = {
  get: function (receiver, name) {
    return `Hello, ${name}!`;
  }
};

var p = new Proxy(target, handler);
p.world // 'Hello, world!';
// Proxying a function object
var target = function () { return 'I am the target'; };
var handler = {
  apply: function (receiver, ...args) {
    return 'I am the proxy';
  }
};

var p = new Proxy(target, handler);
p() // 'I am the proxy';
let validator = {
    set: function(obj, prop, value) {
        if (prop === 'age') {
            if (!Number.isInteger(value)) {
                throw new TypeError('The age is not an integer');
            }
            if (value > 200) {
                throw new RangeError('The age seems invalid');
            }
        }

        // The default behavior to store the value 
        obj[prop] = value;
    }
};

let person = new Proxy({}, validator);

person.age = 100;
console.log(person.age); // 100
person.age = 'young'; // Throws an exception
person.age = 300; // Throws an exception

proxy์˜ handler๊ฐ€ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋Š” ํŠธ๋žฉ(trap)๋“ค์ž…๋‹ˆ๋‹ค.

var handler =
{
  get:...,
  set:...,
  has:...,
  deleteProperty:...,
  apply:...,
  construct:...,
  getOwnPropertyDescriptor:...,
  defineProperty:...,
  getPrototypeOf:...,
  setPrototypeOf:...,
  enumerate:...,
  ownKeys:...,
  preventExtensions:...,
  isExtensible:...
}

 

Symbols

์‹ฌ๋ณผ(Symbol)์€ ๊ฐ์ฒด ์ƒํƒœ์˜ ์ ‘๊ทผ ์ œ์–ด๋ฅผ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค. Symbol์€ ์ƒˆ๋กœ์šด ์›์‹œ ํƒ€์ž…์œผ๋กœ ์ด๋ฆ„ ์ถฉ๋Œ์˜ ์œ„ํ—˜ ์—†์ด ์†์„ฑ(property)์˜ ํ‚ค(key)๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ต์…˜ ํŒŒ๋ผ๋ฏธํ„ฐ์ธ description๋Š” ๋””๋ฒ„๊น… ์šฉ๋„๋กœ ์‚ฌ์šฉ๋˜๋ฉฐ ์‹๋ณ„ ์šฉ๋„๋Š” ์•„๋‹™๋‹ˆ๋‹ค. Symbol์€ ๊ณ ์œ (unique)ํ•˜๋ฉฐ, Object.getOwnPropertySymbols์™€ ๊ฐ™์€ reflection ๊ธฐ๋Šฅ๋“ค๋กœ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— private ํ•˜์ง„ ์•Š์Šต๋‹ˆ๋‹ค(for in๋‚˜ Object.keys()๋กœ๋Š” ์ ‘๊ทผ ๋ถˆ๊ฐ€).

var map = {};
var a = Symbol('a');

map[a] = 123;
map["b"] = 456;

console.log(map[a]); // 123
console.log(map["b"]); // 456

for (let key in map) {
    console.log(key); // b
}

Object.keys(map); // ["b"]

 

Subclassable Built-ins

ES6์—์„œ Array, Date, DOM Element ๊ฐ™์ด ๋‚ด์žฅ ๊ฐ์ฒด๋“ค์€ ์ƒ์†์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ๊ฐ์ฒด ์ƒ์„ฑ ์‹œ ํ˜ธ์ถœ๋˜๋Š” Ctor ํ•จ์ˆ˜๋Š” ๋‹ค์Œ์˜ 2๋‹จ๊ณ„๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค.(๋‘˜๋‹ค ๊ฐ€์ƒ์ ์œผ๋กœ ์‹คํ–‰)

  • ๊ฐ์ฒด ํ• ๋‹น์„ ์œ„ํ•ด Ctor[@@create] ํ˜ธ์ถœํ•˜์—ฌ
  • ์ƒˆ๋กœ์šด ์ธ์Šคํ„ด์Šค์˜ ์ƒ์„ฑ์ž๋ฅผ ํ˜ธ์ถœํ•ด ์ดˆ๊ธฐํ™” ์ง„ํ–‰

์•„์‹œ๋‹ค์‹ถ์ด @@create ์‹ฌ๋ณผ์€ Symbol.create๋ฅผ ํ†ตํ•ด ๋งŒ๋“ค์–ด์กŒ์Šต๋‹ˆ๋‹ค.

// Pseudo-code of Array
class Array {
    constructor(...args) { /* ... */ }
    static [Symbol.create]() {
        // Install special [[DefineOwnProperty]]
        // to magically update 'length'
    }
}

// User code of Array subclass
class MyArray extends Array {
    constructor(...args) { super(...args); }
}

// Two-phase 'new':
// 1) Call @@create to allocate object
// 2) Invoke constructor on new instance
var arr = new MyArray();
arr[1] = 12;
arr.length == 2

Math + Number + String + Array + Object APIs

core Math ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ, Array ์ƒ์„ฑ helper, String helper, ๋ณต์‚ฌ๋ฅผ ์œ„ํ•œ Object.assign ๋“ฑ ๋งŽ์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์ด ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

Number.EPSILON
Number.isInteger(Infinity) // false
Number.isNaN("NaN") // false

Math.acosh(3) // 1.762747174039086
Math.hypot(3, 4) // 5
Math.imul(Math.pow(2, 32) - 1, Math.pow(2, 32) - 2) // 2

"abcde".includes("cd") // true
"abc".repeat(3) // "abcabcabc"

Array.from(document.querySelectorAll('*')) // Returns a real Array
Array.of(1, 2, 3) // Similar to new Array(...), but without special one-arg behavior
[0, 0, 0].fill(7, 1) // [0,7,7]
[1, 2, 3].find(x => x == 3) // 3
[1, 2, 3].findIndex(x => x == 2) // 1
[1, 2, 3, 4, 5].copyWithin(3, 0) // [1, 2, 3, 1, 2]
["a", "b", "c"].entries() // iterator [0, "a"], [1,"b"], [2,"c"]
["a", "b", "c"].keys() // iterator 0, 1, 2
["a", "b", "c"].values() // iterator "a", "b", "c"

Object.assign(Point, { origin: new Point(0,0) })

 

Binary and Octal

2์ง„๋ฒ• (b), 8์ง„๋ฒ• (o) numeric ๋ฆฌํ„ฐ๋Ÿด ํ˜•์‹์ด ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

0b111110111 === 503 // true
0o767 === 503 // true

Promises

Promise๋Š” ๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ์œ„ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž…๋‹ˆ๋‹ค. Promise๋Š” ๋ฏธ๋ž˜์— ์ƒ์„ฑ๋˜๋Š” ๊ฐ’์„ ๋‚˜ํƒ€๋‚ด๋Š” ์ผ๊ธ‰ ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค. Promise๋Š” ํ˜„์กดํ•˜๋Š” ๋งŽ์€ JavaScript ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ์‚ฌ์šฉ๋˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

function timeout(duration = 0) {
    return new Promise((resolve, reject) => {
        setTimeout(resolve, duration);
    })
}

var p = timeout(1000).then(() => {
    return timeout(2000);
}).then(() => {
    throw new Error("hmm");
}).catch(err => {
    return Promise.all([timeout(100), timeout(200)]);
})

 

Reflect API

Reflection API๋Š” ๋Ÿฐํƒ€์ž„ ์‹œ ๊ฐ์ฒด์— ๋Œ€ํ•ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ”„๋ก์‹œ ํŠธ๋žฉ(proxy traps)์™€ ๊ฐ™์€ ๋ฉ”ํƒ€ ํ•จ์ˆ˜๋“ค์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. Reflection์€ ํ”„๋ก์‹œ๋ฅผ ๊ตฌํ˜„ํ•˜๋Š”๋ฐ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

class Greeting {
    constructor(name) {
        this.name = name;
    }

    greet() {
      return `Hello ${name}`;
    }
}

function greetingFactory(name) {
    return Reflect.construct(Greeting, [name], Greeting);
}

greetingFactory('a'); // Greeting {name: "a"}

 

Tail Calls

๋งˆ์ง€๋ง‰์— ํ˜ธ์ถœ๋˜๋Š” ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ ์Šคํƒ์ด ์ดˆ๊ณผ๋˜๊ฒŒ ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์žฌ๊ท€ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๋งค์šฐ ํฐ ์ž…๋ ฅ ๊ฐ’์—์„œ๋„ ์•ˆ์ „ํ•˜๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

function factorial(n, acc = 1) {
    'use strict';
    if (n <= 1) return acc;
    return factorial(n - 1, n * acc);
}

// ํ˜„์žฌ ๋Œ€๋ถ€๋ถ„์˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์—”์ง„์—์„œ ์Šคํƒ ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ๊ฐ€ ์ผ์–ด๋‚˜์ง€๋งŒ,
// ES6์—์„œ๋Š” ์ž…๋ ฅ ๊ฐ’์ด ์ปค๋„ ์•ˆ์ „ํ•˜๋‹ค
factorial(100000);

๐Ÿ”ป์ถœ์ฒ˜ ๋ฐ ์ฐธ๊ณ ์ž๋ฃŒ

https://www.greycampus.com/blog/programming/java-script-versions

 

Java Script Versions

ECMAScript is a widely used standard script language derived mainly from JavaScript. Look into the article to understand the new features for various versions that released after 2009, almost ten years after ES4's abandonment.

www.greycampus.com

https://www.geeksforgeeks.org/difference-between-es5-and-es6/

 

Difference between ES5 and ES6 - GeeksforGeeks

A Computer Science portal for geeks. It contains well written, well thought and well explained computer science and programming articles, quizzes and practice/competitive programming/company interview Questions.

www.geeksforgeeks.org

https://jsdev.kr/t/es6/2944

 

ES6 ๋ฌธ๋ฒ• ์ •๋ฆฌ

Vue ๊ณต๋ถ€๋ฅผ ํ•˜๋‹ค๊ฐ€… ES6 ๋ฌธ๋ฒ•์€ ์•Œ๊ณ  ๊ณต๋ถ€๋ฅผ ํ•ด์•ผ ํ•  ๊ฒƒ ๊ฐ™์•„ ๋ฒˆ์—ญ์„ ์ง„ํ–‰ํ•ด๋ณด์•˜์Šต๋‹ˆ๋‹ค. (ํ•ด์•ผํ•  ๊ฒƒ์ด ์™œ์ผ€ ๋งŽ๋‚˜์š”? ใ… ใ…  ์—ฌ๋Ÿฌ๋ถ„ ๋‹ค๊ฐ™์ด ๊ทธ๋ƒฅ jquery ์”์‹œ๋‹ค ใ…‹ใ…‹) ์˜ค๋ฒˆ์—ญ ํ˜น์€ ์ˆ˜์ •ํ•ด์•ผ ๋  ๊ฒƒ ์ด ์žˆ

jsdev.kr