js 공부 2024.05.03
과제
- 04-19일에 포스팅한 과제를 검사맡음.
- 제출형식이 index.html과 style.css였던 이유는 nginx와 apache에서 인식해서 문서를 웹처럼 띄어주기 때문.
- []_[] 사이에 넣는게 아니었음 이메일 보낼때
- 04-26 오전 9시까지면 적어도 한시간 전에 보냈어야함. (일단 나는 아님)
- 형식 지정해준거 틀 벗어나서 보내지 않기.
타입스크립트
타입스크립트(TypeScript)는 자바스크립트(JavaScript)의 확장 언어로, 마이크로소프트에서 개발하여 2012년에 출시. 이 언어의 주요 목적은 자바스크립트의 한계를 극복하고, 특히 대규모 애플리케이션의 개발과 유지 보수를 용이하게 하는 데 있다. 타입스크립트의 핵심 특징과 탄생 배경을 요약하면 다음과 같다:
- 정적 타입 검사: 타입스크립트는 변수, 함수의 매개변수, 객체의 속성 등에 타입을 명시적으로 선언하여, 코드 작성 시 타입 오류를 미리 감지하고 수정할 수 있게 함으로써, 버그를 줄이고 코드 품질을 향상시킴.
- 클래스 및 인터페이스 지원: 객체 지향 프로그래밍을 통해 코드의 재사용성을 높이고, 유지 보수를 용이하게 한다. 이는 코드의 구조를 체계적으로 관리할 수 있게 도움.
- 모듈 지원: 코드를 모듈화하여 재사용 가능하고 관리하기 쉬운 구조로 작성할 수 있다, 이는 대규모 프로젝트 관리에 큰 이점을 제공한다.
- 도구의 지원 강화: 정적 타입 정보를 활용해 개발 도중에 더 나은 자동 완성, 코드 탐색 및 리팩토링을 지원한다.
- 자바스크립트의 진화에 대응: 최신 ECMAScript 표준을 지원하며, 자바스크립트로 컴파일되므로 모든 자바스크립트 환경에서 실행할 수 있다.
타입스크립트는 자바스크립트의 유연성은 유지하면서도, 정적 타이핑과 강력한 도구 지원을 통해 개발자가 더 크고 복잡한 시스템을 효과적으로 구축할 수 있도록 도움. 이로 인해 대규모 개발 프로젝트와 팀에서의 협업이 훨씬 효율적이고 효과적으로 이루어질 수 있다.
배열
python에서는 list라고 하면 js에서는 array라고함
const
python에서 튜플이 존재하는 이유는 불변이 필요한 자료가 있기 때문.
마찬가지로 js에서도 변하지 않기를 원하기 때문에 const가 존재 하지만 배열안의 값을 변경하는건 가능. 다시 전체를 만드는건 불가능.
예시 :
1
2
3
4
5
6
7
8
9
10
11
12
13
// `const`로 배열을 선언
const numbers = [1, 2, 3, 4, 5];
// 배열의 요소 변경하기 - 가능
numbers[0] = 10; // numbers는 이제 [10, 2, 3, 4, 5]
// 배열에 요소 추가하기 - 가능
numbers.push(6); // numbers는 이제 [10, 2, 3, 4, 5, 6]
// 하지만 numbers 자체를 다른 배열이나 다른 값으로 재할당하는 것은 불가능
// numbers = [7, 8, 9]; // 이 코드는 에러를 발생시킵니다. TypeError: Assignment to constant variable.
console.log(numbers); // 출력: [10, 2, 3, 4, 5, 6]
바뀌는 이유
const가 변수에 할당된 데이터의 주소를 고정하지만, 그 데이터의 내부 상태는 고정하지 않기 때문.
복사
이 이미지에서 보이는 것처럼, JavaScript에서 배열이나 객체를 다른 변수에 할당하면, 실제 데이터의 복사본이 생성되는 것이 아니라 해당 데이터의 참조(주소)가 복사된다. 따라서 cc
변수는 원래의 배열 aa
와 같은 메모리 위치를 가리키고 있기 때문에, cc
를 수정하면 aa
도 영향을 받게 됨. 이를 “얕은 복사(shallow copy)”라고 한다.
얕은 복사의 문제점
얕은 복사는 원본 배열이나 객체의 참조가 그대로 복사되므로, 복사된 변수를 통한 데이터 수정이 원본에도 영향을 미치게 된다. 이는 데이터 무결성 문제를 일으킬 수 있으며, 예상치 못한 버그를 발생시킬 수 있다.
깊은 복사(Deep Copy)
원본의 완전한 복사본을 만들기 위해서는 “깊은 복사(deep copy)”가 필요하다. 깊은 복사는 원본 객체의 실제 내용을 새로운 메모리 위치에 복제하여, 원본과 복사본이 서로 독립적이 되도록 함.
깊은 복사를 위한 방법
JSON 메소드 사용
1
var cc = JSON.parse(JSON.stringify(aa));
이 방법은 간단하고 효과적이지만, 메소드, undefined, symbol, 함수 등 일부 데이터 타입이나 순환 참조는 올바르게 복사되지 않을 수 있다.
lodash 라이브러리 사용Lodash 라이브러리의
cloneDeep
메소드는 다양한 타입과 복잡한 객체 구조를 정확하게 복사할 수 있다.1 2
var lodash = require('lodash'); var cc = lodash.cloneDeep(aa);
자바스크립트 라이브러리
immer
Immer 라이브러리는 불변성을 유지하면서 데이터 구조를 쉽게 수정할 수 있게 해주며, 깊은 복사와 유사한 방식으로 작동한다.
사용 추천
단순한 배열이나 객체라면 JSON 메소드를 사용할 수 있지만, 함수나 순환 참조가 포함된 복잡한 객체를 다룰 때는 lodash
의 cloneDeep
같은 라이브러리가 나을 수 있음.
컨벤션
js
1
let str = 'sss';
html
1
<div id="playerBox">
html이 큰따옴표를 써서 js에서 작은 따옴표를 쓴다.
명시적 타입 변환
명시적 타입 변환(explicit type conversion)이란, 개발자가 의도적으로 특정 자료형을 다른 자료형으로 명시적으로 변환하는 것을 말함. JavaScript에서는 다양한 내장 함수를 통해 이러한 변환을 수행할 수 있다.
주요 타입 변환 함수
- Number()
- 어떤 값이든 숫자로 변환. 숫자로 변환할 수 없는 값은
NaN
을 반환. - 예:
Number("123")
결과는123
Number(true)
결과는1
,Number(false)
결과는0
- 어떤 값이든 숫자로 변환. 숫자로 변환할 수 없는 값은
- String()
- 주어진 값을 문자열로 변환함.
- 예:
String(123)
결과는"123"
- Boolean()
- 주어진 값을 불리언 값으로 변환함.
0
,null
,undefined
,NaN
,""
(빈 문자열)은false
가 되고, 그 외의 모든 값은true
가 된다. - 예:
Boolean(1)
결과는true
- 주어진 값을 불리언 값으로 변환함.
- parseInt()
- 문자열을 정수로 변환함. 문자열이 숫자로 시작하지 않으면
NaN
을 반환. - 예:
parseInt("123px")
결과는123
- 예:
parseInt("abc123")
결과는NaN
(문자로 시작)
- 문자열을 정수로 변환함. 문자열이 숫자로 시작하지 않으면
- parseFloat()
- 문자열을 부동 소수점 숫자로 변환함. 문자열이 숫자로 시작하지 않으면
NaN
을 반환. - 예:
parseFloat("3.14")
결과는3.14
parseFloat("123.45.67")
결과는123.45
(두 번째 점에서 파싱 중단)
- 문자열을 부동 소수점 숫자로 변환함. 문자열이 숫자로 시작하지 않으면
toFixed() 메소드
Number.prototype.toFixed(digits)
메소드는 숫자를 고정된 소수점 자릿수의 문자열로 변환함.- 예:
(1).toFixed(2)
결과는"1.00"
—1
을 소수점 둘째 자리까지 표현한 문자열
예시와 사용법
parseInt
와parseFloat
은 주로 웹에서 입력받은 데이터를 숫자로 변환할 때 사용된다. 이들 함수는 문자열에서 시작하는 숫자를 추출하여 숫자 타입으로 변환하며, 숫자가 아닌 문자를 만나는 즉시 파싱을 멈춘다.Number()
함수는 더 엄격하게 변환을 시도하며, 변환할 수 없는 형식의 문자열은NaN
을 반환.toFixed()
는 숫자의 표현을 통제할 때 유용하며, 특히 금융 계산 결과를 사용자에게 보여줄 때 소수점 이하 자릿수를 정확하게 제어할 수 있다.
이러한 명시적 타입 변환은 데이터 유효성 검사, 사용자 입력 처리, 데이터 형식 조정 등 다양한 상황에서 중요하게 사용된다. 사용자로부터 입력받은 데이터를 적절한 형식으로 변환하거나, API로부터 받은 데이터를 애플리케이션에서 사용하기 적합한 형태로 조정할 때 필수적.
js언어의 모순
이 이미지에서 보이는 JavaScript의 예들은 JavaScript의 타입 변환(type coercion)과 진리값 평가(truthy와 falsy 값)에 대한 규칙을 보여준다. JavaScript는 유연한 타입 변환 규칙을 가지고 있지만, 이로 인해 때때로 예상치 못한 결과가 발생할 수 있으며, 이는 종종 언어의 모순으로 여겨진다.
예시 분석
Boolean('1')
결과는true
- JavaScript에서 비어 있지 않은 문자열은 모두
true
로 평가된다. 이 규칙은1
,"hello"
등 모든 비어 있지 않은 문자열에 적용.
- JavaScript에서 비어 있지 않은 문자열은 모두
Boolean('0')
결과는true
'0'
이라는 문자열은 비어 있지 않기 때문에true
로 평가된다. 이는 종종 혼란을 일으킬 수 있는데, 숫자0
은false
로 평가되기 때문.
'0' == 0
결과는true
- JavaScript에서는
==
연산자가 느슨한 비교를 수행. 이 경우, 문자열'0'
과 숫자0
이 같다고 평가된다. JavaScript는 먼저 문자열'0'
을 숫자0
으로 타입 변환한 후 비교를 수행.
- JavaScript에서는
Boolean(0)
결과는false
- 숫자
0
은 falsy 값. JavaScript에서는0
,NaN
,null
,undefined
, 빈 문자열(""
), 그리고 불리언false
가 falsy 값으로 평가되어 조건문 등에서false
로 처리된다.
- 숫자
모순과 혼란의 원인
- 데이터 타입의 자동 변환: JavaScript는 자동으로 데이터 타입을 변환(
==
사용 시). 이 자동 변환은 코드를 간결하게 작성할 수 있도록 돕지만, 예측하지 못한 버그의 원인이 되기도 함. - Truthy와 Falsy 값: 특정 값이
true
또는false
로 평가되는 규칙은 초보자에게 혼란을 줄 수 있다. 특히,'0'
과 같은 비어 있지 않은 문자열이true
로 평가되는 것은 직관적이지 않을 수 있다.
이러한 모순을 해결하기 위해 많은 개발자들은 엄격한 비교 연산자 ===
를 사용하여 타입 변환 없이 값을 비교하는 방법을 선호함. 이 방법은 타입을 명확하게 유지하고 예상치 못한 결과를 방지하는 데 도움이 된다.
반복문
for vs for in vs for of
1. 일반 for
루프
개념: 가장 전통적인 루프 형태로, 인덱스를 기반으로 순회를 제어한다. 시작점, 종료 조건, 증감식을 명시적으로 지정한다.
예제:
1
2
3
4
var fruits = ['apple', 'banana', 'cherry'];
for (var i = 0; i < fruits.length; i++) {
console.log(fruits[i]);
}
장점: 인덱스를 사용하여 배열 요소에 접근하므로, 인덱스를 활용한 복잡한 조건이나 역순 순회 등이 필요할 때 유용하다.
2. for-in
루프
개념: 객체의 모든 열거 가능한 속성을 순회함. 배열에 사용할 경우 인덱스를 문자열 형태로 반환하지만, 일반적으로 객체의 속성을 순회할 때 사용됨.
예제:
1
2
3
4
var person = {firstName: "John", lastName: "Doe", age: 30};
for (var key in person) {
console.log(key + ': ' + person[key]);
}
주의점: 배열을 순회할 때 for-in
루프는 배열의 프로토타입 체인 상의 속성까지 순회할 수 있으므로, 보통 배열보다는 객체 속성을 순회할 때 사용함.
3. for-of
루프
개념: ES6에서 도입된, 컬렉션 전용의 루프로서, Array
, Map
, Set
, String
등과 같은 이터러블 객체의 요소들을 순회함. for-in
과 달리 값 자체를 반환한다.
예제:
1
2
3
4
var fruits = ['apple', 'banana', 'cherry'];
for (var fruit of fruits) {
console.log(fruit);
}
장점: 배열뿐만 아니라 모든 이터러블 객체에 대해 값을 바로 가져올 수 있어서 코드가 간결하고 읽기 쉽다. 이터레이션 프로토콜을 따르는 모든 데이터 구조에 일관성 있게 사용될 수 있음.
요약 및 차이점
- 일반
for
루프: 인덱스를 통한 접근 및 제어가 가능하며, 복잡한 순회 조건을 설정할 수 있다. for-in
루프: 주로 객체의 속성을 순회할 때 사용되며, 배열보다는 객체에서 사용하는 것이 적합함.for-of
루프: 이터러블 객체의 값을 직접 순회할 수 있어 간단하고 효율적이다. 배열과 같은 컬렉션을 순회할 때 가장 깔끔하고 적합한 방법을 제공함.
메서드
forEach
1
2
3
4
5
6
7
var fruits = ['apple', 'banana', 'cherry'];
var cb = function(params) {
console.log(params);
}
fruits.forEach(cb);
코드 설명
- 배열 선언
var fruits = ['apple', 'banana', 'cherry'];
fruits
라는 이름의 변수에 사과, 바나나, 체리를 요소로 하는 배열을 선언.
- 콜백 함수 선언
javascriptCopy codevar cb = function(params) { console.log(params); }
cb
라는 이름의 변수에 함수를 할당. 이 함수는 매개변수params
를 받아서, 그 값을 콘솔에 출력.
- forEach 메서드 사용
fruits.forEach(cb);
fruits
배열의 각 요소에 대해cb
함수를 실행.forEach
는 배열의 각 요소를 차례로cb
함수의 인자로 전달하고,cb
함수는 받은 인자를 콘솔에 출력.
실행 결과
이 코드를 실행하면, 콘솔에 다음과 같이 출력:
1
2
3
apple
banana
cherry
메서드 축약 (화살표함수)
1
2
3
4
5
function fl(a) {
console.log(a);
}
f1('aaa');
출력 : aaa
1
2
var f2 = (a) => {console.log(a);}
f2('bbb')
출력 : bbb
1
2
var f3 = () => { console.log("ccc");}
f3();
출력 : ccc
1
2
3
var fruits = ['apple', 'banana', 'cherry'];
fruits.forEach((item) => console.log(item));
출력 :
apple
banana
cherry
forEach안에 함수가 들어갈 수 있는데 그 안에 화살표함수를 만들어서 짧게 가능. 파이썬의 람다같은듯?
Array
파이썬에는 push가 append임
list.append는 1991년(파이썬 초기)에 고안된 반면, pop은 그 1997년에 고안됐기 때문.
파이썬 창시자인 Guido도 pop에는 push가 더 적절하다고 생각했지만 같은 일을 하는 메소드를 다르게 명명하는걸 원치 않았기 때문에 append가 계속 살아남음.
To implement a stack, one would need to add a list.pop() primitive (and no, I’m not against this particular one on the basis of any principle). list.push() could be added for symmetry with list.pop() but I’m not a big fan of multiple names for the same operation – sooner or later you’re going to read code that uses the other one, so you need to learn both, which is more cognitive load.
예제 코드 :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
var comments = ["짬뽕", "국밥", "수육"];
// 사용자의 입력을 리스트에 추가하는 함수
function wComments(params) {
// 사용자가 입력한 내용을 DOM을 통해 가져옵니다.
const comment = document.getElementById("input").value;
// 가져온 내용을 리스트에 추가합니다.
comments.push(comment);
// 변경된 리스트를 화면에 그립니다.
drawList();
}
// 리스트를 화면에 그리는 함수
function drawList() {
let html = "";
// 리스트의 각 요소를 순회하며 HTML에 추가합니다.
for (var i = 0; i < comments.length; i++) {
// 템플릿 리터럴을 사용하여 HTML에 버튼과 함께 리스트를 추가합니다.
html += `<li>${comments[i]}<button onclick="modifyComment(${i})">E</button><button onclick="deleteComment(${i})">x</button></li>`;
}
// 그려진 HTML을 comments라는 id를 가진 요소에 설정합니다.
const cmtListEl = document.getElementById("comments");
cmtListEl.innerHTML = html;
}
// 삭제 함수
function deleteComment(idx) {
// 사용자에게 확인 메시지를 보여주고, 확인 시에만 삭제 작업을 수행합니다.
if (!confirm("지울까요?")) {
return;
}
// 배열에서 해당 인덱스의 요소를 삭제합니다.
comments.splice(idx, 1);
// 변경된 리스트를 다시 그립니다.
drawList();
}
// 수정 함수
function modifyComment(idx) {
// 사용자로부터 수정할 내용을 입력 받습니다.
var text = prompt('수정할 내용', comments[idx]);
// 입력이 없을 경우 수정을 취소합니다.
if (!text) {
return;
}
// 해당 인덱스의 요소를 새로운 내용으로 교체합니다.
comments[idx] = text;
// 변경된 리스트를 다시 그립니다.
drawList();
}
// 초기 리스트를 화면에 그립니다.
drawList();
continue & break
continue
와 break
문은 JavaScript에서 흔히 사용되는 제어 구조 중 하나로, 반복문의 흐름을 제어하기 위해 설계됨. 그러나 이들은 함수 범위 내에서는 사용될 수 없다. 그 이유는 이 구문들의 동작 범위와 목적이 반복문에 한정되어 있기 때문.
continue
문
- 목적: 현재 반복을 건너뛰고, 반복문의 다음 순회(iteration)를 진행하게 함.
- 사용 범위:
for
,while
,do...while
반복문 내에서만 사용할 수 있다.
break
문
- 목적: 반복문을 완전히 종료하고, 반복문 다음의 코드 실행을 시작함.
- 사용 범위:
for
,while
,do...while
반복문 내에서, 그리고switch
문 내에서 사용할 수 있다.
함수 내에서 continue
와 break
사용 불가의 이유
- 함수의 흐름 제어: 함수는 반환(return)을 통해 흐름을 제어함.
return
문은 함수의 실행을 중단하고, 선택적으로 값을 함수 호출자(caller)에게 반환함. 이는 함수의 실행을 ‘중단’하는 역할을 하지만,break
와continue
처럼 반복문 내의 흐름을 제어하는 것은 아니다. - 구문의 역할 구분:
continue
와break
는 명시적으로 반복의 흐름을 제어하는 구문. 함수 내에서 이러한 키워드를 사용하려는 시도는 반복문의 특정 반복을 건너뛰거나 중단하는 것이 아니라, 함수 자체의 흐름을 제어하려는 것으로 간주될 수 없기 때문에 JavaScript 언어 사양에 의해 허용되지 않는다.
적절한 사용 예
함수 내에서 반복문을 사용하는 경우, continue
와 break
는 해당 반복문의 흐름을 제어하는 데에만 사용될 수 있다. 함수의 전체 흐름을 중단하거나 반환하려면 return
문을 사용해야 함. 예를 들어, 함수 내에서 특정 조건을 만족하는 경우 함수 실행을 중단하고 싶다면, return
문을 사용하여 바로 종료할 수 있다.
예시 :
정규식으로 문자 치환
todo & music
todo
music
해야할거
- 분수의 뺄셈 덧셈 나눗셈 곱셈 하는 프로그램 만들기 (배운언어들로(?))