사용자 도구

사이트 도구


study:ecma2015

ECMA2015(ES6)

Netscape --javascript(JAVA ..)

  1. prototype
  2. jquery
  3. React - facebook 서비스(라이브리성…)
  4. AngularJS - Angular1.0 - Google – javascript
  5. Vue
  6. Angular 2 –> Angular – typescript

ECMAScript 2015

ES6 === ES2015 (ES2016,ES2017..) ES2015 개선된 JavaScript문법
ES6 browser compatibility의 훌륭한 지원.
ES6를 기반으로 한 JavaScript생태계의 확산.
브라우저 호환성

language 기본

  • var
    • function scope
  • let
    • block scope like for a general programming language
  • const
    • 재할당을 하지 못한다.
    • 배열의 push등은 가능하다.
    • immutable array를 만들어서 사용할 수 있다.
      •         const list = ["apple","orange","watermelon"];
                const list2 = [].concat(list, "banana");
                console.log(list2);
                console.log(list === list2);
         
  • string에 추가 method
    • startsWith
    • endsWith
    • includes
  • for of - 순회하기
    • var data = [1,2,234];
      data.forEach(function(value,idx){
        console.log(value);
      });
       
      data.forEach(function(value){
        console.log(data[a]);
      }
      for(let idx in data) {
        console.log(data[idx]);
      }
      Array.prototype.getIndex = function(){} 
      // for in 에서 문제발생
      // Object의 function도 같이 순회한다.
       
      for(let value of data) {
        console.log(value);
      }
       
      let str = 'asdf 111';
      for(let value of str) { // character단위로 순회한다.
        console.log(value);
      }
  • || ?? operator
    • let height = 0;
      
      alert(height || 100); // 100
      alert(height ?? 100); // 0
  • spread operator, 펼침연산자
    • let pre = ["apple","orange", 100];
      let newData = [...pre];
      console.log(pre === newData);
    • let pre=[100,200,"hello",null];
       
      let newData = [0,1,2,3, ...pre, 4];
    • Argument로 넘겨 줌
      function sum(a,b,c){
        return a+b+c;
      }
      let pre = [100,200,300];
      console.log(sum.apply(null, pre));
       
      console.log(sum(...pre));

ES2015 from method

function addMark(){
  let newData = [];
 
  for(let i=0; i < arguments.length; i++) {
    newData.push(arguments[i] + "!");
  }
 
  console.log(newData);
}
 
addMark(1,2,3,4,5);

argument.map활용 –> Error남… 배열같지만 배열이 아닌 것들이 javascript에는 존재한다.

function addMark(){
  //let newData = arguments.map(function(value){ //--> Error
  let newarray = Array.from(arguments);
  let newData = newarray.map(function(value){
    return value + "!";
  });
 
  console.log(newData);
}
 
addMark(1,2,3,4,5);

예제1

ex1.html
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="wid">
  <title>JS Bin</title>
</head>
<body>
  <ul>
    <li>apple</li>
    <li>orange</li>
    <li>banana</li>
    <li>strawberry</li>
  </ul>
</body>
</html>

문제

ex1.js
function print() {
  /*
  filter, includes, from을 사용해서 문자열'e'가 포함된
  노드로 구성된 배열을 만들어서 반환하기
  */
}
 
print();

풀이

aw1.js
function print() {
  /*
  filter, includes, from을 사용해서 문자열'e'가 포함된
  노드로 구성된 배열을 만들어서 반환하기
  */
  let list = document.querySelectorAll("li");
  console.log(toString.call(list));
 
  let listArray = Array.from(list);
  console.log(toString.call(listArray));
 
  let eArray = listArray.filter(function(v){
    //return v.includes("e"); // Error . v는 node
    return v.innerText.includes("e");//
  });
  return eArray;
}
 
console.log(print());

Object

function을 이용한 Object생성

function getObj(){
  const name = "crong";
 
  const getName = function() {
    return name;
  }
 
  const setName = function(newName) {
    name = newName;
  }
 
  const printName = function() {
    console.log(name);
  }
 
//  return {
//    getName: getName,
//    setName: setName
//  }
  return { getName, setName }
}
 
var obj = getObj();
console.log(obj.getName());

Destructuring

Array

let data = ["crong","honux","jk","jinny"];
let [jisu,,jung] = data;
console.log(jisu, jung);

Object

let obj = {
  name : "crong",
  address : "korea",
  age : 10
}
obj["name"];
obj.name;
;
 
obj = $.extend(obj,
{
name2 : "asdfa";
}
)
obj["name"];
obj["name2"];
obj.name2;
 
 
let {name:myName, age:myAge} = obj; // myName, myAge변수에 할당함.
console.log(myName, myAge);

활용 JSON파싱

var news = [
  { "title":"sbs",
    "imgurl":"http://asdfasdf",
    "newslist":[
    ]
  },
  { "title":"mbc",
    "imgurl":"http://asdfasdf",
    "newslist":[
    ]
  }
];
 
let [,mbc] = news;
let {title, imgurl} = mbc;
console.log(title,imgurl);
let [,{title,imgurl}] = news;
console.log(title,imgurl);
function getNewsList([,newslist]){
  console.log(newslist);
}
getNewsList(news);

Event

document.querySelector("div").addEventListener("click",fucntion(evt){
  console.log(evt);
});
document.querySelector("div").addEventListener("click",fucntion({target}){
  console.log(target.tagName);
});
document.querySelector("div").addEventListener("click",fucntion({type}){
  console.log(type);
});

SET

자료구조 Set - 중복없이 유일한 값을 저장하려고 할때, 이미 존재하는지 체크할 때 유용.

let mySet = new Set();
console.log(toString.call(mySet));
 
mySet.add("crong");
mySet.add("hary");
mySet.add("chrong");
 
console.log(mySet.has("crong"));
 
mySet.forEach(function(v){
  console.log(v);
});
 
 
mySet.delete("crong");// set에서 삭제

WeakSet

참조를 가지고 있는 객체만 지정이 가능하다. 객체형태를 중복없이 저장하려고 할때 유용하다.

let arr = [1,2,3,4];
let ws = new WeekSet();
 
ws.add(arr);
ws.add(111); // error
ws.add("111"); // error
ws.add(null); // error
ws.add(fuction(){});
console.log(ws);
let arr = [1,2,3,4];
let arr2 = [5,6,7,8];
let obj = {arr, arr2};
let ws = new WeekSet();
 
ws.add(arr);
ws.add(arr2);
ws.add(obj);
 
arr = null;
arr2 = null;
console.log(ws);
console.log(ws.has(arr), ws.has(arr2));

map & WeakMap

Array –> set,weakset Object –> map, weakmap

map은 key/value의 구조(dictionary)

let wm = new WeakMap();
let myfun = function(){};
// 이 함수가 얼마나 실행됐는지를 알려고 할때
 
wm.set(myfun,0);
 
console.log(wm);
 
let count = 0;
for(let i=0;i<10;i++){
  count = wm.get(myfun); // get value
  count++;
  wm.set(myfun, count);
}
 
console.log(wm.get(myfun)); // 10
myfun = null;
console.log(wm.get(myfun)); // undefined
 
console.log(wm.has(myfun)); // false

WeakMap 활용 --> private

function Area(height, width){
  this.height = height;
  this.width = width;
}
 
Area.prototype.getArea = function(){
  return this.height * this.width;
}
 
lget myarea = new Area(10,20);
console.log(myarea.getArea());
console.log(myarea.height);

weakmap의 전역변수를 이용

const wm = new WeakMap();
function Area(height,width){
 wm.set(this, {height, width});
}
 
Area.prototype.getArea = function(){
  const {height, width} = wm.get(this);
  return height * width;
}
lget myarea = new Area(10,20);
console.log(myarea.getArea());
console.log(myarea.height);
 
 
//
 
console.log(wm.has(myarea));// true;
myarea = null;
console.log(wm.has(myarea));// false;
// Garbage Collection

실습.Destructuring and Set 활용

lotto번호만들기.

  1. 유일한값을 추출하는 과정에서 Set을 사용합니다.
  2. getRandomNumber함수에 변수를 전달하는 과정에서 destructuring을 사용해봅시다.
const SETTING = {
  name : "LUCKY LOTTO!",
  count : 6,
  maxNumber : 45
}
 
function getRandomNumber(maxNumber) {
// 랜덤한 유일한 숫자값을 추출
}

Answer

const SETTING = {
  name : "LUCKY LOTTO!",
  count : 6,
  maxNumber : 45
}
 
function getRandomNumber(maxNumber) {
// 랜덤한 유일한 숫자값을 추출
}

Template처리

json으로 응답을 받고, javascript object로 변환한 후에 어떠한 데이터처리 조작을 한 후에 dom에 추가! 데이터 + HTML문자열의 결합이 필요하기 때문에

const data = [
  {
    name : 'coffee-bean',
    order : true,
    items : ['americano', 'milk', 'green-tea']
  },
  {
    name : 'starbucks',
    order : false,
  }
];
 
const template = `<div>welcome ${data[0].name} !!</div>`
console.log(template);

Tagged template literals

const data = [
  {
    name : 'coffee-bean',
    order : true,
    items : ['americano', 'milk', 'green-tea']
  },
  {
    name : 'starbucks',
    order : false,
  }
];
// Tagged template literals
function fn(tags, name, items) {
  //console.log(tags);
  if(typeof items === "undefined") {
    items = "주문가능한 상품이 없습니다.";
  }
  return (tags[0] + name + tags[1] + items + tags[2]);
}
const template = fn`<div>welcome ${data[0].name}!!</div>
  <h2>주문가능항목</h2><div>${data[0].items}</div>`;
 
//console.log(template);
 
data.forEach(v => {
  let template = fn`<div>welcome ${v.name}!!</div>
  <h2>주문가능항목</h2><div>${v.items}</div>`;
  console.log(template);
  document.querySelector('#message').innerHTML += template;
});

Arrow Function

setTimeout(function(){
  console.log("settimeout");
}, 1000);
 
let newArr = [1,2,3,4,5].map(function(value, index, object) {
  return value * 2;
});
 
let newArr3 = [1,2,3,4,5].map( (v) => (v * 3));
let newArr4 = [1,2,3,4,5].map( v => v * 4);

this context of Arrow function

const myObj = {
  runTimeout() {
    setTimeout(function(){
      this.printData(); // this는 window( in browser).
                        // bind(this)를 통해서 myObj로 bind
    }.bind(this), 200);  
  },
  printData(){
    console.log('hi codesquad!');
  }
}
 
myObj.runTimeout();
arrow function에서 this
const myObj = {
  runTimeout() {
    setTimeout(()=>{
      this.printData();
    }, 200);
  },
  printData(){
    console.log('hi codesquad!');
  }
}
 
myObj.runTimeout();
DOM Event도 같은 방식
const el = document.querySelector("p");
 
const myObj = {
  register() {
    el.addEventListener("click", (evt) => {
      this.printData(evt.target); // bind없이 this
    });
  },
 
  printData(el) {
    console.log('clicked!!', el.innerText);
  }
}
myObj.register();

default parameters

function sum(value, size=1){
  return value * size;
}
 
console.log(sum(3));

object

function sum(value, size={value:1}){
  return value * size.value;
}
 
console.log(3, {value:0}));

