`Control+Shift+J` `Command+Option+J`(Mac의 경우)를 눌러 DevTools를 엽니다.
ES6 === ES2015
(ES2016,ES2017..)
ES2015
개선된 JavaScript문법
ES6 browser compatibility의 훌륭한 지원.
ES6를 기반으로 한 JavaScript생태계의 확산.
브라우저 호환성
const list = ["apple","orange","watermelon"]; const list2 = [].concat(list, "banana"); console.log(list2); console.log(list === list2);
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); }
let height = 0; alert(height || 100); // 100 alert(height ?? 100); // 0
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];
function sum(a,b,c){ return a+b+c; } let pre = [100,200,300]; console.log(sum.apply(null, pre)); console.log(sum(...pre));
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);
function print() { /* filter, includes, from을 사용해서 문자열'e'가 포함된 노드로 구성된 배열을 만들어서 반환하기 */ } print();
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());
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());
let data = ["crong","honux","jk","jinny"]; let [jisu,,jung] = data; console.log(jisu, jung);
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);
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);
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 - 중복없이 유일한 값을 저장하려고 할때, 이미 존재하는지 체크할 때 유용.
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에서 삭제
참조를 가지고 있는 객체만 지정이 가능하다. 객체형태를 중복없이 저장하려고 할때 유용하다.
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));
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
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);
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
const SETTING = { name : "LUCKY LOTTO!", count : 6, maxNumber : 45 } function getRandomNumber(maxNumber) { // 랜덤한 유일한 숫자값을 추출 }
const SETTING = { name : "LUCKY LOTTO!", count : 6, maxNumber : 45 } function getRandomNumber(maxNumber) { // 랜덤한 유일한 숫자값을 추출 }
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);
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; });
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);
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();
const myObj = { runTimeout() { setTimeout(()=>{ this.printData(); }, 200); }, printData(){ console.log('hi codesquad!'); } } myObj.runTimeout();
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();
function sum(value, size=1){ return value * size; } console.log(sum(3));
function sum(value, size={value:1}){ return value * size.value; } console.log(3, {value:0}));
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); }
function Health(name){ this.name = name; } Health.prototype.showHealth = function(){ console.log(this.name + "님 안녕하세요"); }
class Health { constructor(name, lastTime) { this.name = name; this.lastTime = lastTime; } showHealth() { console.log("안녕하세요" + this.name); } } const myHealth = new Health("crong");
ES5에 추가됨
const healthObj = { showHealth : function() { console.log("오늘은 운동시간 : " + this.healthTime); } } const myHealth = Object.create(healthObj); myHealth.healthTime = "11:20"; myHealth.name = "mama"; console.log(myHealth);
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);
const previousObj = { name : "mama", lastTime : "11:20" } const myHealth = Object.assign({}, previousObj, { "lastTime" : "12:30" }); console.log("myhealth is ", myHealth);
명확하고 단순한 것을 유지함.
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);
//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);
아직은 Browser 에서는 사용 못 하고 있음.
import log, { getTime, getCurrentHour } from './myLogger'; log('my first test data'); log(`getTime is ${getTime()}`); log(`current hour is ${getCurrentHour()}`);
export function log(data){ console.log(data); } export const getTime = () => { return Date.now(); } export const getCurrentHour = () => { return (new Date).getHours(); }
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);
“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')
(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'})
$(function() { var selections = []; $(".niners").click(function() { // 이 클로저는 selections 변수에 접근합니다. selections.push(this.prop("name")); // 외부 함수의 selections 변수를 갱신함 }); });
예제는 더글라스 크락포드(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.
이런 부작용을 고치기 위해서 “즉시 호출된 함수 표현식(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
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의 범위를 함수를 감싸는 코드와 동일하게 유지해줌으로써 기존의 클로저로 인한 번거로움을 많이 해소해 준다.