본문 바로가기

항해99 WIL

항해99 3주차 WIL (JavaScript의 ES란?, ES5/ES6 문법 차이)

JavaScript의 ES란?, ES5/ES6 문법 차이

 

자바스크립트의 ES란 ??

ES는 ECMA (European Computer Manufactures Association) Script의 약자이다.

 

ES의 탄생 배경

자바스크립트는 1990년대 Netscape 회사의 Brendan Eich라는 사람에 의해 최초 개발되었다. 자바스크립트가 잘 되자, MS의 IE 3에도 Jscript라는 언어를 개발해 IE에 탑재하였는데, 이 두 스크립트가 너무 제각각이라, 크로스 브라우징 이슈(기능이 모든 브라우저에서 동일하게 동작하지 않는 이슈)가 발생했다. 

 

표준을 위해 자바스크립트를 ECMA(European Computer Manufactures Association)라는 정보와 통신시스템의 비영리 표준 기구에 제출하였고 표준에 대한 작업을 ECMA-262란 이름으로 1996년 11월에 시작해 1997년 6월에 채택되었다. 또한 ECMA에서는 자바스크립트의 표준만 내리는 게 아니라 다른 표준안도 정하기 때문에 그와 구분하기 위해 숫자를 붙였는데 262다.

ES5는 ECMA Script5의 규격을 따른다고 생각하면 된다.

 

 

 

현재는 ES6 ECMA Script6의 규격을 따르고 있으며 즉ECMA 스크립트 규격, 표준 즉, 스펙을 말한다.

 

ES5문법

1. 'use strict'

  • 'strict mode'에서 javascript code를 실행
  • 선언하지 않은 variable, object를 사용/수정/삭제할 수 없다.
  • 함수 호이스팅도 제한된다.
  • script나 function 시작 부분에 "use script";을 선언함으로써 사용
  • IE9에서는 지원하지 않는다.

 

2. String.trim()

  • string의 공백 제거
var str = "      Hello Recat        ";
console.log(str.trim());    // Hello Recat

3. Array.isArray()

  • Object가 Array인지 검사
var fruits = ["바나나", "오렌지", "포도", "딸기"];
console.log(Array.isArray(fruits));    //  true

4. Array.forEach()

  • Array의 element들을 하나씩 호출
var txt ="";
var number = [45, 4, 9, 16, 25];
numbers.forEath(myFunction);

function myFunction(value) {
	txt = txt + value + ' ';
}

console.log(txt);    // 45 4 9 16 25

5. Array.map()

  • Array를 순회하면서 새로운 Array를 만든다.(기존에 있던 Array는 변경되지 않는다.)
var number1 = [45, 4, 9, 16, 25]
var number2 = numbers1.map(myFunction);  // [90, 8, 18, 32, 50]

function myFunction(value, index, array) {
	return value * 2;
}

6. Array.filter()

  • 조건에 맞는 새로운 Array를 생성
var number = [45, 4, 9, 16, 25];
var over18 = number.filter(myFunction);         // [45, 25]

function myFunction(value, index, array) {
	return value > 18;
}

7. Array.reduce()

  • 각 element를 순회하면서 새로운 value를 생성(Array를 하나의 single value로 줄인다.)
  • 기존에 있던 Array는 변경되지 않는다.
var number1 = [45, 4, 9, 16, 25];
var sum = numbers1.reduce(myFunction);  // 99

function myFunction(total, value, index, array) {
	return total + value;
}

8. Array.reduceRight()

  • Array.reduce()와 같은 기능이지만, 오른쪽부터 순회한다.
  • 기존에 있던 Array는 변경되지 않는다.

9. Array.every()

  • 모든 Array의 Element들이 주어진 조건을 만족하는지 검사
var = number = [45, 4, 9, 16, 25];
var allOver18 = number.every(myFunction);    //  false

function myFunction(value, index, array) {
	return value > 18;
}

10. Array.some()

  • Array의 Element 중에 주어진 조건을 만족하는 Element가 있는지 검사
var numbers = [45, 4, 9, 16, 25];
var someOver18 = number.some(myFunction);   //  true