rest parameters

function checkNum(){
  const argArray = Array.prototype.slice.call(arguments);
  console.log(argArray);
  console.log(toString.call(arguments));
  const result = argArray.every((v) => typeof v === "number");
  console.log(result);
}
 
const result = checkNum(10,2,3,"55");
const result = checkNum(10,2,3,4,5,"55");

rest parameters

function checkNum(...argArray){
  const result = argArray.every((v) => typeof v === "number");
  console.log(result);
}

ES6 class

function Health(name){
  this.name = name;
}
 
Health.prototype.showHealth = function(){
  console.log(this.name + "님 안녕하세요");
}

constructor

class Health {
  constructor(name, lastTime) {
    this.name = name;
    this.lastTime = lastTime;
  }
  showHealth() {
    console.log("안녕하세요" + this.name);
  }
}
 
const myHealth = new Health("crong");

Object assign 메서드

ES5에 추가됨

const healthObj = {
  showHealth : function() {
    console.log("오늘은 운동시간 : " + this.healthTime);
  }
}
 
const myHealth = Object.create(healthObj);
 
myHealth.healthTime = "11:20";
myHealth.name = "mama";
 
console.log(myHealth);

Object Assign

const healthObj = {
  showHealth : function() {
    console.log("오늘은 운동시간 : " + this.healthTime);
  }
}
 
