본문 바로가기

FRONT-END/JAVASCRIPT

자바스크립트 표준 #1

반응형

자바스크립트 표준

ECMAScript 6 표준

ECMAScript 5가 2009년에 정의되면서 자바스크립트의 활용이 다양해지기 시작

이때 부터 기존 자바스크립트가 가지고 있던 문제점들이 지적되고, 자바스크립트의 언어적 한계를 개선하여 더 다양한 분야에서 활용하고자 하는 움직임이 있었다.

그 결과 2009년부터 ECMAScript 6의 준비 작업을 시작하여 2015년 6월에 발표되었다.

ECMAScript 6(ES6)은 ECMAScript 2015라고도 불리며 기존 자바스립트 개발자들의 다양한 논의를 거쳐서 자바스크립트 언어가 나아갈수 있는 개선된 방향을 보여주고 있다.


하지만 이미 기존의 표준을 기반으로 전 세계의 수많은 웹페이지가 동작하고 있어서 ES5의 핵심 중 하나는 하위 호환성을 지원하는 것이었다.

따라서  ES6이 정의된 브라우저로 이전의 표준으로 정의된 웹페이지를 열어도 문제없도록, 기존의 표준 위에 추가적인 기능들이 조금 더 나은 프로그래밍 언어의 모습을 얹어놓았다.


 추가기능

 세부내용 

 변수, 상수 선언

 변수 선언용 let, 상수 선언용 const 키워드 추가

 화살표 표현식

 함수 정의에 대한 새로운 화살표 표현식 => 추가

 클래스

 클래스 키워드 추가

 객체 표현식 기능 확대

 프로토타입 정의 기능, 함수와 속성에 대한 표현식 추가

 템플릿 문자열

 역따옴표(`)를 통한 문자열의 추가 기능 확대

 Destructuring 기능

 객체 표현식을 통해 변수들을 매핑하여 할당기능

 함수 인자 기능 확대

  인자 기본값 설정, 가변 인자 기능 확대

 Iterator와 for-of 기능

 Iterator 속성 정의 기능과 for-of 추가 키워드 정의, Iterator 속성을 간단하게 정의하기 위한 function과   yield  키워드 추가

 Map과 Set 기능 추가

 Map과 Set 키워드 와 WeakMap, WeakSet 키워드 추가

 Binary+Octal  표현식

 2진수, 8진수 표현식 추가

 TypedArray 기능

 형식 기반 배열 기능 추가

 모듈기능 표준화

 모듈관리를 위한 export, import 표준 추가

 Proxy 모듈 추가

  객체 가상화 또는 Proxy 패턴의 다양한 기능을 기본 표준으로 추가

 Symbol 모듈 추가

 새로운 기본형에 대한 정의 기능 추가

 Promise  모듈 추가

 Promise API 기능 추가

 기존 추가 API Math, Number, String, Array, Obejct에 추가 API





변수, 상수 선언

기존 자바스크립트는 var 키워드로 변수나 상수를 자유롭게 설정

ES6에서는 상수와 변수를 구분할 수 있는 키워드 추가


<!DOCTYPE html>

<html lang="ko">

 <head>

   <meta charset="utf-8">

   <title>hello ES6</title>

 </head>

 <body>

 <script>

(function(){

 let myObject = {

  name: "unikys",

  say() {

  alert("My name is "+this.name);

  }

 };


 myObject.say();


 const constString = "This is a constant";

 constString = "This will raise an error"; //Error!

 }());

 </script>

 </body>

 </html>


기존 var 키워드의 일반적인 객체는 let 키워드로 정의

변경되지 않을 상수는 const 키워드로 정의


기존에는 자바스크립트의 블록 개념이 다른 언어와 달리 if나 for 블록 안에서 var 변수를 정의하여도 외부에서 사용할 수 있었다.

그러나 let 과  const 키워드는 C나 JAVA와 같은 블록 개념을 도입하여 if나 for안에서 변수를 정의하면 외부에서 사용할 수 없다.


 if(true){

 var varVariable = 1;

 let letVariable = 2;

 }

 console.log(varVariable);

 console.log(letVariable);  //Uncaught ReferenceError: letVariable is not defined



 let myArray = [0,1,2,3,4,5],

 length = myArray.length;


 for (let i = 0; i < length; i++) {

  if(myArray[i] > 3){

break;

}

 }

 console.log(myArray[i]);  //Uncaught ReferenceError: i is not defined

let으로 정의하면 if 블록안에서 사용할 수 있고, for문 안에서만 사용할 수 있다.


기존의 var 키워드는 같은 변수명을 여러번 정의해도 문제가 없었으나, let이나 const 키워드로 같은 변수명, 또는 상수명을 정의하면 에러가 발생

 var duplicatedName ="This is with var";

 let duplicatedName = "No problem";

 const duplicatedName = "Syntax error will be raised"; //Uncaught SyntaxError: Identifier 'duplicatedName' has already been declared

let과 const 키워드로 중복 정의할 때 에러가 발생하는 이유는 개발자의 실수로 인한 변수를 덮어쓰기를 방지하기 위해서이다.



함수 화살표 표현식

자바스크립트에서 클로저의 활용이 다양하게 나오면서 가장 많이 사용되기 시작한 키워드가 바로 function이다.

그래서 ES6에서는 익명함수를 표현할 때 간단하게 표현할수 있는 화살표 표현식을 추가

 let myFunc = () => alert("This is a new function literal");

 myFunc();


 var myFuncES5 = function (){

 alert("This is a new function literal");

 };


 myFuncES5();

괄호(), 그리고 화살표 "=>"를 같이 사용하면 ES6부터 제공하는 새로운 함수 표현식이 된다.

여기서  function이 생략되고 =>가 추가된것으로 생각하면된다. 하나의 실행문을 함수에서 포함하고 있다면 중괄호도 생략할 수 있다


let paramFunc = (greeting, name) => {

alert(greeting + ", " + name );

}


paramFunc("Hello", "World");


var paramFuncES5 = function(greeting, name) {

alert(greeting + ", " + name);

}


paramFuncES5("Hello", "World");


function은 키워드라서 미니피케이션등 하려고 해도 더는 축약이 불가능하다.

따라서 화살표 표현식으로 더 축약하기 위해서, 그리고 많은 function 정의를 간편하게 하기 위해서 ES6에 함수 화살표 표현식이 추가로 정의되었다.


그리고 기존 익명 function과 가장 크게 다른점은 콜백함수로 실행될 때 기존의 익명 function은 글로벌 컨텍스트에 접근하였으나, 함수 화살표 표현식은 콜백 함수를 할당한 당시의 컨텍스트를 그대로 활용한다.

이에 따라서 객체지향의 관점에서 콜백함수를 정의할 때 더 유연하고 쉽게 컨텍스트를 활용할 수 있다.

var name = "Global";

function Person(){

this.name = "Unikys";


setTimeout(()=> alert("My name is "+ this.name),100);

setTimeout(function(){

alert("Global name is "+ this.name);

}, 100);

}


var person = new Person();

setTimeout()의 콜백함수가 호출될 때 함수 화살표  표현식 안에서 this.name은 Person의 this.name="Unikys"에 접근한다.

하지만 익명 function은 글로벌 영역의 변수 name ="Global"에 접근하여 서로 다른 값을 출력한다.

다른 프로그래밍 언어를 하다가 자바스크립트를 하면 이러한 함수의 컨텍스트에 대한 제대로 알지못해서 프로그래밍을 잘못하는 예가 많다.

그래서 함수 화살표 표현식에서는 그러한 실수를 없애기 위해 변경되었다.

이러한 예 이외의 익명 function이 가장 많이 쓰이는 곳은 즉시 호출 함수(IIFE)를 사용하는 경우일 것이다.

자바스크립트의 <script>태그에서 시작하자마자 많이 나타나는 즉시 호출 함수는 글로벌 영역에서 자바스크립트가 처리되는 것을 방지하고, 한 단계 캡슐화하기 위해서 사용된다.

(function(){

alert("ES5 IIFE");

 }());


 (()=>{

 alert("ES6 IIFE");

 })();

function 키워드를 이용할 때 괄호를 어디에 묶어도 상관없지만, 화살표 표현식을 사용할 때는 먼저 괄호로 묶고 함수를 호출해야한다는 점이다.

이차이를 빼면 두 표현식은 같은 용도로 사용할 수 있다.



클래스(class) 키워드

기존 자바스크립트에서는 객체지향을 구현하려고 할 때 function을 생성자로 사용하였다.

ES6에서는 class 키워드가 추가돼서 클래스를 정의하여 사용할 수 있게 되었다.

class Car {

constructor(name){

this.name = name;

this.type = "Car";

}

getName(){

return this.name;

}

}


 let car = new Car("My Car");

 console.log("car.getName():" + car.getName());


기존에는 function 자체의 이름을 클래스명으로 하고, function 내부에서 실행되는 내용 자체를 생성자로 두고 있어서 자바스크립트에서 정확하게 '클래스'라고 말하기에는 조금 모호한 부분이 있었다.

하지만 ES6부터는 class 키워드와 함께 생성자로 설정할수 있고, 속성과 멤버변수도 설정할 수 있도록 기능이 추가되었다.

또한 다른 객체지향 언어처럼 서브 클래스를 사용할 수도 있다.

이로써 자바스크립트를 통해서 객체지향 프로그래밍이 수월해졌다.

class Car {

constructor(name){

this.name = name;

this.type = "Car";

}

getName(){

return this.name;

}

}


 let car = new Car("My Car");

 console.log("car.getName():" + car.getName());



class SUV extends Car {

constructor(name){

super(name);

this.type = "SUV";

}

}


let suv = new SUV("My SUV");

console.log("suv instance of SUV: " + (suv instanceof SUV));

console.log("suv instanceof Car: " + (suv instanceof Car));

console.log("suv.getName(): "+ suv.getName());

console.log(SUV);


 }());


생성자 함수 constructor라는 이름으로 정의하며, 다른 객체지향 언어와 마찬가지로 부모 클래스의 생성자를 호출하려면 super 키워드를 사용하면 된다.

자바스크립트의 서브 클래스를 초기화하려면 먼저 부모 클래스의 생성자를 호출해야하므로 constructor의 가장위에 super()등의 생성자를 호출한다.

그 다음 SUV 클래스로 인스턴스를 새로 생성한 후, SUV 클래스와 부모 클래스인 Car 클래스에 대해서 인스턴스인지 확인한다.

그리고 실제로 SUV를 그대로 로그에 찍어서 어떻게 출력되는지 확인하는 절차로 이어진다.

먼저 car.getName()은 정상적으로 "My car"로 출력된다. suv가 SUV의 인스턴스이면 SUV가 Car의 서브클래스이므로 Car의 인스턴스로 판단되는 것을 확인할수 있다.

따라서 SUV 클래스에서 정의하지 않는 getName() 함수도  동일하게 사용할 수 있고, SUV 클래스 자체를 출력한 결과를 보면"function class SUV extends Car" 인것을 알수 있다.


class 키워드는 내부적으로는 함수처럼 동작한다. 이 때문에 typeof SUV는 "function"이라고 나타난다.

이러한 class 키워드는 자바스크립트에서 약간 모호했던 클래스와 상속에 대한 개념을 제대로 정립하고 객체지향 프로그래밍을 위해 추가되었다.


객체표현식 기능 확대

ES6에서는 기존의 JSON 표현식에서 확대하여 조금 더 동적이고 간단하게 객체 표현식을 제공한다.

ES6에서 속성을 다른 변수로 정의할때 변수명과 같은 속성명으로 값을 설정하려면 간단하게 설정할 수 있는 기능이 추가되었다.

var property1 = "New",

property2 = "Object literal",

namedProperty = "Functionlities";


var mergedObject = {

property1: property1,

property2: property2,

property3: namedProperty

};


console.log(mergedObject);


var newMergedObejct = {

property1,

property2,

property3: namedProperty

};


console.log(newMergedObejct);




기존에는 mergedObject와 같이 속성명과 속성값의 변수명이 같더라도 항상 같이 명시해야했지만, ES6부터는 newMergedObject와 같이 변수명을 별도로 명시하지 않아도 자동으로 속성명이 할당된다.

그리고 property3과 같이 속성명과 속성값을 따로 명시하면 변수명과 값을 다르게 설정할 수 있으므로 혼합해서 사용해도 된다.


또 다른 ES6의 특징은 기존에는 속성명을 고정된 문자열로만 정의해야 했던 객체 표현식을 계산식 또는 문자열 조합의 결과로 설정할 수 있다는 점이다.

이 특징 때문에 기존에는 객체 표현식과 별개로 별도 속성을 설정해야 했다면, ES6에서는 객체 표현식만으로도 처리할 수 있게 되었다.

var i = 0,

newComputedProperty = {

["property"+ ++i] : i,

["property"+ ++i] : i,

["property"+ ++i] : i

};


console.log(newComputedProperty);


var j =0,

previousComputedProperty = {};


previousComputedProperty["property"+ ++j] = j;

previousComputedProperty["property"+ ++j] = j;

previousComputedProperty["property"+ ++j] = j;


console.log(previousComputedProperty);




기존에는 객체 표현식만으로 처리하지 못하고 별도의 객체의 속성을 설정하는 단계를 거쳐야 했지만, ES6에서는 객체 표현식 안에서 모두 처리할 수 있게 되었다.


또 함수를 정의할 때 기존과 다르게 functioni 키워드를 생략하고 바로 함수명부터 설정해도 되고, 이전보다 getter와 setter를 설정하는 것이 편리해졌다

객체 안에서 속성으로 함수를 많이 지정하는 자바스크립트의 특성상 이렇게 객체를 생성하면 다른 프로그래밍 언어를 하다가 자바스크립트를 접하는 개발자들에게는 더 직관적이다.

또한 function 키워드를  생략할 수 있어서 미니피케이션에도 조금이나마 도움이된다.

var newFunctionDefinition = {

func() {

alert("This is new definition")

},

_name: "Unikys",

get name(){

return this._name;

},

set name(name){

this._name = name;

}

};


var previousFunctionDefiniction = {

func : function(){

alert("This is the compatible definiction");

},

_name : "Unikys"

};


Object.defineProperty(previousFunctionDefiniction, "name", {

get: function(){

return this.name;

},

set: function(name){

this._name = name;

}

});


객체 표현식안에서 function 키워드를 제외하고 바로 괄호와 인자를 정의하면된다.

그리고 get, set을 속성명 앞에 붙이는 것만으로 쉽게 getter와 setter를 설정할 수 있다.


그리고 이전에는 객체가 생성되면 내부적으로 객체의 프로토타입이 __proto__로 숨겨진 속성으로 표현되었다.

그러나 ES6에서는 객체 표현식으로 정의할 수 있게 되었다.

이는 기존의 Object.create으로 생성하던 객체와프로토타입의 기능을 그대로 객체 표현식으로 옮겨온 것으로 생각하면된다.


var car = {

name: "Default",

type: "Car",

getName() {

return this.name

}

}


var suvES6 = {

__proto__: car,

name: "My Car",

type: "SUV"

};


var suvES5 = Object.create(car, {

name : {

writable: true,

configurable: true,

value: "My car"

},

type: {

writable: true,

configurable: true,

value: "SUV"

}

});


var suvES5Other = Object.create(car);

suvES5Other.name = "My Car";

suvES5Other.type = "SUV";


console.log(suvES5Other);

기존에는 Object.create을 통해서 프로토타입을 정의하고 직접 속성을 별도로 추가하거나 조금 복잡하게 설정해야 했지만, ES6의 객체 표현식에서는 __proto__ 속성을 직접 설정함으로써 하나의 표현식으로 해결할수 있다.


출처-속깊은 자바스크립트 양성익 지음

반응형