function myFunction(value, index, array) {
	return value > 18;
}

11. Array.indexOf()

  • Array의 element 중 주어진 value와 같은 element의 위치를 반환( 제일 첫 번째 위치는 0이다.)
var fruits = ["사과", "오렌지", "사과", "망고"]
var a = fruits.indexOf("사과");    // 0

12. Array.lastIndexOf()

  • Array.indexOf()와 같지만, Array의 뒤쪽부터 순회
var fruits = ["사과", "오렌지", "사과", "망고"];
var a = fruits.lastIndexOf("사과");    //  2

13. JSON.parse()

  • 웹 서버로부터 데이터를 받았을 때, string 타입의 데이터를 javascript의 object 타입으로 바꿔준다.
  • 데이터는 JSON 형태이다.
var obj = JSON.parse('{"name":"Hwan", "age":25, "city":"Aansan"}');

14. JSON.stringify()

JSON 형태의 데이터를 웹 서버로 전송할 때 string 타입으로 바꿔준다.

var obj = {"name":"Hwan", "age":25, "city":"Aansan"};
var myJSON = JSON.stringify(obj)

15. Date.now()

시간을 millisecond 단위로 반환

console.log(Date.now() === new Date().getTime());    //  true

참조 : https://www.w3schools.com/js/js_es5.asp

 

JavaScript ES5

W3Schools offers free online tutorials, references and exercises in all the major languages of the web. Covering popular subjects like HTML, CSS, JavaScript, Python, SQL, Java, and many, many more.

www.w3schools.com

 

 ES6문법

1. Let + Const

 

  • let
    block(function, for, if 등) 안에서 유효한 변수
  • const
    block(function, for, if 등) 안에서 유효한 변수 const는 수정 불가능한 불변성(immutable)을 말하는 것이 아니라 값 재할당이 불가능한 것 const를 사용하더라도, 배열과 오브젝트의 값을 변경하는 게 가능하다.
const list = ["godori", "irodog", "roodig"];
list.push("dorigo");
console.log(list);  // ["godori", "irodog", "roodig", "dorigo"]

2. Arrows

  • ES6에서는 익명함수를 화살표('=>')로 축약해 표현 가능
  • Arrow Function Expression 또는 Fat Arrow Function이라 부른다.
param => expression

 

([param][, param]) => {
  statements
  }
  • param : 매개변수, 콤마(,)로 구분하고 괄호를 감싸서 호출한다. 파라미터가 한 개인 경우, 괄호를 생략해도 된다.
  • statements or expression : 여러 구문은 중괄호(brace, {})로 감싸준다. 한 개의 표현식이라면 중괄호를 생략해도 된다.

code sample

//한줄짜리 표현식
let square = x => x * x;
square(3); // 9

//중괄호를 생략한 한줄 표현식은 중괄호와 함께 리턴한 것과 동일
let square2 = (x) => { return x * x };
square2(3);  // 9

//파라미터로 전달할 경우, 훨씬 간결하게 표현 가능
setTimeout(() => {
  console.log('delayed');
}, 100);
  
let list = [1, 2, 3, 4];
list.filter(n => {
  return n % 2 === 0;
});  // [2, 4]
list.reduce((sum, n) => sum + n, 0);  // 10
    
//즉시실행함수는 아래와 같이 표현 가능
(() => {
     console.log('foo');
})();

//'=>'로 정의한 함수 내의 'this'는 현재 객체를 가리킨다.
let obj = [
  getThis: function() {
    var getter = () => this;
    return getter();
  }
};
obj.getThis() === obj;  //-> ture

//'this'는 lexical 범위 내의 'this'를 가리켜서,
//아래 코드처럼 객체의 메서드에서 'this'를 사용하면 객체 선언을 감싸고 있는 함수의 'this'를 가리키게 된다.
(function () {
  this.name = 'outer';
  var inner = {
    name: 'inner',
    getName: () => {
      return this.name;
    }
  };
  inner.getName();  //-> 'outer'
}());

