변수, 제어문, 함수, 클래스 등 언어의 기초를 이루는 구성과 상세하고 미묘한 사용법을 배웁니다.
오류와 실패의 관계
함수 내부의 오류는 내부에서 처리하지 말고, 외부에서 처리할 수 있게 throw문을 사용해서 외부에 오류를 전가하자
const sum = (arr) => {
let total = 0;
for (let i = 0; i < arr.length; i++) {
if (typeof arr[i] !== 'number') {
throw `invalid element ${i}: ${arr[i]}`;
}
total += arr[i];
}
...
}
try {
sum([1,2,null])
} catch (e) {
console.error(e);
}
- 안정성도 중요하지만 신뢰성이 더 중요하다! 오류가 발생했을 때 최대한 빨리 실행의 실패로 이어지가 짜라. 특정 오류때문에 프로그램이 아예 멈추거나 하면 그 오류를 찾고, 수정하는게 더 쉽다. 만약 잘못된 처리가 이뤄졌는데 정상적으로 작동하게되면 찾기도 더 힘들고 발견하는데 시간이 오래걸린다. (컨텍스트 에러가 더 위험하다)
- ex) 월급 지급 프로그램
- 특정 직원에게 잘못된 금액이 지급되는것 보다 아예 오류를 발생시켜 지급자체가 안되게끔하는게 더 낫다.
- 신뢰성
- 코드의 실행결과가 실제 예측한대로 잘 작동하는 것
- 안정성
- 코드가 멈추지 않고 작동하게끔하는 것
- ex) 월급 지급 프로그램
- 유지보수시에는 코드를 수정하는 이유를 충분히 고민하고 수정해라.
- 역할에 따라 코드를 나누고 코드들을 합리적인 구조로 변경하면서 중복을 제거하자.
- 자바스크립트에서는 함수의 인터페이스(매개변수의 모양과 타입)가 일치하면 그 함수들을 하나의 함수로 정리할수도 있다. (해당 동영상에서는 배열의 총 합을 구하는 함수를 수정해가면서 예를 들고 있다. 한곳에 뭉쳐져있던 코드를 설명을 해주며 분리해간다.)
- 데이터와 데이터를 이용한 알고리즘이 이원화 되면 관리가 어려워진다 -> 데이터를 소유한 객체쪽에서 데이터를 활용하는 알고리즘을 제공해라
메모리와 연산의 관계
- 메모리(변수)를 많이 쓰면 연산을 덜 할 수 있다.
- ex) 피보나치 함수 구현시 메모이제이션을 하는 경우, fibo(N) 의 결과를 얻기 위해 N이전까지의 결과를 메모리에 저장하면 연산을 덜 할수있자.
- 라이프사이클과 스코프를 잘 이해하고 코드를 짜면 메모리를 덜 쓰게하거나 연산을 덜하게 하는 방법을 선택할 수 있다.
// elementSum이 arraySum이 실행할때마다 생겼다가 사라짐 -> 메모리를 덜 점유함
const arraySum = arr => {
const elementSum = (arr, i, acc) => {
if (arr.length === i) return acc;
return elementSum(arr, acc + arr[i], i + 1);
};
return elementSum(arr, 0, 0);
}
// arraySum이 실행시 클로져로 저장되어 생겼다가 사라지지 않음 -> 메모리를 더 점유하지만 함수가 여러번 생성되지않음
const arraySum = arr => {
const elementSum = (arr, i, acc) => {
if (arr.length === i) return acc;
return elementSum(arr, acc + arr[i], i + 1);
};
const arraySum = (arr) => elementSum(arr, 0, 0)
return arraySum;
}
재귀함수를 for문으로
const err = msg => {throw msg};
const _tailRecursiveSum = (array, i, acc) => i > 0 ? _tailRecursiveSum(array, i - 1, array[i] + acc) : (array[0] ?? err("invalid element index 0")) + acc;
const tailRecursiveSum = (array) => _tailRecursiveSum(array, array.length - 1, 0);
const iterateSum = (array) => {
let acc = 0;
for (let i = array.length - 1; i > 0; i = i - 1) {
acc = array[i] + acc; // 재귀함수에서는 함수를 호출하면서 매개변수에 값을 하나씩 추가했지만, for문을 활용함 함수는 1번만 실행되기때문에 훨씬 빠르다.
}
acc += (array[0] ?? err("invalid element index 0")) + acc;
return acc;
};
과제 구현 코드
// JSON.stringify를 구현하시오
// https://www.youtube.com/watch?v=rQOpmgo99BQ
/**
* 자료
* https://reference.codeproject.com/Book/javascript/reference/global_objects/json/stringify
* https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify
*/
class myJSON {
constructor() {
}
static get_type(data) {
if (data === null) {
return ('null');
} else if (data === undefined) {
return ('undefined');
} else {
return (typeof data);
}
}
static valueToString(value, valueOwnerConstructor) {
let str = '';
switch(myJSON.get_type(value)) {
case 'string':
str = `"${value.toString()}"`;
break;
case 'number':
str = value.toString();
break;
case 'null':
str = 'null';
break;
case 'undefined':
str = valueOwnerConstructor === Array ? 'null' : undefined;
break;
case 'function':
str = 'null';
break;
case 'symbol':
str = valueOwnerConstructor === Array ? 'null' : undefined;
break;
case 'boolean':
str = value.toString();
break;
}
return str;
}
static wrapStr(start, end, str) {
return `${start}${str.join(',')}${end}`;
}
static stringify(value) {
let str = '';
const valueType = myJSON.get_type(value);
if (valueType === 'null') {
str = 'null';
} else if (valueType === 'undefined') {
str = undefined;
} else if (value.constructor === Object) {
const strs = [];
for (let key in value) {
const v = myJSON.valueToString(value[key], value.constructor);
if (v) strs.push(`"${key}":${v}`);
}
str = myJSON.wrapStr('{', '}', strs);
} else if (value.constructor === Array) {
const strs = [];
for (let item of value) {
const v = myJSON.valueToString(item, value.constructor);
if (v) strs.push(`${v}`);
}
str = myJSON.wrapStr('[', ']', strs);
} else {
str += myJSON.valueToString(value, null);
}
return str;
}
}
const test01 = {
str: 'a',
num: 1,
'undefined': undefined,
'null': null,
symbol: Symbol('test'),
boolean: true,
}
const test02 = {};
const test07 = [];
const test03 = 1;
const test04 = null;
const test05 = 'foo';
const test06 = [1, '1', true, null, undefined, Symbol(''), () => ''];
const tests = [test01, test02, test07, test03,test04,test05, test06];
function testMyJSON(v) {
try {
console.log(`==== myJSON() ====`)
console.log(myJSON.stringify(v))
console.log(`==== JSON() ====`)
console.log(JSON.stringify(v))
console.log("\n\n")
} catch (e) {
console.error(e)
}
}
tests.map(test => testMyJSON(test))