🔥 학습목표
- JavaScript의 정의, 실행환경에 대해 설명할 수 있다.
- 변수와 자료형에 대해 설명할 수 있다.
- 변수 keyword 종류와 그에 따른 스코프 차이를 설명할 수 있다.
- JavaSCript Deep Dive 01~07장, 09장, 13~15장 공부&정리
- 부록: CleanCode-변수 네이밍 규칙
브라우저, 서버, 모바일 개발이 가능한 멀티 패러다임 프로그래밍 언어이다.
JavaScript 코드를 실행할 수 있는 프로그램. 크롬에 내장된 v8이 대표적이다.
자바스크립트의 표준 사양인 ECMA-262. 프로그래밍 언어의 값, 타입, 객체와 프로퍼티, 함수 등 핵심 문법을 규정한다.
즉, 자바스크립트는 일반적으로
프로그래밍 언어로서 기본 뼈대를 이루는 ECMAScript와 브라우저가 지원하는 클라이언트 사이드 Web API(DOM, Canvas, XMLHttpRequest 등)를 아우르는 개념이다.
구글 v8 자바스크립트 엔진으로 빌드된 자바스크립트 런타임 환경
브라우저의 자바스크립트 엔진에서만 동작하던 자바스크립트를 브라우저 이외의 환경에서도 동작할 수 있도록 자바스크립트 엔진을 브라우저에서 독립시킨 자바스크립트 실행 환경이다.
javascript로 브라우저 뿐만 아니라 서버를 구축하고, 서버에서 JavaScript가 작동되도록 해주는 런타임 환경(플랫폼)이라고 생각하면 된다.
=> 간략: 브라우저 외부에서 자바스크립트 실행 환경을 제공한다.
웹 애플리케이션의 개발 규모와 복잡도가 상승하면서 필요에 따라 많은 패턴과 라이브러리가 출현했다. 덕분에 개발에는 많은 도움을 주엇으나 변경이 유연하면서 확장하기 쉬운 애플리케이션 아키텍처의 구축을 어렵게 했고, 필연적으로 프레임워크가 등장하게 되었다.
그 중 SPA(Single Page Application)가 대중화 되면서 Angular.js, React.js, Vue.js, Svelte 등 다양한 SPA 프레임워크/라이브러리들이 탄생했다.
- 여러 페이지를 링크로 연결하지 않기 때문에 불필요한 로드가 발생하지 않음.
- Ajax 기술을 이용하여 서버와 JSON 문자열로 데이터를 주고 받음.
- 데이터가 변경되는 부분만 바뀜. 페이지가 변할 때마다 모든 내용을 Redirect할 필요가 없음.
- JavaScript 비동기 통신 관련 기술을 기반으로 함.
🎁 SPA란?
둘 다 복합적으로 이루어진다.
sum
함수가 있다고 치자. 컴파일러 언어의 경우 sum
함수의 결과값은 미리 기계어로 번역되어 정해져 있다. 반면 인터프리터는 한 줄 씩 실행되기 때문에 sum
함수를 만날 때마다 일일히 실행한다. 함수 안에 복잡한 반복문이 있다면 모두 거쳐야 결과가 도출된다.
이러한 인터프리터의 단점을 개선하기 위해 v8 엔진이 나타나고 자바스크립트도 컴파일 과정을 거치게 되었다.
<기존의 자바스크립트>
JavaScript code → Parser → AST → Interpreter → Bytecode
<개선 된 자바스크립트>
Profiler가 등장한다. 이는 인터프리터를 관찰하며 실행 코드를 계속해서 모니터링한다. 코드 내 반복 실행되는 것이 있다면 이를 컴파일러에게 넘겨 실시간 컴파일 하고 최적화 된 Bytecode를 생성한다.
이처럼 필요할 때마다 컴파일 하는 컴파일러를 JIT(Just-In-Time)라고 한다.
🎁 Compiler? Interpreter? 자세한 내용
외부 라이브러리를 사용하지 않거나 최소한으로 사용하여 작성한 자바스크립트 코드.
<body>
의 마지막 부분에 <script>
작성을 권장.var
, let
, const
키워드를 사용한다.
🔴 주로 let, const만 사용해야 한다. (이후 설명)
var score; // undefined
위와 같이 var
변수를 선언할 시 자바스크립트에서 제공하는 원시 타입 값 undefined
가 할당 된다.(이를 암묵적인 초기화 라고 한다.)
var score = 100;
변수 선언은 선언 단계와 초기화 단계를 동시에 진행할 수도 있다. 다만 자바스크립트 엔진은 저렇게 단축 표현해도 변수 선언과 값의 할당을 2개의 문으로 나누어 각각 실행한다.
변수선언
은 소스코드가 순차적으로 실행되는 런타임 이전에 먼저 실행 (undefined로 초기화)값의할당
은 런타임에 실행console.log(score); // undefined
var score = 80; // 값의 할당
console.log(score); // 80
위 코드에서 var score
을 선언 및 할당하기도 전에 콘솔에 출력하면 에러가 뜨지 않고 undefined
를 출력한다.
바로 런타임 이전에 변수 선언과 함께 undefined로 암묵적 초기화가 발생하기 때문이다.
이렇게 변수 선언문이 코드의 선두로 끌어 올려진 것처럼 동작하는 자바스크립트 고유의 특징을 변수 호이스팅이라고 한다.
var score = 80;
score = 100;
위와 같이 값을 재할당 하면 값 80이 저장되어 있던 메모리 공간을 지우고 그 메모리 공간에 할당하는 것이 아닌, 새로운 메모리 공간을 확보하고 그 메모리 공간에 숫자 값 100을 저장한다.
그리고 기존의 80을 담고있던 메모리 공간은 score
라는 식별자를 잃게 되며 가비지 콜렉터(garbage collector)를 통해 어떤 식별자도 참조하지 않는 메모리로써 공간을 해제 당한다.
var firstName
: 카멜 케이스. 변수나 함수 이름에 사용var FirstName
: 파스칼 케이스. 생성자 함수, 클래스 이름에 사용🔴 NaN
, null
대소문자 헷갈리지 말자.
var x = '1';
console.log(+x); // 1 문자열을 숫자 타입으로 변환한다.
console.log(x); // "1" 부수 효과는 없다.
NaN === NaN // false
Number.isNaN(NaN); // true
Number.isNaN(1 + undefined) // true
Nan은 자신과 일치하지 않는 유일한 값이다.
따라서 숫자가 NaN인지 조사하려면 빌트인 함수 Number.isNaN()을 사용해야 한다.
🔵 Object.is 메서드
비교 연산자(===)는 +0과 -0을 동일하다고 판단한다. 또한 NaN과 NaN을 비교하면 다른 값이라고 한다.
보다 정확한 비교를 위해서는 Object.is 메서드를 사용한다.
Object.is(NaN, NaN); // true
조건식? 조건식이 true일 때 반환값 : 조건식이 false일 때 반환값
🔴 null
은 typeof
연산자로 확인할 시 object
데이터 타입을 반환한다. 따라서 값이 null 타입인지 확인할 때는 일치 연산자(===)를 사용해야 한다.
var x = 10;
var str = x + '';
console.log(typeof str, str); // string 10
// x 값이 변한 건 아니다.
console.log(typeof x, x) // number 10
위와 같은 방법으로도 숫자→문자열 타입 변환이 가능하다.
자바스크립트 엔진은 표현식 x + ''
을 평가하기 위해 x 변수의 숫자 값을 바탕으로 새로운 문자열 '10'을 생성하고 이것으로 '10' + ''
를 평가한다. 이때 암묵적으로 생성된 문자열 '10'
은 재할당 되지 않는다.
자신이 작성한 코드에서 암묵적 타입 변환이 발생하는지 예측 가능해야 한다. 자바스크립트 문법을 잘 이해하고 있는 개발자에게는 (10).toString() 보다 10+'' 이 더욱 간결하고 이해하기 쉽다.
=> 라고.. JavaScript DeepDive에서는 그렇게 말하는데 솔직히 나라면 몇자 더 치더라도 toString() 코드를 주욱 읽어나갈 때 가독성이 더 좋을 거 같은데.. 잘 모르겠다. 그렇다면 그런 줄 알자. 남이 쓰자면 쓰겠지만 혼자선 저렇게 안 쓸 듯.
?.
>?.
: 좌항이 null 또는 undefined일 경우 undefined
를 반환하고, 그렇지 않으면 우항의 프로퍼티 참조
를 이어간다.
var elem = null;
var value = elem?.value;
console.log(value); // undefined
var length = str && str.length;
와 같이 &&
연산자로 표현하는 방법도 있다.
허나 차이점은
&&
: 좌항 피연산자가 Falsy 값이면 무조건 우항 피연산자를 평가한다.(0이나 ''은 객체로 평가될 때도 있다.)?.
: 좌항 피연산자가 Falsy 값이더라도null
이나 undefined
가 아니면 우항의 프로퍼티 참조를 이어간다.??
: 좌항의 피연산자가 null
혹은 undefined
인 경우 우항의 피연산자를 반환하고, 그렇지 않으면 좌항의 피연산자를 반환한다.
=> 식별자가 유효한 코드 범위
스코프 체인 : 스코프가 계층적으로 연결된 것.
var
: 같은 스코프 내에서 중복 선언 허용. 함수 레벨 스코프로, 함수의 코드 블록만을 지역 스코프로 인정.let
, const
: 같은 스코프 내에서 중복 선언 비허용. 블록 레벨 스코프로, if, for, while 등의 코드블록도 지역 스코프로 인정.let
으로 선언한 변수는 "선언 단계"와 "초기화 단계" 가 분리되어 진행 된다.< 변수 호이스팅이 일어나지 않는가? >
🔴 호이스팅 일어난다.
let foo = 1; // 전역 변수
{
console.log(foo); // 초기화 되지 않은 참조 에러
let foo = 2; // 지역 변수
}
만약 호이스팅 되지 않았더라면 전역 변수에서 let이 선언&초기화 되었으므로 1
을 반환해야 한다.
하지만 스코프 내에서 호이스팅이 일어나기 때문에 코드 블록 내의 지역 변수 foo
를 별도 선언하고, 초기화 단계 실행(변수 선언문 도달) 전에 접근 했으므로 참조 에러가 나타난다.
🔴 선언과 초기화를 동시에 해야한다.
🔵 상수(변하지 않는 값)으로 사용한다.
애자일 소프트웨어 장인 정신 / 클린 코드 - 로버트 C. 마틴
" 좋은 이름을 지으려면 시간이 걸리지만 좋은 이름으로 절약하는 시간이 훨씬 더 많다. 그러므로 이름을 주의 깊게 살펴 더 나은 이름이 떠오르면 개선하기 바란다."
아래 질문에 모두 답할 수 있는 변수, 함수, 클래스 이름을 작성해라.
int d; // x
int elapsedTimeInDays; // o
int daysSinceCreation; // o
int daysSinceModification; // o
int fileAgeInDays; // o
const STATUS_VALUE = 0;
const FLAGGED = 4;
public List<int[]> getFlaggedCells() { // 1. 무얼 수행하는 함수인가?
List<int[]> flaggedCells = newArrayList<int>(); // 2. 함수가 반환하는 리스트를 어떻게 사용하는가?
for(int[] cell : gameBoard) // 3. 무슨 리스트의 원소를 뽑아오는가?
if (cell[STATUS_VALUE] == FLAGGED) // 4. gameBoard에서 0번째 값이 왜 중요하며 값 4는 무슨 의미인가?
flaggedCells.add(cell);
return flaggedCells;
}
// 한 번 더 수정
public List<Cell> getFlaggedCells() { // int 배열 대신 칸을 간단한 클래스로 만듦
List<Cell> flaggedCells = newArrayList<Cell>();
for(Cell cell : gameBoard)
if (cell.isFlagged()) // isFlagged 라는 좀 더 명시적인 함수 사용
flaggedCells.add(cell);
return flaggedCells;
}
getActiveAccount()
, getActiveAccounts
, getActiveAccountInfo()
이런 식으로 하면 어느 함수를 호출해야 하는지 헷갈린다.)l
은 절대 안 된다! - 1
이랑 헷갈리기 때문. )Customer
, WikiPage
, Account
, AddressParser
등postPayment
, deletePage
, save
등controller
, manager
, driver
를 섞어 쓰면 혼란스럽다.저 세 개가 근본적으로 어떻게 다른가?add
, 집합에 값 하나를 추가하면 insert
혹은 append
가 좋다.