//Arraow Function 내에서 'use strict'; 구문을 정의한 경우,
//strict mode의 'this'는 무시된다.
let obj = {
  getThis: function () {
    let getter = () function () {
      'use strict';
      return this;
    };
  }
};
obj.getThis() === obj; //-> true
obj.getThis2() === undefined; // -> true

3. Classes

  • 자바스크립트는 프로토타입 기반(prototype-based) 객체지향 언어.
  • 프로토타입 기반으로 클래스를 만들 수도 있지만, class를 이용하여 명료하게 클래스를 만들 수 있게 되었다.
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();
  }
}

4. Enhanced object literals

 

ES6에서 객체 리터럴은 선언문에서 아래와 같은 기능을 할 수 있도록 함.

 

  • 프로토타입 설정
  • foo : foo 선언을 위한 단축 표기법
  • 메서드 정의, super 클래스 호출 및 동적 속성명을 지원
let obj = {
	//__proto__
    __proto__: theProtoObj,
    
    // 'handler: handler'의 단축 표기
    handler,
    
    //Methods
    toString() {
    // Super calls
    return "d" + super.toString();
    },
    
    // Computed (dynmic) property names
    [ 'prop_' + (() => 42)() ]: 42
};

4. 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 inerpolation
let name = "hwan", 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);

5. Destructuring

 

Destructuring는 배열과 객체에 패턴 매칭을 통한 데이터 바인딩을 제공.

 

  • Destructuring는 할당 실패에 유연하고 실패 시 undefined 값이 자동 할당
  • foo["bar"]와 같이 객체의 속성 값도 자동으로 검색하여 바인딩
// list matching
let [a, , b] = [1, 2, 3];   // a: 1(number), b: 3(number)

// objext matching
let { op: a, lhs: { op: b }, rhs: c }
	 = getASTNode()
     
// objext matching 단축 표기
// binds 'op', 'lhs', and 'rhs' in scope
let {op, lhs, rhs} = getASTNode()

// parameter에서도 사용 가능
function g({name: x}) {
  console.log(x);
}
g({name: 5})

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

// Fail-soft destructuring with defauits
let [a = 1] = [];
a === 1;

6. Default + Rest + Spread

 

파라미터에 기본 값을 설정 가능

function f(x, y=12) {
  // y is 12 if not passed (or passed as undefind)
  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

7. Iterators + For... Of

 

Iterator 객체는 CLR의 IEnumerable 혹은 Java의 Iterable처럼 사용자 정의의 반복을 가능하게 해 준다. 

for... of 반복문이 ES6에서 추가되었으며, for...in 반복문과 달리 iterator 기반의 컬렉션 전용 반복문이다.

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) {
// truncate the sequence at 1000
	if (n > 1000)
        break;
    console.log(n);  // 1, 2, 3, 5, 8, ...987

8. Generators

 

Generators는 function* 와 yield 키워드를 이용하여 iterator 선언을 단순하게 작성할 수 있게 해 준다. function*로 선언한 함수는 Generator 객체를 반환한다. Generators는 iterator의 하위 타입이며 next와 throw 메서드를 가지고 있다. 이 메서드들로 인해 yield 키워드로 반환된 값은 다시 Generator에 주입되거나 예외처리를 할 수 있게 되었다.

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

for (let 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"];
}

let 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: ture }

 

9. Unicode

 

완전한 유니코드를 지원하기 위해 문자열에 새로운 유니코드 리터럴과 정규표현식에 u 모두가 추가되었다. 또한 21비트 형식까지 처리하기 위한 API가 추가되었다. 이 추가된 기능은 자바스크립트로 글로벌 앱을 만들 수 있도록 지원한다.

// same as ES5.1
"吉".length == 2

// new ReExp 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(let c of "吉") {
		console.log(c); // 吉
}

 

10. Modules

 

언어 차원에서 컴포넌트 정의를 위한 모듈을 지원한다. 유명한 자바스크립트 모듈 로더들(AMD, CommonJS)의 패턴을 적용시켰다. 런타임 동작은 호스트에 정의된 기본 로더에 의해 정의된다. 묵시적 비동기 형태로 요구되는 모듈들이 정상적으로 로드되지 전까지 코드가 실행되지 않는다.