const myHealth = Object.assign(Object.create(healthObj),{
  name : "mama",
  lastTime : "11:20"
});
 
myHealth.healthTime = "11:20";
myHealth.name = "mama";
 
console.log(myHealth);

Object assign으로 immutable객체 만들기

const previousObj = {
  name : "mama",
  lastTime : "11:20"
}
 
const myHealth = Object.assign({}, previousObj, {
  "lastTime" : "12:30"
});
 
console.log("myhealth is ", myHealth);

setPrototypeOf

명확하고 단순한 것을 유지함.

const healthObj = {
  showHealth : function() {
    console.log("오늘 운동시간 : " + this.healthTime);
  }
}
const myHealth = {
  name : "mama",
  lastTime : "11:20"
}
 
const newobj = Object.setPrototypeOf(myHealth, healthObj);
console.log("myhealth is ", myHealth);
 
console.log("newobj is ", newobj);

Object setPrototypeOf로 객체간 prototype chain생성하기

//parent
const healthObj = {
  showHealth : function() {
    console.log("오늘 운동시간 : " + this.healthTime);
  },
  setHealth : function(newTime) {
    this.healthTime = newTime;
  }
}
 
// child obj
const healthChildObj = {
  getAge : function() {
    return this.age;
  }
}
 
const lastHealthObj = Object.setPrototypeOf(healthChildObj, healthObj);
 
