====== ECMA2015(ES6) ====== [[book:ecmascript:home|JavaScript Mama’s book]] * [[http://www.ecma-international.org/publications/standards/Ecma-262.htm|Standard ECMA-262 최신 ES2022 - 2019]] * [[https://developer.mozilla.org/ko/docs/Web/JavaScript|JavaScript MDN]] * [[javascript:vanilla|Vanilla Javascript]] * [[http://daplus.net/javascript-javascript%EC%97%90%EC%84%9C-dom-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%B0%94%EC%9D%B8%EB%94%A9%EC%9D%84-%EA%B5%AC%ED%98%84%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95/|재미있는 2-Way 데이터 바인딩]] * [[https://javascriptpi.blogspot.com/2016/12/two-way-data-binding.html|DOM 요소를 서로 또는 JavaScript 객체와 바인딩하는 방법을 보여주는 코드와 데모입니다.]] * [[https://rxjs.dev/|rxjs - Angular에서 사용하는 two way data binding 라이브러리]] * [[https://poiemaweb.com|웹 프로그램 튜토리얼(정리잘되어있음)]] * [[javascript:bootstrap|Javascript BootStrap]] * [[javascript:handbook|Javascript 요약집]] * [[javascript:clone|Clone Function]] * [[javascript:regexp|regexp예]] * [[javascript:maro_pattern|Maro Pattern]] * avgrund - popup jQuery lib * [[http://webframeworks.kr/tutorials/translate/arrow-function/|화살표 함수와 메소드 정의]] * [[javascript:browser|edge로 가기]] * DevTool열기 `Control+Shift+J` `Command+Option+J`(Mac의 경우)를 눌러 DevTools를 엽니다. ===== Netscape --javascript(JAVA ..) ===== - prototype - jquery - React - facebook 서비스(라이브리성...) - AngularJS - Angular1.0 - Google -- javascript - Vue - Angular 2 --> Angular -- typescript * [[javascript:array|Array]] * [[javascript:extend|Object extend]] * [[javascript:regexp|RegExp 전화번호]] * [[javascript:regexp|RegExp Password]] * [[javascript:class|Class와 this]] * [[javascript:callbackAndThis|callback function과 this]] * [[javascript:void|void undefined]] ===== ECMAScript 2015 ===== ES6 === ES2015 (ES2016,ES2017..) ES2015 개선된 JavaScript문법\\ ES6 browser compatibility의 훌륭한 지원.\\ ES6를 기반으로 한 JavaScript생태계의 확산.\\ [[https://kangax.github.io/compat-table/es6/|브라우저 호환성]] ==== 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 ==== JS Bin === 문제 === 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()); ==== 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번호만들기. === - 유일한값을 추출하는 과정에서 Set을 사용합니다. - 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 = `
welcome ${data[0].name} !!
` 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`
welcome ${data[0].name}!!

주문가능항목

${data[0].items}
`; //console.log(template); data.forEach(v => { let template = fn`
welcome ${v.name}!!

주문가능항목

${v.items}
`; 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 에서는 사용 못 하고 있음. 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(); } ==== 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 위의 예제에서, 익명의 내부함수가 실행될 시점에 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 ==== 화살표함수와 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의 범위를 함수를 감싸는 코드와 동일하게 유지해줌으로써 기존의 클로저로 인한 번거로움을 많이 해소해 준다. {{http://chanlee.github.io/categories/|ChanLee}}