Lucian Log
Blog
Computer Science
Algorithm
DB
Network
OS
General
AI
Blockchain
Concurrency
ETC
Git
Infrastructure
AWS
Docker
Java-Ecosystem
JPA
Java
Spring
JavaScript-Ecosystem
JavaScript
Next.js
React
TypeScript
Python-Ecosystem
Django
FastAPI
Python
SQLAlchemy
Software Engineering
Architecture
Culture
Test
Home
Contact
Copyright © 2024 |
Yankos
Home
>
JavaScript-Ecosystem
> JavaScript
Now Loading ...
JavaScript
JavaScript - Async/Await
Async-Await async, await을 사용하는 구문은 ES8에서 소개된 JavaScript의 비동기 처리를 위한 syntactic sugar입니다. 비동기 처리하는 과정이나 결과는 이전 callback 함수를 통해 구현하는 방식이나 혹은 ES6에서부터 사용하는 promise 객체를 사용해 구현하는 방식과 동일하지만, 문법적으로 조금 더 편리하게 비동기 처리를 할 수 있도록 제공됩니다. async keyword async function myFunc() { // Function body here }; myFunc(); 비동기 함수를 만들기 위해 사용하는 키워드입니다. 구현한 비동기 처리 로직은 위와 같이 async로 선언된 함수로 감싸서 의도대로 실행할 수 있습니다. const myFunc = async () => { // Function body here }; myFunc(); 또한, async 함수는 함수 선언식 뿐만 아니라 함수 표현식으로도 사용할 수 있습니다. async 함수의 리턴 값 async 함수는 항상 promise 객체를 리턴합니다. 덕분에, 원래의 promise 비동기 처리 방식대로 .then(), .catch() 등을 그대로 사용할 수 있습니다. 다만, 리턴할 때 3가지 상황에 따라 다른 promise 객체를 내어줍니다. 명시적으로 리턴하는 값이 없을 때: undefined를 resolved value로 사용하는 promise 객체를 리턴합니다. 명시적으로 promise 객체가 아닌 값을 리턴할 때: 해당 리턴 값을 resolved value로 사용하는 promise 객체를 리턴합니다. 명시적으로 promise 객체를 리턴할 때: 해당 promise 객체를 그대로 리턴합니다. await keyword async 키워드 만으로는 비동기 처리를 제대로 할 수 없기 때문에, async 함수 안에서는 보통 await을 함께 사용합니다. await은 지정한 함수에서 promise 객체가 리턴 및 resolve될 때까지 async 함수 실행 자체를 멈추었다가, promise의 resolved value를 받으면 해당 값을 리턴하고 async 함수의 남은 코드를 다시 실행하는 키워드입니다. 즉, promise를 객체를 받아 해당 promise 객체를 pending 상태에서 resolved 상태까지 실행하여 resolved value를 리턴하는 전 과정을 포괄합니다. 이러한 특이성으로 인해, await은 주로 라이브러리에서 가져온 promise를 리턴하는 함수와 함께 사용하는 것이 일반적입니다. async function asyncFuncExample(){ let resolvedValue = await myPromise(); console.log(resolvedValue); } asyncFuncExample(); // Prints: I am resolved now! 위 코드에서 myPromise()는 "I am resolved now!"라는 string을 resolve할 promise를 리턴하는 함수입니다. 이렇게 promise의 로직을 인지하며 await을 사용하면, 비동기적인 코드가 순차적인 코드 흐름으로 읽히도록 구현할 수 있습니다. Error handling with try... catch async function usingTryCatch() { try { let resolveValue = await asyncFunction('thing that will fail'); let secondValue = await secondAsyncFunction(resolveValue); } catch (err) { // Catches any errors in the try block console.log(err); } } usingTryCatch(); 기존의 promise 객체 비동기 처리 방식에서 chain이 길어질 때, .catch를 사용해도 어떤 순서에서 error가 발생한 것인지 파악하기 어려웠습니다. 반면에, async... await에서는 try... catch를 사용해 쉽게 error handling을 진행할 수 있습니다. async 함수에서 try... catch는 동기적인 코드와 같은 방식으로 error handling을 할 수 있으면서 동시에, 동기 및 비동기 error 모두를 잡아낼 수 있기 때문에, 쉬운 디버깅을 가능하게 한다는 큰 이점이 있습니다. async function usingPromiseCatch() { let resolveValue = await asyncFunction('thing that will fail'); } let rejectedPromise = usingPromiseCatch(); rejectedPromise.catch((rejectValue) => { console.log(rejectValue); }) 물론 async 함수도 promise 객체의 .catch 메서드를 종종 사용할 때가 있습니다. 위와 같이, 복잡한 코드의 마지막 에러만 잡아내고 싶을 경우 global scope에서 사용하는 것이 하나의 예입니다. 독립적인 promise들을 다루는 방법 다수의 promise 객체들이 서로 의존하고 있을 때는 promise마다 await을 사용하여 명확한 순서로 비동기 처리를 하는 것이 효율적입니다. 반면에, promise 객체들이 서로 독립적일 때는 순서에 상관없이 모든 promise가 동시에 실행되는 것이 보다 효율적입니다. async 함수에서 앞서 이야기한 concurrent 실행을 진행하는 방법을 크게 2가지 소개하겠습니다. await in one line /* 원래의 모습 async function waiting() { const firstValue = await firstAsyncThing(); const secondValue = await secondAsyncThing(); console.log(firstValue, secondValue); } */ // concurrent 실행 async function concurrent() { const firstPromise = firstAsyncThing(); const secondPromise = secondAsyncThing(); console.log(await firstPromise, await secondPromise); } use Promise.all async function asyncPromAll() { const resultArray = await Promise.all([asyncTask1(), asyncTask2(), asyncTask3(), asyncTask4()]); for (let i = 0; i<resultArray.length; i++){ console.log(resultArray[i]); } } Reference Codecademy - introduction to javascript
JavaScript-Ecosystem
· 2021-08-09
JavaScript - Browser compatibility and transpilation
Browser Compatibility & Transpilation 우리는 정기적으로 web browser의 update 알림을 받습니다. 주기적인 update가 필요한 이유는 보통 보안상 취약점을 처리하고 HTML, CSS 혹은 JavaScript의 새로운 syntax 버전을 지원하기 위해서입니다. 특히, JavaScript의 표준을 관리하는 기관, Ecma International이 2015년에 발표한 ECMAScript2015(흔히, ES6로 불리우는)가 등장했을 때, 많은 개발자들은 장점이 많은 ES6를 바로 채택하고 사용했지만 대부분의 브라우저에서 ES6가 지원되지 않아 브라우저 호환성(browser compatibility) 문제가 발생했습니다. 이 챕터에서는 새로운 syntax 버전과의 gap으로 인해 발생하는 이러한 브라우저 호환성 이슈를 개발자들이 어떤식으로 처리하는지에 초점을 맞추려고 합니다. caniuse.com caniuser.com은 브라우저 호환성 정보를 쉽게 찾아볼 수 있는 사이트입니다. 어떤 브라우저의 몇 번째 버전이 특정 라이브러리를 지원하는지 여부를 간단히 체크할 수 있습니다. 이 곳에서 검색해보면, ES5는 여전히 대다수의 브라우저에서 지원됩니다. 이와 달리, ES6는 점진적인 적용을 감안해야 합니다. 그 결과 대부분의 최신 버전 브라우저에서는 ES6가 원활히 지원되는 반면, ES6 module과 같은 ES6의 특정 feature들은 지원되지 않는 브라우저가 아직 대다수입니다. ES6의 장점과 Transpilation의 필요성 ES6는 이전 버전인 ES5에 비해 상당한 이점들이 있습니다. Readability and economy of code Addresses sources of ES5 bugs A similarity to other programming languages 이러한 장점들은 많은 web developer들이 ES6를 곧바로 채택하도록 만들었습니다. 다만, ECMA는 이로 인해 발생할 호환성 문제를 미리 예상해, ES6가 ES5 코드로 mapping될 수 있게끔 만들었습니다. 예를 들어, const나 let 키워드를 var로 mapping하거나, interpolation을 concatenation으로 mapping하는 방식입니다. 이러한 mapping은 충분히 규칙적이기 때문에, 개발자들은 ES6가 자동으로 ES5으로 변환되도록 하는 Babel이라는 JS library를 만들었습니다. 즉, 하나의 프로그래밍 언어를 다른 언어로 변환하는 과정을 transpilation이라고 하며, Babel은 ES6를 ES5로 transpile합니다. Babel Babel은 ES6를 ES5로 손쉽게 transpile해주는 library입니다. 먼저, Babel을 사용하기 위해 ES6의 파일(main.js)의 위치를 ./src/main.js에 둡니다. project |_ src |___ main.js // ES6 file 그리고 Babel을 설치하기 전에 npm을 사용할 수 있게끔 프로젝트를 setup해야 합니다. npm은 node project manager의 약자로 node package에 대한 접근과 관리를 위해 사용됩니다. npm을 사용하면 작업의 반복과 버그를 줄일 수 있습니다. 터미널에서 npm을 init합니다. (Node가 설치되어 있어야 합니다!) npm init 이 때, metadata에 관한 사항을 적어달라는 prompt가 나오는데, title과 description정도만 입력하고 전부 무시해도 좋습니다. (title, description 역시 선택사항입니다.) Init 이후에, root 디렉토리에는 package.json 파일이 생성됩니다. package.json 파일은 해당 프로젝트의 metadata와 프로젝트를 실행하기 위해 필요한 node package 목록, command line scripts에 해당하는 key-value pair 등을 저장합니다. Babel은 터미널 창에서 다음과 같이 사용합니다. Babel package 설치하기 (2개 모두) for CLI tool npm install babel-cli -D for mapping information npm install babel-preset-env -D 실행이 완료되면 Babel 패키지 및 관련된 모든 dependency들이 node_modules 디렉토리에 저장되어 있는 것을 확인할 수 있습니다. -D 옵션 -D는 해당 패키지를 package.json의 devDependencies라는 property에 추가하는 옵션입니다. 일단 devDependencies에 추가된 패키지들은 다른 개발자들이 현재 프로젝트를 실행할 때 각각의 패키지를 install할 필요없이 npm install 커맨드 한 번으로 모두 설치되는 이점을 가집니다. Source가 되는 JS version 설정하기 Root 디렉토리에서 .babelrc 파일을 생성합니다. touch .babelrc .babelrc 내에 source가 될 js 파일의 버전을 명시합니다. 아래와 같은 object를 파일에 저장하면, Babel은 ES6+에 대한 코드들을 목표 언어로 변환할 것입니다. ``` { “presets”: [“env”] } package.json에 Babel 실행을 위한 script 기재하기 package.json에 script property에 가보면 다음과 같은 객체가 존재함을 확인할 수 있습니다. ... "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, ... 이 객체의 "test" property 밑에, 다음과 같이 Babel을 실행하기 위한 script를 하나 추가합니다. ... "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "babel src -d lib" } 추가한 코드는 각각 다음과 같은 의미를 가지고 있습니다. babel — The Babel command call responsible for transpiling code. src — Instructs Babel to transpile all JavaScript code inside the src directory. -d — Instructs Babel to write the transpiled code to a directory. lib — Babel writes the transpiled code to a directory called lib. Babel 실행하기 (root directory) npm run build 작업이 완료되면 ./lib 디렉토리에 변환된 ES5 코드가 담긴 파일을 확인할 수 있습니다. 파일명은 본래의 ES6 파일명과 동일하게 생성됩니다. 최종적인 디렉토리 구조는 다음과 같습니다. project |_ lib |___ main.js |_ node_modules |___ .bin |___ ... |_ src |___ main.js |_ .babelrc |_ package.json Reference Codecademy - introduction to javascript
JavaScript-Ecosystem
· 2021-08-08
JavaScript - Class
Class Javascript는 OOP(object-oriented programming) language입니다. 따라서, 실제 세계를 모델로 class와 instance를 만들어 object들을 사용할 수 있습니다. Syntax example class Dog { constructor(name) { this._name = name; this._behavior = 0; } get name() { return this._name; } get behavior() { return this._behavior; } incrementBehavior() { this._behavior ++; } } const halley = new Dog('Halley'); console.log(halley.name); // Print name value to console console.log(halley.behavior); // Print behavior value to console halley.incrementBehavior(); // Add one to behavior console.log(halley.name); // Print name value to console console.log(halley.behavior); // Print behavior value to console class Class를 생성하기 위해 필요한 키워드 입니다. constructor Class가 object와 가장 구분되는 지점은 constructor 메서드의 유무입니다. constructor는 새로운 instance가 만들어질 때마다 호출되는 class의 중요한 메서드이며, instance를 초기화하는 역할을 합니다. this Class의 맥락에서 this는 해당 class의 instance를 의미합니다. new Class의 instance를 생성하기 위해 사용하는 키워드입니다. new는 class 내의 constructor() 메서드를 호출하고 새로운 instance를 반환합니다. 상속(Inheritance) class Cat { constructor(name, usesLitter) { this._name = name; this._usesLitter = usesLitter; this._behavior = 0; } get name() { return this._name; } get behavior() { return this._behavior; } get usesLitter() { return this._usesLitter; } incrementBehavior() { this._behavior++; } } 앞선 class의 예제에서 Dog class를 만들었던 것처럼, Cat class도 이와 유사하게 만들 수 있습니다. 여기선 Cat의 경우 모든 것이 Dog와 동일하지만 배변기 사용 가능 여부를 나타내는 usesLitter property만 하나 더 가집니다. 이렇게 여러 class가 동일한 부분을 가질 경우, 코드의 반복을 피하기 위해 부모 class를 만들어 자식 class가 이를 상속(inheritance)받게끔 설계하는 것이 효율적입니다. 상속은 부모 class가 가지는 property와 method를 동일하게 사용할 수 있게끔 물려받는 것을 의미합니다. 상속을 사용하면 코드의 가독성이 높아지고 유지보수가 매우 쉬워집니다. class Animal { constructor(name) { this._name = name; this._behavior = 0; } get name() { return this._name; } get behavior() { return this._behavior; } incrementBehavior() { this._behavior++; } } 따라서, 위와 같이 Animal class를 만들어 Dog와 Cat의 공통된 부분을 모은 후, 이를 각자 상속받도록 설계하는 것이 보다 나은 코드를 만드는 방향이 될 것입니다. Animal을 상속받은 Cat의 코드는 다음과 같습니다. class Cat extends Animal { constructor(name, usesLitter) { super(name); this._usesLitter = usesLitter; } get usesLitter() { return this._usesLitter; } } extends Class를 다른 class의 자식 class로 만들기 위해 사용하는 키워드입니다. 부모 class의 method들을 자식 class가 사용할 수 있게 됩니다. super 부모 class의 constructor 메서드를 호출하는 키워드입니다. 부모 class의 property 상속과 관련이 깊습니다. 또한, 자식 class에서 this를 사용하기 위해, 자식 class 내의 constructor 메서드 첫 번째 줄에 반드시 호출해주어야 합니다. (그렇지 않으면, reference error가 발생합니다!) const bryceCat = new Cat('Bryce', false); console.log(bryceCat._name); // output: Bryce console.log(bryceCat.name); // output: Bryce 끝으로, Animal class를 상속받은 Cat은 위와 같이 instance를 만들어 사용할 수 있습니다. Static method Static method는 class에 직접적으로 접근해 사용하는 메서드를 말합니다. 해당 class의 instance를 통해서는 사용할 수 없다는 특징이 있습니다. 예를 들어, Date class는 instance를 만들 수 있으면서 .now() 같은 static method를 사용할 수 있습니다. 다음은 Animal class에 static method generateName을 추가한 코드입니다. class Animal { constructor(name) { this._name = name; this._behavior = 0; } static generateName() { const names = ['Angel', 'Spike', 'Buffy', 'Willow', 'Tara']; const randomNumber = Math.floor(Math.random()*5); return names[randomNumber]; } } console.log(Animal.generateName()); // returns a name static Static method를 선언하는 키워드입니다. static이 사용된 메서드는 instance를 통해 사용할 수 없고, class에서 직접적으로 접근해야 호출 가능합니다. Instance를 통해 호출할 경우, error를 일으킵니다. Reference Codecademy - introduction to javascript
JavaScript-Ecosystem
· 2021-08-07
JavaScript - Object
Object Javascript의 data type은 6개의 primitive data type(string, number, boolean, null, undefined, symbol)과 1개의 object data type으로 구성되어 있습니다. Javascript는 객체지향 언어이고 6개의 primitive data type도 객체와 같이 동작하는 특징이 있습니다. 또한, object는 mutable(변경가능한) 속성을 가집니다. Syntax Object는 {}를 통해 구현됩니다. {} 안에는 unordered data를 key-value pair로 삽입합니다. value의 경우 어떤 data type이 와도 괜찮습니다. 반면에, key의 타입은 string이어야 합니다. 다만, key의 경우 특별한 특수문자를 집어넣는 것이 아니라면 quotation mark 없이 사용해도 string으로 자동 인식됩니다. // An object literal with two key-value pairs let spaceship = { 'Fuel Type': 'diesel', color: 'silver' }; Property Object에 저장된 함수가 아닌 data는 property라고 부릅니다. Property에 접근할 때는 .이 사용됩니다. 만일 object 내에 없는 property에 접근한 경우에는 undefined가 반환됩니다. let spaceship = { homePlanet: 'Earth', color: 'silver' }; spaceship.homePlanet; // Returns 'Earth', spaceship.color; // Returns 'silver', 또 다른 방법은 []을 사용하는 것입니다. 원하는 key를 []안에 넣으면 object에서 해당하는 property에 접근합니다. []는 특수문자가 포함된 key string에 특히 유용합니다. let spaceship = { 'Fuel Type': 'Turbo Fuel', 'Active Duty': true, homePlanet: 'Earth', numCrew: 5 }; spaceship['Active Duty']; // Returns true spaceship['Fuel Type']; // Returns 'Turbo Fuel' spaceship['numCrew']; // Returns 5 spaceship['!!!!!!!!!!!!!!!']; // Returns undefined Add, update and delete [], .와 =를 사용하면, object에 새로운 property를 추가하거나 기존 property를 수정할 수 있습니다. 또한, const 변수에 담긴 object여도 해당 object 안의 property를 추가하거나 수정할 수 있습니다. const spaceship = {type: 'shuttle'}; spaceship = {type: 'alien'}; // TypeError: Assignment to constant variable. spaceship.type = 'alien'; // Changes the value of the type property spaceship.speed = 'Mach 5'; // Creates a new key of 'speed' with a value of 'Mach 5' Object 내의 property를 삭제하는 방법은 delete 키워드를 사용하는 것입니다. 역시 const 변수에 담긴 object여도 내부의 property 삭제가 가능합니다. const spaceship = { 'Fuel Type': 'Turbo Fuel', homePlanet: 'Earth', mission: 'Explore the universe' }; delete spaceship.mission; // Removes the mission property Method Object 내에 저장된 데이터가 함수라면, 해당 데이터는 method라고 부릅니다. Method는 key에 method 이름을, value에 익명 함수를 저장함으로써 구현합니다. const alienShip = { invade: function () { console.log('Hello! We have come to dominate your planet. Instead of Earth, it shall be called New Xaculon.') } }; ES6에서 새로이 소개된 method 문법에서는 :과 function 키워드 없이도 정의할 수 있습니다. const alienShip = { invade () { console.log('Hello! We have come to dominate your planet. Instead of Earth, it shall be called New Xaculon.') } }; Method는 ., ()를 사용해 호출합니다. alienShip.invade(); // Prints 'Hello! We have come to dominate your planet. Instead of Earth, it shall be called New Xaculon.' Pass by reference Javascript에서 object는 pass by reference로 동작합니다. Object를 담는 변수는 실제로는 해당 객체가 담겨 있는 메모리 주소를 담기 때문에, object가 함수에 인자로 전달되어 변형이 일어나면 함수 밖의 실제 object도 영향을 받아 변형됩니다. const spaceship = { homePlanet : 'Earth', color : 'silver' }; let paintIt = obj => { obj.color = 'glorious gold' }; paintIt(spaceship); spaceship.color // Returns 'glorious gold' 함수 내에서 object를 재할당하는 경우 let spaceship = { homePlanet : 'Earth', color : 'red' }; let tryReassignment = obj => { obj = { identified : false, 'transport type' : 'flying' } console.log(obj) // Prints {'identified': false, 'transport type': 'flying'} }; tryReassignment(spaceship) // The attempt at reassignment does not work. spaceship // Still returns {homePlanet : 'Earth', color : 'red'}; spaceship = { identified : false, 'transport type': 'flying' }; // Regular reassignment still works. 함수의 인자로 object를 받을 때, 함수 내에서 새로운 object를 재할당을 하는 것은 기존 object에 영향을 미치지 않습니다. 위 예에서 obj 파라미터는 함수내에 생성되는 로컬 변수입니다. tryReassignment 함수의 흐름은 파라미터 obj에 인자로 들어온 object의 메모리 주소가 담기고, 이에 대해 새로운 object를 할당하여 새 object의 메모리 주소가 다시 obj에 담기게끔 이어집니다. 하지만, 함수가 종료되면 로컬 변수였던 obj 역시 사라지기 때문에, 기존 spaceship에 담긴 object는 변형 없이 그대로 남아 있게 됩니다. for … in Array의 경우 index를 통해 looping할 수 있지만, object는 key를 사용하기 때문에 다른 looping 수단이 필요합니다. 따라서, object looping에 대해서는 for ... in 구문을 사용합니다. let spaceship = { crew: { captain: { name: 'Lily', degree: 'Computer Engineering', cheerTeam() { console.log('You got this!') } }, 'chief officer': { name: 'Dan', degree: 'Aerospace Engineering', agree() { console.log('I agree, captain!') } }, medic: { name: 'Clementine', degree: 'Physics', announce() { console.log(`Jets on!`) } }, translator: { name: 'Shauna', degree: 'Conservation Science', powerFuel() { console.log('The tank is full!') } } } }; // for...in for (let crewMember in spaceship.crew) { console.log(`${crewMember}: ${spaceship.crew[crewMember].name}`); } this keyword this 키워드는 calling object를 나타내며, object의 method 내에서 property에 접근할 때는 this 키워드를 사용합니다. 여기서 calling object란 해당 method를 호출하는 객체를 말합니다. const goat = { dietType: 'herbivore', makeSound() { console.log('baaa'); }, diet() { console.log(this.dietType); } }; goat.diet(); // Output: herbivore 예를 들어, diet() method에서 dietType property에 접근하기 위해서는 반드시 this 키워드가 필요합니다. diet() 내에서 dietType에 접근할 경우 scope가 diet() 안쪽으로 설정되기 때문에 reference error가 발생합니다. 따라서, dietype property에 접근하려면 this 키워드로 calling object인 goat를 불러와 접근해야 합니다. Arrow function과 this const goat = { dietType: 'herbivore', makeSound() { console.log('baaa'); }, diet: () => { console.log(this.dietType); } }; goat.diet(); // Prints undefined 객체에 method를 정의할 때, arrow function 사용은 지양해야 합니다. 위와 같은 경우 this가 가리키는 calling object는 global object입니다. this가 diet scope에 존재하지 않기 때문에, 상위 스코프를 탐색하게 되고 global object가 this가 됩니다. 따라서, global object에는 dietType property가 없기 때문에, this.dietType은 undefined를 가집니다. Privacy of object Product를 만들다보면, 어떠한 object 내 property에 아무나 접근하지 못하게끔 막아야 하는 상황이 발생합니다. 특정 프로그래밍 언어들에서는 이러한 경우를 제어할 수 있는 privacy와 관련된 built-in 키워드를 제공합니다. 하지만 Javascript의 경우 이러한 제어 방법이 없기 때문에, 네이밍 컨벤션을 통해 다른 개발자들에게 해당 property를 어떻게 써야할 지 알려줍니다. 대표적으로 property의 식별자 앞에 _를 붙이는 것은 해당 property가 변형되어서는 안된다는 의미입니다. const robot = { _energyLevel: 100, recharge(){ this._energyLevel += 30; console.log(`Recharged! Energy is currently at ${this._energyLevel}%.`) } }; robot['_energyLevel'] = 'high'; robot.recharge(); // Output: Recharged! Energy is currently at high30%. 예를 들어, 위 코드의 경우 _energyLevel은 robot['_energyLevel'] = 'high';과 같이 실제로 변형이 가능합니다. 하지만, 개발자의 의도에 맞지 않게 string 값으로 변형함으로 인해 high30%와 같은 어색한 결과가 발생했습니다. 이처럼 _가 붙은 property는 원치않는 결과가 나올 수 있으니 직접적으로 접근하여 변형시키면 안된다는 의미를 내포합니다. Getters & Setters Getters method const person = { _firstName: 'John', _lastName: 'Doe', get fullName() { if (this._firstName && this._lastName){ return `${this._firstName} ${this._lastName}`; } else { return 'Missing a first name or a last name.'; } } } // To call the getter method: person.fullName; // 'John Doe' Getters는 객체 내부에서 property를 가져와 반환해주는 method입니다. Method 앞에 get를 사용해 구현하며, this를 통해 객체 내의 property를 조작합니다. Getters를 호출할 때는 마치 property에 접근하는 것 같이, () 없이 .만으로 호출합니다. Getters를 사용하면, property에 접근할 때 원하는 action을 임의로 추가할 수 있고, 다른 개발자들이 이해하기 쉽도록 코드를 짤 수 있습니다. Setters method const person = { _age: 37, set age(newAge){ if (typeof newAge === 'number'){ this._age = newAge; } else { console.log('You must assign a number to age'); } } }; person.age = 40; console.log(person._age); // Logs: 40 person.age = '40'; // Logs: You must assign a number to age 객체 내 property에 대한 접근을 도와주는 getters와 달리, setters는 객체 내 존재하는 property의 value를 재할당할 수 있게 도와주는 method입니다. Method 앞에 set을 사용해 구현하며, 마찬가지로 this를 사용해 객체 내 property를 조작합니다. Setters를 호출할 때도 마치 property에 값을 할당하는 것 같이 .만 사용하여 호출합니다. Setters도 input checking, easier readability 등의 이점을 가집니다. Naming of getters, setters Getters와 setters의 이름은 객체 내의 property들의 이름과 겹쳐서는 안됩니다. 만일 겹칠 경우, 끝없는 call stack error에 빠지게 됩니다. 이를 피하기 위해, property 이름 앞에 _를 붙여주는 것은 좋은 방법이 됩니다. Factory function const monsterFactory = (name, age, energySource, catchPhrase) => { return { name: name, age: age, energySource: energySource, scare() { console.log(catchPhrase); } } }; const ghost = monsterFactory('Ghouly', 251, 'ectoplasm', 'BOO!'); ghost.scare(); // 'BOO!' 하나하나의 object를 직접 만드는 것은 손이 많이 가고 비효율적입니다. 따라서, 몇 가지 parameter를 받아서 customized된 object를 반환하는 함수를 만들면 다수의 object를 효율적으로 생성할 수 있습니다. 이러한 함수를 factory function이라고 합니다. Property value shorthand const monsterFactory = (name, age) => { return { name: name, age: age } }; 기존에는 객체에 property를 저장하기 위해 위 코드와 같이 key-value pair 방식을 사용했습니다. 다만, ES6에서는 factory function을 사용할 때와 같이 parameter의 이름과 property의 이름이 같은 경우에 대해 코드 중복을 줄일 수 있도록 property value shorthand 문법을 제공합니다. 따라서 위 코드는 다음과 같이 수정될 수 있습니다. const monsterFactory = (name, age) => { return { name, age } }; Destructured assignment 객체의 key를 통해 value를 가져와 변수에 저장하던 일반적인 방식에 대해, 조금 더 간략한 destructured assignment 방식이 존재합니다. const vampire = { name: 'Dracula', residence: 'Transylvania', preferences: { day: 'stay inside', night: 'satisfy appetite' } }; 위와 같은 vampire 객체에서 residence property를 가져와 변수에 저장하고 싶다면, 두 가지 방식을 사용할 수 있습니다. const residence = vampire.residence; console.log(residence); // Prints 'Transylvania' 먼저 일반적인 방식으로 key를 통해 가져올 수 있습니다. const { residence } = vampire; console.log(residence); // Prints 'Transylvania' 그런데 만일 key의 이름과 같은 이름으로 변수를 생성한다면, 위와 같이 {}를 통해 보다 간결히 property를 가져와 변수에 저장할 수 있습니다. Reference Codecademy - introduction to javascript
JavaScript-Ecosystem
· 2021-08-06
JavaScript - Iterator
Iterator Looping을 더욱 쉽게 만들어주는 JavaScript의 built-in array methods를 iteration method(=iterator)라고 합니다. Iterator는 array가 element들을 조작하고 value를 반환하기 위해 호출하는 메서드로서 도움을 줍니다. forEach() forEach()는 특정 함수를 array 각각의 element들에 적용하는 iterator입니다. 보통 iterator의 인자로 함수를 받은 후, element들 각각을 인자로 사용해 해당 함수를 호출합니다. (이렇게 다른 함수의 인자로 사용되는 함수를 callback 함수라고 부릅니다.) forEach()는 기존의 array를 변경하지 않으며, undefined를 return합니다. groceries.forEach(groceryItem => console.log(groceryItem)); 또한, arrow function을 인자로 사용해 iterator를 호출할 수도 있습니다. 이처럼, iterator의 인자로 사용되는 함수의 syntax는 임의로 자유롭게 사용할 수 있습니다. map() const numbers = [1, 2, 3, 4, 5]; const bigNumbers = numbers.map(number => { return number * 10; }); console.log(numbers); // Output: [1, 2, 3, 4, 5] console.log(bigNumbers); // Output: [10, 20, 30, 40, 50] map() 역시 forEach()와 비슷하게 동작합니다. 인자로 callback 함수를 받아, array 각각의 element를 callback 함수의 인자로 사용합니다. 다만, map()은 함수를 적용한 새로운 값들을 array에 담아서 반환한다는 점이 특징입니다. filter() const words = ['chair', 'music', 'pillow', 'brick', 'pen', 'door']; const shortWords = words.filter(word => { return word.length < 6; }); console.log(words); // Output: ['chair', 'music', 'pillow', 'brick', 'pen', 'door']; console.log(shortWords); // Output: ['chair', 'music', 'brick', 'pen', 'door'] filter()는 원래의 array에서 특정 조건에 만족하는 element들만 골라내어 새로운 array에 담아 반환합니다. 따라서, filter()에 인자로 사용되는 callback 함수는 반드시 boolean 값을 리턴하는 함수여야 합니다. 이 때, callback 함수가 true를 반환하게 하는 element들이 새로운 array에 담깁니다. findIndex() const jumbledNums = [123, 25, 78, 5, 9]; const lessThanTen = jumbledNums.findIndex(num => { return num < 10; }); console.log(lessThanTen); // Output: 3 console.log(jumbledNums[3]); // Output: 5 findIndex()는 특정 element의 위치를 알고 싶을 때 사용하는 iterator입니다. Callback 함수가 true를 반환하는 첫 번째 element의 index를 return합니다. 만일, callback 함수의 조건을 충족하는 element가 없다면 findIndex()는 -1을 반환합니다. reduce() const numbers = [1, 2, 4, 10]; const summedNums = numbers.reduce((accumulator, currentValue) => { return accumulator + currentValue }) console.log(summedNums) // Output: 17 Iteration accumulator currentValue return value First 1 2 3 Second 3 4 7 Third 7 10 17 reduce()는 말그대로 array을 감소시켜 하나의 값으로 만드는 iterator입니다. Callback 함수에 따라 array의 각 element를 accumulator에 대해 계산해, 최종적으로 하나의 계산 값을 반환합니다. const numbers = [1, 2, 4, 10]; const summedNums = numbers.reduce((accumulator, currentValue) => { return accumulator + currentValue }, 100) // <- Second argument for .reduce() console.log(summedNums); // Output: 117 Iteration # accumulator currentValue return value First 100 1 101 Second 101 2 103 Third 103 4 107 Fourth 107 10 117 또한, reduce()는 optional한 두 번째 parameter를 받을 수 있으며, 이 때 해당 parameter는 accumulator로서 사용됩니다. Reference Codecademy - introduction to javascript
JavaScript-Ecosystem
· 2021-08-04
JavaScript - Array
Array Javascript의 array는 어떤 data type도 저장할 수 있으며, 저장된 data마다 순서(index)를 지닙니다. Syntax 기본적인 문법은 []을 중심으로 이뤄지며, array 내부에 다양한 type의 data들이 함께 저장될 수 있습니다. Indexing Array는 []에 index를 사용하여 원하는 element에 접근할 수 있습니다. Indexing의 시작은 0부터 진행되며, 만일 element의 총 개수를 넘어가는 index로 접근할 경우 undefined가 반환됩니다. Indexing to String const hello = 'Hello World'; console.log(hello[6]); // Output: W 또한, Indexing은 String type의 data에도 적용됨을 유의합니다. Update with index let seasons = ['Winter', 'Spring', 'Summer', 'Fall']; seasons[3] = 'Autumn'; console.log(seasons); //Output: ['Winter', 'Spring', 'Summer', 'Autumn'] Indexing을 사용하면 접근한 data를 원하는 값으로 update하는 것도 가능합니다. let & const in array let condiments = ['Ketchup', 'Mustard', 'Soy Sauce', 'Sriracha']; const utensils = ['Fork', 'Knife', 'Chopsticks', 'Spork']; condiments[0] = 'Mayo'; console.log(condiments); // [ 'Mayo', 'Mustard', 'Soy Sauce', 'Sriracha' ] condiments = ['Mayo']; console.log(condiments); // [ 'Mayo' ] utensils[3] = 'Spoon'; console.log(utensils); // [ 'Fork', 'Knife', 'Chopsticks', 'Spoon' ] const 변수에 저장한 array라도 해당 array 내부의 요소는 여전히 변경가능(mutable)합니다. 다만, 새로운 array 혹은 값을 변수에 재할당할 수는 없습니다. Useful property & method length: array 내의 존재하는 element의 개수를 반환합니다. push(): array의 맨 끝에 element를 추가합니다. (이 때, 인자를 여러 개 받을 수 있습니다.) const itemTracker = ['item 0', 'item 1', 'item 2']; itemTracker.push('item 3', 'item 4'); console.log(itemTracker); // Output: ['item 0', 'item 1', 'item 2', 'item 3', 'item 4']; pop(): array의 맨 끝의 element를 제거하고 그 값을 반환합니다. (인자를 받지 않습니다.) shift(): array 맨 앞의 element를 제거하고 반환합니다. (인자를 받지 않습니다.) unshift(): array의 맨 앞에 element를 추가합니다. (이 때, 인자를 여러 개 받을 수 있습니다.) slice(): 설정한 index대로 slicing한 결과를 반환합니다. const animals = ['ant', 'bison', 'camel', 'duck', 'elephant']; console.log(animals.slice(2)); // expected output: Array ["camel", "duck", "elephant"] console.log(animals.slice(2, 4)); // expected output: Array ["camel", "duck"] console.log(animals.slice(1, 5)); // expected output: Array ["bison", "camel", "duck", "elephant"] console.log(animals.slice(-2)); // expected output: Array ["duck", "elephant"] console.log(animals.slice(2, -1)); // expected output: Array ["camel", "duck"] indexOf(): 인자로 오는 값이 array에서 몇 번째 index인지 찾아 반환합니다. Reference Codecademy - introduction to javascript
JavaScript-Ecosystem
· 2021-07-24
JavaScript - Function
Function of Javascript Syntax Syntax of declaring parameter and calling with argument Parameter를 함수에 선언하는 문법은 다음과 같습니다. 그리고 다음과 같이 인자를 전달해 해당 함수를 호출합니다. Default parameter Javascript에서 default parameter는 ES6 버전에서 소개되었습니다. 함수에 default parameter를 설정해두면, 인자가 전달되지 않거나 data type이 undefined인 인자가 전달될 때 argument의 값으로 default parameter에 설정된 값이 오게 됩니다. function greeting (dog = 'stranger dog') { console.log(`Hello, ${dog}!`) } greeting('Welsh Corgi') // Output: Hello, Welsh Corgi! greeting() // Output: Hello, stranger dog! Return 보통의 언어들처럼 return 키워드를 사용해 함수의 결과를 반환합니다. 만일 어떤 값을 리턴하지 않으면, 기본적으로 undefined 값이 반환됩니다. function greeting(name) { let text = 'Bow wow, hello ' + name + '!'; } console.log(greeting('lucian')) // Prints undefined function greeting(name) { let text = 'Bow wow, hello ' + name + '!'; return; } console.log(greeting('lucian')) // Prints undefined Hoisting Javascript는 함수가 선언된 곳 이전에서도 해당 함수를 호출할 수 있습니다. 이러한 Javascript의 특징을 hoisting이라고 부릅니다. 다만, 함수 선언 이전에 호출하는 것은 일반적으로 좋은 방법이 아니기 때문에, hoisting의 사용은 지양하는 것이 좋습니다. greeting(); // Output: Hello, World! function greeting() { console.log('Hello, bow wow!'); } 함수 표현식 (Function Expression) 함수를 정의하는 또 다른 방법으로 함수 표현식이 있습니다. 보통의 함수 선언식과 달리 함수 표현식은 익명함수를 변수에 저장하는 방식으로 구현합니다.(ES6부터 보통 const 변수에 담습니다.) 익명함수는 식별자(이름)가 없는 함수를 말합니다. 함수 표현식의 기본 문법 예제는 다음과 같습니다. 함수 표현식으로 만든 함수는 변수의 이름을 사용해서 호출합니다. variableName(argument1, argument2) 함수 표현식에서 또 한 가지 유의할 점은 hoisting이 적용되지 않는다는 것입니다. 함수 표현식은 항상 함수를 호출하기 전에 위치해야 합니다. Arrow function 함수를 짧게 정의하도록 돕는 또 하나의 방법입니다. function 키워드를 쓰는 대신 =>를 써서 함수를 선언합니다. 다음은 arrow function의 syntax 예제입니다. const greeting = (name) => { let text = `Hi, ${name}. Bow wow!` return text; }; console.log(greeting('Lucian')); // Hi, Lucian. Bow wow! Concise arrow function Arrow function은 몇 가지 조건 하에서 더욱 간결해질 수 있습니다. 먼저, 함수의 parameter가 한 개라면, () 없이 parameter를 선언할 수 있습니다. 함수의 body가 single-line block일 경우, {}은 생략할 수 있습니다. {}이 없는 경우, 해당 body의 결과는 return 키워드에 상관없이 자동으로 반환됩니다. Reference Codecademy - introduction to javascript 함수 표현식 VS 함수 선언식
JavaScript-Ecosystem
· 2021-07-23
JavaScript - First step
First step of Javascript 출력 console 객체의 log 메서드를 사용해 콘솔에 출력합니다. console.log("print out something"); 주석 처리 Single line comment // something comment Multi-line comment /* something comment */ Fundamental data types Number: Any number, including numbers with decimals: 4, 8, 1516, 23.42. String: Any grouping of characters on your keyboard (letters, numbers, spaces, symbols, etc.) surrounded by single quotes: ' ... ' or double quotes " ... ". Though we prefer single quotes. Some people like to think of string as a fancy word for text. Boolean: This data type only has two possible values— either true or false (without quotes). It’s helpful to think of booleans as on and off switches or as the answers to a “yes” or “no” question. Null: This data type represents the intentional absence of a value, and is represented by the keyword null (without quotes). Undefined: This data type is denoted by the keyword undefined (without quotes). It also represents the absence of a value though it has a different use than null. Symbol: A newer feature to the language, symbols are unique identifiers, useful in more complex coding. No need to worry about these for now. Object: Collections of related data. Object를 제외한 나머지 6개의 data types는 Primitive data type이라고 부릅니다. Operator Javascript에는 다음과 같은 산술 연산자들이 존재합니다. Add: + (복합 대입 연산자는 +=) Minus: - (복합 대입 연산자는 -=) Multiply: * (복합 대입 연산자는 *=) Divide: / (복합 대입 연산자는 /=) Modulo: % (복합 대입 연산자는 %=) Increment operator: ++ (+1을 함과 동시에 할당까지 진행) Decrement operator: -- (-1을 함과 동시에 할당까지 진행) 비교 연산자는 ===를 제외하고는 다른 언어들과 비슷한 양상을 보입니다. 비교 대상은 Number 뿐만 아니라 String도 포함됩니다. Less than: < Greater than: > Less than or equal to: <= Greater than or equal to: >= Is equal to: === Is not equal to: !== 논리 연산자는 다음과 같이 사용합니다. And: && Or: || Not: ! 변수 (Variable) Javascript에서는 camel case가 변수명 convention으로 사용됩니다. favoriteFood, numOfSlices, etc… 또한, 변수는 값을 꼭 할당할 필요 없이 선언만 할 수도 있습니다. 이렇게 선언만 한 경우, 해당 변수에는 자동적으로 undefined 값이 정의됩니다. let price; console.log(price); // Output: undefined price = 350; console.log(price); // Output: 350 Javascript에서는 변수를 선언하는 키워드의 종류로 var, let, const가 있습니다. var: 새로운 변수를 생성할 수 있게 해주는 기본 키워드입니다. 2015년 등장한 ES6 버전 이전에 가장 많이 쓰였습니다. let: 변수에 다른 값이 재할당될 수 있음을 의미하는 키워드입니다. ES6 버전에서 처음 등장했습니다. let dog = 'Welsh Corgi'; console.log(dog); // Output: Welsh Corgi dog = 'Poodle'; console.log(dog); // Output: Poodle const: 변수에 다른 값이 재할당될 수 없음을 의마하는 키워드입니다. 실제로 다른 값을 재할당하면 TypeError가 발생합니다. 또한, 변수는 선언함과 동시에 값이 할당되어야 합니다. 선언만 할 경우 SyntaxError가 발생합니다. let과 마찬가지로 ES6 버전에서 처음 등장했습니다. String concatenation Javascript에서도 +를 사용해 string 간의 concatenation을 수행할 수 있습니다. const favoriteAnimal = 'Welsh Corgi'; console.log('My favorite animal: ' + favoriteAnimal); // My favorite animal: Welsh Corgi 만일 data type이 String이 아닌 data와 concatenation을 할 경우, String type으로 auto converting 되어 정상적으로 concatenation됩니다. const count = 3; console.log('There are ' + count + ' Welsh Corgies!'); // There are 3 Welsh Corgies! String interpolation ES6 버전에서는 template literal을 사용해 변수를 string에 삽입하는 interpolation을 수행할 수 있습니다. Interpolation은 `` 를 사용해 표현하며, placeholder ${변수명}`를 사용해 변수를 삽입합니다. 이렇게 만든 template literal은 문자열로서 취급됩니다. const myPet = 'Welsh Corgi'; console.log(`I own a pet ${myPet}.`); // I own a pet Welsh Corgi. Interpolation은 코드의 가독성을 높이므로, 만들어질 string의 모습을 누구나 쉽게 알 수 있다는 장점이 있습니다. Conditional statement 다음은 Javascript에 존재하는 몇 가지 조건문들의 문법입니다. Syntax of If statement if (condtion) { codeblock } else if (condition) { codeblock } else if (condition) { codeblock } else { codeblock } Syntax of ternary operator (condition) ? (codeblock when true) : (codeblock when false); Syntax example of switch statement let dog = 'Welsh Corgi'; switch (dog) { case 'Golden Retriever': console.log('Golden Retriever, bow wow!'); break; case 'Dachshund': console.log('Dachshund, bow wow!'); break; case 'Welsh Corgi': console.log('Welsh Corgi, bow wow!'); break; default: console.log('No correct dog but bow wow!'); break; } Reference Codecademy - introduction to javascript
JavaScript-Ecosystem
· 2021-07-22
<
>
Touch background to close