[DAY 01] JS 주요 문법(1)
[1] JavaScript
[1-1] JavaScript의 탄생 배경
- 팀 버너스리가 최초의 브라우저 개발
- 넷 스케이프가 최초의 상용 브라우저인 Navigator 출시
- 이때의 웹은 HTML로만 이루어져 정적인 기능만 제공
- 이는 링크가 존재하는 워드 문서와 큰 차이가 없었음
- 프로그래밍 언어를 브라우저에 내장
- 브렌던 아이크는 10일만에 Mocha라는 언어를 만들어내고, LiveScript로 이름 변경
- Java가 큰 인기를 끌어, 마케팅 효과를 위해 JavaScript로 이름 변경
[1-2] JavaScript로 할 수 있는 것
- 초창기: 브라우저에서 단순한 DOM조작, alert, confirm 등을 사용하기 위함
- 현재: 복잡한 UI, 지도, 유튜브, 서버 개발, 모바일 앱 개발 등 가능
- 서버 개발:
node.js
,NestJs
,Express
, ⋯ - 앱 개발:
React Native
,NativeScript
,Cordva
, ⋯ - 프론트엔드 개발:
jQuery
,Backbone.js
,React
,Vue
,Angular
,i18n
,WebRTC
, ⋯
- 서버 개발:
[2] 브라우저의 동작 원리
- 통신: 서버와 브라우저의 통신
- 브라우저가 서버로 요청을 보내면, 서버는 요청에 따라 특정 값을 응답
- 이 요청은 한 번에 하나씩할 수도, 동시에 할 수도 있다.
- 렌더링: DOM이라는 객체를 화면에 그리는 것
- DOM: 통신을 통해 받은 HTML을 브라우저가 읽어서 생성됨
- DOM은 트리구조의 특징
- 스크립트 실행: 이를 통해 동적인 화면을 구성할 수 있다.
[3] 프론트엔드 개발자의 역할
- 프론트엔드 개발자: 브라우저에서 동작하는 UI 개발
- 개발 능력뿐만 아니라, 다른 직군과 협업을 위한 소통 능력이 아주 중요
- 고객과 맞닿아있는 직군이기 때문에 기획, 마케팅 영역까지
- 핵심역량 6가지
- 커뮤니케이션
- UI
- 네트워크
- 보안
- 브라우저
- 디자인
- 컴퓨터 과학 무시, CSS 안하기, 코더가 되는 것 → 절대❌
[4] 변수, 상수, 자료형, 메모리
[4-1] 변수
[4-2] 상수
const
[4-3] 자료형
Number
String
Boolean
: True or FalseObject
Array
Function
Undefined
: 선언 후, 값 대입XNull
: 변수가 비어있음
[4-4] 메모리
- 할당 → 사용 → 해제
- Garbage Collector를 통해 메모리 정리
- Garbage Collection이라는 자동 메모리 관리 알고리즘을 통해 만들어진 객체
- 사용하지 않는 메모리를 해제하는 역할
- 이것 덕분에 메모리에 대해 큰 신경 없이 편리하게 사용 가능
[4-5] 메모리 심화
- 힙에는 참조타입, 콜스택에는 원시타입이 들어간다.
- Mark and Sweep Algorithm: 닿을 수 없는 주소를 더 이상 필요없는 주소로 정의하고 지우는 알고리즘
[5] 표현식과 연산자
[5-1] 표현식
- 어떠한 결과 값으로 계산되는 식
- 원시값(숫자, 문자열, 논리값), 변수, 상수, 함수 호출 등으로 조합할 수 있다.
[5-2] 연산자
- 할당 연산자: 오른쪽 표현식을 왼쪽 피연산자 값에 할당
- 비교 연산자: 좌측 피연산자와 우측 피연산자를 비교, true or false 반환
- 산술 연산자: 덧셈, 뺄셈, 나눗셈 수행, Number 반환
- 비트 연산자: 비트를 직접 조작
- 논리 연산자: Boolean 통해 참과 거짓을 검증
- 삼항 연산자:
조건 ? 참: 거짓
- 관계 연산자: 객체에 속성이 있는지 확인
- typeof: 피연산자의 타입 반환, 문자열로 반환
[6] 흐름제어
[6-1] Control Flow
- Goto
- If / Then / Else
- 거짓으로 판단:
false, undefined, null, 0, NaN, ′′
- 거짓으로 판단:
- Switch / Case
- For / While
[6-2] Data Flow
- Stateless
- Recursion
- Pipe
[7] 배열과 객체
[7-1] 배열
- 배열 생성
const arr1 = new Array();
const arr2 = [];
const arr3 = [1, 2, 3, 4, 5];
const arr4 = new Array(5); // 5개의 빈 요소
const arr5 = new Array(5).fill(1); // [1, 1, 1, 1, 1]
const arr6 = Array.from(Array(5), function (v, k) { // [1, 2, 3, 4, 5]
retrun k + 1;
});
length
const arr = [1, 2, 3, 4, 5];
arr.length = 3; // [1, 2, 3] // 권장하지 않음
- 배열 관련 함수:
join, reverse, concat
const arr1 = [1, 2, 3, 4, 5];
const arr2 = [6, 7, 8];
arr1.join(", "); // 1, 2, 3, 4, 5
arr1.reverse(); // [5, 4, 3, 2, 1] // 원본 배열에 영향
arr1.concat(arr2); // [1, 2, 3, 4, 5, 6, 7, 8]
- 배열의 마지막 인덱스에 요소 추가/삭제하는 함수:
push, pop
const arr = [1, 2, 3];
arr.push(4); // [1, 2, 3, 4]
arr.push(5, 6, 7); // [1, 2, 3, 4, 5, 6, 7]
arr.pop(); // 7 // 삭제한 요소를 반환
arr.pop(); // 6
- 배열의 첫 인덱스에 요소 추가/삭제하는 함수:
unshift, shift
const arr = [1, 2, 3, 4, 5]
arr.shift(); // 1
arr.shift(); // 2
arr.unshift(10); // [10, 3, 4, 5]
- 배열 원소 중간에 접근:
slice, splice
const arr = [1, 2, 3, 4, 5, 6];
//2번 인덱스부터 3번 인덱스까지 자르기
arr.slice(2,4); // [3, 4] // 원본 배열에 영향X
//2번 인덱스부터 2개의 요소 삭제
arr.splice(2,2); // [1, 2, 5, 6] // 원본 배열에 영향
- 배열 순회:
for of
추천
const arr = [1, 2, 3, 4, 5, 6];
for (let i = 0; i < 5; i += 1) {
console.log(arr[i]);
}
// 이렇게 사용하기!
for (const item of arr) {
console.log(item);
}
- 배열은 객체처럼 사용 가능 (배열 타입과 객체 타입은 동일)
const arr = [1, 2, 3];
arr['key] = "value"; // 권장하지 않는 방법
console.log(arr); // [1, 2, 3, key: 'value']
arr.length; // 3 // key 값이 추가되어도 길이는 불변
// 배열은 JS에서 특수한 객체이기 때문에 배열의 길이는 내부적으로 관리
[7-2] 객체
- 객체 생성
const obj1 = new Object();
const obj2 = {};
const obj3 = { name: "김지은", age: "스물셋" };
- 객체의 값 추가/삭제
// 추가
const obj = { name: "김지은", age: "스물셋" };
obj["email"] = "[email protected]";
// { name: "김지은", age: "스물셋", email: '[email protected]' }
obj.phone = "01027143094";
// { name: "김지은", age: "스물셋", email: '[email protected]', phone: '01027143094' }
// 삭제
delete obj.phone; // { name: "김지은", age: "스물셋", email: '[email protected]' }
- key가 있는지 확인:
in
const obj = { name: "김지은", age: "스물셋" };
console.log("email" in obj); // false
console.log("name" in obj); // true
- key, value 집합 알아내기:
keys, values
const obj = { name: "김지은", age: "스물셋" };
console.log(Object.keys(obj)); // ['name', 'age']
console.log(Object.values(obj)); // ['김지은', '스물셋']
- 객체 순회하기:
for in
const obj = { name: "김지은", age: "스물셋", phone: "01027143094" };
for (const key in obj) {
console.log(key, obj[key]);
}
[8] 스코프와 클로저
[8-1] 스코프
- 유효 범위라고도 부르며, 변수가 어느 범위까지 참조되는 지를 뜻한다.
Global Scope
(전역 스코프), Local Scope
(지역 스코프)
const a = 5; // Global Scope
{
const b = 3; // Local Scope
console.log(a, b); // 5 3
}
console.log(a, b); // Error
- 여기에서
const
가 아닌 var
를 사용하면, 호이스팅 되어 변수 선언이 상단으로 올라가버려, 개발자가 예상치 못한 오류가 생길 수 있다.
[8-2] 클로저
- 함수가 선언된 환경의 스코프를 기억하여 함수가 스코프 밖에서 실행될 때에도 기억한 스코프에 접근할 수 있게 만드는 문법
- 닫힘, 폐쇄라는 뜻처럼 더 이상 외부에서 접근 불가한 영역을 클로저를 통해 접근 가능
function makeGreeting(name) {
const greeting = "Hello, "; // 지역스코프라서 함수가 종료되면 메모리에서 사라진다.
return function () {
console.log(greeting + name);
};
}
const world = makeGreeting("World!");
const jieun = makeGreeting("Ji-Eun");
// 그런데 실행 시점에 greeting이 살아있다!
world();
jieun();
[8-3] 은닉화
- 클로저를 이용하여 내부 변수와 함수를 숨길 수 있다.
- 클로저를 유용하게 사용할 수 있는 방법!
function Counter() {
let privateCounter = 0
function changeBy(val){
privateCounter += val
}
return {
increment: function() {
changeBy(1)
},
decrement: function() {
changeBy(-1)
},
value: function() {
return privateCounter
},
}
}
const counter = Counter();
console.log(counter.value()); // 0
counter.increment();
console.log(counter.value()); // 1
counter.dncrement();
console.log(counter.value()); // 0
- 위 코드의 Counter 함수를 보면, 변수와 내부 함수는 외부에서 접근 불가
- 따라서 반환된 함수로만 값을 조작할 수 있게 되어 개발자의 실수를 줄일 수 있다.
[8-4] 클로저를 잘 알아야 하는 이유
- 유용하게 사용하기 < 알기 힘든 버그를 잘 수정하기
function counting() {
let i = 0;
for (i = 0; i < 5; i += 1) {
setTimeout(function () {
console.log(i)
}, i * 1000);
}
}
counting(); // 5 5 5 5 5
Global Scope
(전역 스코프), Local Scope
(지역 스코프)const a = 5; // Global Scope
{
const b = 3; // Local Scope
console.log(a, b); // 5 3
}
console.log(a, b); // Error
const
가 아닌 var
를 사용하면, 호이스팅 되어 변수 선언이 상단으로 올라가버려, 개발자가 예상치 못한 오류가 생길 수 있다.- 닫힘, 폐쇄라는 뜻처럼 더 이상 외부에서 접근 불가한 영역을 클로저를 통해 접근 가능
function makeGreeting(name) {
const greeting = "Hello, "; // 지역스코프라서 함수가 종료되면 메모리에서 사라진다.
return function () {
console.log(greeting + name);
};
}
const world = makeGreeting("World!");
const jieun = makeGreeting("Ji-Eun");
// 그런데 실행 시점에 greeting이 살아있다!
world();
jieun();
- 클로저를 유용하게 사용할 수 있는 방법!
function Counter() {
let privateCounter = 0
function changeBy(val){
privateCounter += val
}
return {
increment: function() {
changeBy(1)
},
decrement: function() {
changeBy(-1)
},
value: function() {
return privateCounter
},
}
}
const counter = Counter();
console.log(counter.value()); // 0
counter.increment();
console.log(counter.value()); // 1
counter.dncrement();
console.log(counter.value()); // 0
function counting() {
let i = 0;
for (i = 0; i < 5; i += 1) {
setTimeout(function () {
console.log(i)
}, i * 1000);
}
}
counting(); // 5 5 5 5 5
(당당하게 1 2 3 4 5
라고 생각한 나...)
-
setTimeout의 대기시간이 끝나 콜백함수가 실행되는 시점에는 루프가 종료되어 i는 5가 되어 있다.
- 콜백함수는 클로저이기 때문에 상위 i값을 물어보고, 이미 i값은 5까지 증가했기 때문에 5가 5번 출력되는 것!
-
해결방법1: 즉시 실행 함수(
IIFE
) 이용하여 루프마다 클로저 만들기- 즉시 실행 함수: 정의되자마자 즉각적으로 실행되는 함수
function counting() { let i = 0; for (i = 0; i < 5; i += 1) { (function (number) { setTimeout(function () { console.log(number); }, number * 100); })(i); } } counting();
- 즉시 실행 함수: 정의되자마자 즉각적으로 실행되는 함수
-
해결방법2:
블록 스코프
로 해결하기(let
이용)-
let은 블록 수준 스코프이기 때문에 매 루프마다 클로저가 생성된다.
-
매 반복마다 새로운 i가 선언되고, 반복이 끝난 이후의 값으로 초기화된다.
function counting() { for (let i = 0; i < 5; i += 1) { // for 내부에 let 변수 선언한 것과 동일 setTimeout(function () { console.log(i) }, i * 1000); } } counting();
-
Author And Source
이 문제에 관하여([DAY 01] JS 주요 문법(1)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@jieun0411/데브코스-TIL-DAY01저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)