const childObj = Object.setPrototypeOf({
  age: 22
}, healthChildObj);
 
console.log("childObj is ", childObj);

Module(export & import)의 이해

아직은 Browser 에서는 사용 못 하고 있음.

app.js
import log, { getTime, getCurrentHour } from './myLogger';
 
log('my first test data');
log(`getTime is ${getTime()}`);
log(`current hour is ${getCurrentHour()}`);
myLogger.js
export function log(data){
  console.log(data);
}
 
export const getTime = () => {
  return Date.now();
}
 
export const getCurrentHour = () => {
  return (new Date).getHours();
}

Proxy

const myObj = { name:'mama', changedValue:0 };
const proxy = new Proxy(myObj, {
  get: function(target, property, receiver){
    console.log('get Value')
 
    // if(property in target) ... 없는 프러퍼티에 대해서 Error처리를 할 수 있다.
 
    //return target[property];
    return Reflect.get(target, property, receiver);
  },
  set: function(target, property, value, receiver){
    console.log('set value');
    console.log('target : ', target);
    console.log('value :', value);
    target['changedValue']++;
    target[property] = value;
    return true;
  }
});
 
console.log('myObj : ', myObj);
console.log('proxy : ', proxy);
proxy.name = 'crong';
console.log('proxy : ', myObj);

기타정보들

IIFE[Immediately Invoked Function Expression]

“Iffy”라고 발음. 즉시호출함수표현… 기초 지식은 많이 있겠지만, JavaScript에서는 function도 하나의 data type 이다. 따라서 파라메터로 넘겨주는 것이 가능하다. 또한 JavaScript에서는 function의 이름을 생략할 수 있다.

(function(d){
let myday = new Date(d);
myday.setFullYear(myday.getFullYear() + 1);
return myday;
})('2018.08.10');

function f(a){ asdfasdfgo 일… } ; f('asdf');

f( (function(d){ let myday = new Date(d); myday.setFullYear(myday.getFullYear() + 1); return myday; })('2018.08.10') ); f('asd')

About DATE

날짜 포맷(yyyymmdd)출력하기(datepicker)

(function(p_date){
  let startDate = new Date(p_date);
  startDate.setDate(startDate.getDate() + 1);
  return $.datepicker.formatDate('yy.mm.dd', startDate);
})("2018.09.12")

말일 구하기

(function(day){
	let lastday = new Date(day.substring(0,4), day.substring(4,6)-1+1, 0);
	return $.datepicker.formatDate('yymmdd', lastday);
})(getStdDate())

날짜 더하기

((new Date()).getFullYear() + 1) + ".12.31"

요일명

var d = new Date()
d.toLocaleDateString('ko-KR', {weekday: 'long'})

클로저(Closure)

jQuery에서 사용하는 클로저

$(function() {
  var selections = [];
  $(".niners").click(function() { // 이 클로저는 selections 변수에 접근합니다.
    selections.push(this.prop("name")); // 외부 함수의 selections 변수를 갱신함
    });
  });

Private구현방법.

예제는 더글라스 크락포드(Douglas Crockford)에 의해 처음 시연되었습니다:

function celebrityID() {
  var celebrityID = 999;
  // 우리는 몇개의 내부 함수를 가진 객체를 리턴할것입니다.
  // 모든 내부함수는 외부변수에 접근할 수 있습니다.
  return {
    getID: function() {
      // 이 내부함수는 갱신된 celebrityID변수를 리턴합니다.
      // 이것은 changeThdID함수가 값을 변경한 이후에도 celebrityID의 현재값을 리턴합니다.
      return celebrityID;
    },
    setID: function(theNewID) {
      // 이 내부함수는 외부함수의 값을 언제든지 변경할 것입니다.
      celebrityID = theNewID;
    }
  }
}
var mjID = celebrityID(); // 이 시점에, celebrityID외부 함수가 리턴됩니다.
mjID.getID(); // 999
mjID.setID(567); // 외부함수의 변수를 변경합니다.
mjID.getID(); // 567; 변경된 celebrityID변수를 리턴합니다.

비꼬기

클로저가 갱신된 외부함수의 변수에 접근함으로써, 외부 함수의 변수가 for문에 의해 변경될 경우 의도치 않은 버그가 발생할 수 있습니다.

function celebrityIDCreator(theCelebrities) {
  var i;
  var uniqueID = 100;
  for (i=0; i<theCelebrities.length; i++) {
    theCelebrities[i]["id"] = function() { return uniqueID + i; }
  }
  return theCelebrities;
}
 
var actionCelebs = [{name:"Stallone", id:0}, {name:"Cruise", id:0}, {name:"Willis", id:0}];
var createIdForActionCelebs = celebrityIDCreator(actionCelebs);
var stalloneID = createIdForActionCelebs[0];
console.log(stalloneID.id); // 103

위의 예제에서, 익명의 내부함수가 실행될 시점에 i의 값은 3입니다(배열의 크기만큼 증가한 값). 숫자 3은 uniqueID에 더해져 모든 celebritiesID에 103을 할당합니다. 그래서, 기대(100,101,102)와 달리 모든 리턴된 배열의 id=103이 됩니다.

이런 결과가 나타난 이유는, 앞서 언급했듯이 클로저는(이 예제에서 내부의 익명함수) 외부 변수에 대해 값이 아닌 참조로 접근하기 때문입니다. 즉, 클로저는 최종 갱신된 변수(i)에 대해서만 접근할 수 있으므로, 외부 함수가 전체 for문을 실행하고 리턴한 최종 i의 값을 리턴하게 됩니다. 100+3=103.

IIFE사용하여 수정하기

이런 부작용을 고치기 위해서 “즉시 호출된 함수 표현식(Immediately Invoked Function Expression. IIFE)”를 사용할 수 있습니다.

function celebrityIDCreator(theCelebrities) {
    var i;
    var uniqueID = 100;
    for (i=0; i<theCelebrities.length; i++) {
        theCelebrities[i]["id"] = function(j) {
            // j 파라미터는 호출시 즉시 넘겨받은(IIFE) i의 값이 됩니다.
            return function() {
                // for문이 순환할때마다 현재 i의 값을 넘겨주고, 배열에 저장합니다.
                return uniqueID + j;
            } () // 함수의 마지막에 ()를 추가함으로써 함수를 리턴하는 대신 함수를 즉시 실행하고 그 결과값을 리턴합니다.
        } (i); // i 변수를 파라미터로 즉시 함수를 호출합니다.
    }
    return theCelebrities;
}
var actionCelebs = [{name:"Stallone", id:0}, {name:"Cruise", id:0}, {name:"Willis", id:0}];
var createIdForActionCelebs = celebrityIDCreator(actionCelebs);
var stalloneID = createIdForActionCelebs[0];
console.log(stalloneID.id); // 100
var cruiseID = createIdForActionCelebs[1];
console.log(cruiseID.id); // 101

화살표함수와 this

ES5에서 가장 헷갈리는것이 바로 this의 범위이다. 클로저가 생성한 컨텍스트로 인해 this가 this가 아닌 상황이 발생하여 “that = this, self = this”와 같은 패턴을 사용해야만 했다.

var self = this
$('.btn').click(function(event){
  self.sendData()
})

또는 “.bind(this)”를 사용해 this를 현재 컨텍스트와 수동으로 바인딩하기도 했었다.

$('.btn').click(function(event){
  this.sendData()
}.bind(this))

화살표 함수를 사용하면 이러한 번거로움을 해소할 수 있다.

$('.btn').click((event) =>{
  this.sendData()
})

화살표 함수는 함수 표현식을 간략하게 표기하도록도 해주지만 this의 범위를 함수를 감싸는 코드와 동일하게 유지해줌으로써 기존의 클로저로 인한 번거로움을 많이 해소해 준다.

ChanLee

study/ecma2015.txt · 마지막으로 수정됨: 2025/04/15 10:05 저자 127.0.0.1