// lib/math.js
export function sum(x, y) {
	return x + y
}
export var pi = 3.141593;

 

1. 'math'라는 variable로 접근하여 사용하는 방법

// app.js
import * as math from "lib/math";
console.log("2π = " + math.sum(math.pi, math.pi)); // 2π = 6.283186

 

2. export 한 모듈의 이름을 import 해서 사용하는 방법

// 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 let a = 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);

11. Module loaders

 

Module Loaders는 다음을 지원한다.

  • 동적 로딩(Dynamic loading)
  • 상태 격리(State isolation)
  • 전역 네임스페이스 격리(Global namepace 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
let loader = new Loader({
	global: fixup(window) // replace 'console.log'
});    
loader.eval("console.log('hello world!')");

// 모듈 캐시 직접 조작
System.get('jquery');
System.set('jquery', Module({$: $}));  // WARNIG: not yet finalized

12. Map + Set + WeakMap + WeakSet

 

일반 알고리즘을 위한 효율적인 데이터 구조를 제공한다. WeakMap과 WeakSet는 메모리 누수로부터 자유롭게 해 준다. 이들 내 저장된 객체에 다른 참조가 없는 경우, garbage collection이 될 수 있다.

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

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

// Weak Maps
let wm = new WeakMap();
wm.set(s, { extra: 42 });
wm.size // undefined (사용된 곳이 없기 때문)

// Weak Sets
let ws = new WeakSet();
ws.add({ data: 42 });
wm.size // undefined (사용된 곳이 없기 때문)

 

13. Proxies

 

프록시(Proxy)를 사용하면 호스트 객체에 다양한 기능을 추가하여 객체를 생성할 수 있다.

interception, 객체 추상화, 로깅/수집/, 값 검증 등에 사용될 수 있다.

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

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

let p = new Proxy(target, handler);
p()  // 'I am the proxy';
let validator = {
	set: function(obj, prop, value) {
    	if (prop === 'age') {
        	if (!Number.isIntger(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)들이다.

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

14. Symbols

 

심볼(Symbol)은 객체 상태의 접근 제어를 가능케 한다. Symbol은 새로운 원시 타입으로 이름 충돌의 위험 없이 속성(property)의 키(key)로 사용할 수 있다. 옵션 파라미터인 description는 디버깅 용도로 사용되며 식별 용도는 아니다. Sybol은 고유(unique)하며, Object, getOwnPropertySymbols와 같은 reflection 기능들로 접근할 수 있기 때문에 private 하진 않는다. (for in나 Object.keys()로는 접근 불가)

let map = {};
let 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"]

 

15. Subclassable Built-ins

 

ES6에서 Array, Date, DOM Element 같이 내장 객체들은 상속이 가능하다. 객체 생성 시 호출되는 Ctor함수는 다음의 2단계를 가진다(둘 다 가상적으로 실행).

 

  • 객체 할당을 위해 Ctor[@@create] 호출하여
  • 새로운 인스턴스의 생성자를 호출해 초기화 진행

 

@@create Symbol은 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
let arr = new MyArray();
arr[1] = 12;
arr.length == 2

16. posmises

Promise는 비동기 프로그래밍을 위한 라이브러리이다. Promise는 미래에 생성되는 값을 나타내는 일급 객체이다. Promise는 현존하는 많은 자바스크립트 라이브러리에 사용되고 있다.

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

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

17. mat + 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) })

 

18. Binary and Octal literals

 

2진법 (b), 8진법 (o) numeric 리터럴 형식이 추가되었다.

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

 

19. 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"}

20. Tail Calls

 

마지막에 호출되는 함수가 호출 스택이 초과되게 하지 않는다. 재귀 알고리즘을 매우 큰 입력 값에서도 안전하게 만든다.

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

// 현재 대부분의 자바스크립트 엔진에서 스택 오버플로우가 일어나지만,
// ES6에서는 입력 값이 커도 안전하다.
factorial(100000)

 

상세하게 ES6문법에 자세히 알고 싶다면 밑의 참조 url을 확인 이상하다 해보길 바란다.

 참조 : https://www.w3schools.com/js/js_es6.asp