JavaScript의 기본적인 문법을 살펴보는 section이다. JavaScript의 기본 지식을 접한적 없더라도 Java에 익숙하다면 낯설지 않은 정보들이 대부분이다. 다만 JavaScript에서만 독특하다고 느껴지는 부분들이 있어 해당 부분에만 📌 표시를 추가했다.
- 프로젝트명
- assets
- sripts
- vendor.js
- app.js
- styles
...
.js
: JavaScript 파일 확장자
<script>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Basics</title>
<script>
alert('This works - between script tags! ');
</script>
</head>
<head>
섹션에서 <script>
태그를 추가<script>의 source
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Basics</title>
<script src="assets/scripts/app.js"></script>
</head>
<script src="가져올 파일 명"></script>
<script/>
)를 제공하지 않는다.<body>
<header>
<h1>The Unconventional Calculator</h1>
</header>
<section id="calculator">
<input type="number" id="input-number" />
<div id="calc-actions">
<button type="button" id="btn-add">+</button>
<button type="button" id="btn-subtract">-</button>
<button type="button" id="btn-multiply">*</button>
<button type="button" id="btn-divide">/</button>
</div>
</section>
<section id="results">
<h2 id="current-calculation">0</h2>
<h2>Result: <span id="current-result">0</span></h2>
</section>
<script src="assets/scripts/vendor.js"></script>
<script src="assets/scripts/app.js"></script>
</body>
<body>
안의 코드가 실행되어 페이지가 로드 된 이후 스크립트 실행을 원하는 경우, 단순히 스트립트 코드를 body 끝부분으로 옮기면 된다.
이때, app.js
파일의 코드가 vendor.js
파일의 코드를 의존하므로, 의존되는 파일이 더 먼저 위치해야 한다. (순서가중요)
let userName = 'Max';
키워드 변수명 = 변수에 저장할 값;
// 새로운 값 할당 (let 재사용 X)
userName = 'Manu';
let
const totalUsers = 15;
// 값 변경시 예외가 발생한다.
// totalUsers = 20;
userName
userName
!= UserName
let ageGroup5
$kindOfSpecial
, _internalValue
let user_name
let 21Players
let user-b
let let
let currentResult
let currentResult = 0;
;
를 사용하는 것은 선택사항이다.const a = 1; const b = 2
+
Add two numbers-
Substract two numbers*
Multiply two numbers/
Devide two numbers%
Devide two numbers, yield remainder**
Exponentiation(제곱) (e.g. 2** 3 = 8)=
Assign value to variable+=, -=, ...
Perform calculation and re-assgin result to variable++, --
Increment/Decrement variable value & re-assign축약 연산자는 위치에 따라 반환값을 다르게 반환한다.
// number = 0 alert(++number); // 1 alert(number++); //0
'Hi'
, "Hi"
"
와 '
모두 사용 가능. 단, 하나를 선택한 이후엔 유지해야 한다. '
로 시작해서 "
로 끝낼 수 없음.)true, false
{
name: 'Max',
age: 31
}
[1, 3, 5]
${expression}
를 통해 표현식 삽입이 가능하다.${expression}
코드가 있으면, JavaScript는 호출된 표현식의 값을 텍스트의 해당 부분에 출력하도록 지시받는다.let calculationDescription = '(' + defaultResult + ' + 10) * 3 / 2 - 1';
let calculationDescription = `( ${defaultResult} + 10) * 3 / 2 - 1`;
source내 삽입되는 newline characters(\n
)은 template literal의 일부가 된다. 즉, 일반적인 문자열에서는 줄 바꿈을 위해 \n
을 따로 작성해줘야만 했지만, 백틱을 사용한 template literal 내부에서는 줄 바꿈이 그대로 적용된다.
코드상의 여분의 공란, 줄 바꿈이 모두 그대로 문자열에 적용되므로 이를 주의해 사용해야 한다. (코드의 가독성을 위해 줄을 바꾸거나 띄어쓰면 안됨)
console.log("string text line 1\n" + "string text line 2");
console.log(`string text line 1
string text line 2`);
let calculationDescription = `(${defaultResult} + 10
* 3 / 2 - 1`;
h2 태그가 적용되어 렌더링된 화면에는 들어나지 않지만, 개발자 도구에서 코드를 확인해보면 (\n
)를 사용하지 않았는데도 줄바꿈이 적용된것을 확인할 수 있다.
\
문자열 탈출\
와 결합된 특별한 의미를 갖게 됨.\n
: \
+ n
= 언어적 n이 아닌 줄바꿈의 의미를 가짐\'
: 문자 '
가 문자열을 닫는 의미가 아닌 문자로 출력되어야 함을 의미.\\
: 문자 \
를 출력.\
는 언제나 뒤의 문자를 탈출시키는 용도로 사용 되므로, 문자 출력시 앞에 \
를 하나 더 붙여줘야 한다.문자열 + 숫자
연산은, 항상 숫자를 문자열로 변환하고, 문자열을 접합시민다. 15 + '05'
= '1505'parseInt()
: 소숫점이 없는 경우parseFloat()
: 소숫점 아래가 있는 경우10
입력시 10.0
으로 구문 해석parseInt(userInput.value); // 숫자변환
.toString()
currentResult.toString() // 문자변환
숫자 & 문자열 연산
3 + '3' = '33'
+
연산자는 유일하게 문자열 접합 기능을 제공한다.- JavaScript는 모두 아래와 같은 연산을 수행할 수 있다. 산출된 값들은 모두 '숫자'이다. (문자x)
3 - '3' = 0
3 / '3' = 1
3 * '3' = 9
=undefined
이렇게 코드를 작성하면 안됨.런타임에서 변수 유형을 평가할 수 있게 해준다.
NaN
은 number 타입이다.undefined
는 별개의 특수 유형이다.null
은 특수 유형이 아니라 객체의 한 종류이다. const defaultResult = 0;
let currentResult = 0;
defaultResult = (currentResult + 10) * 3 / 2 - 1;
키워드(function) 함수명(매개변수) {
실행을 원하는 코드(함수본문)
}
function greetUser(name) {
alert('Hi ' + name);
}
greetUser('Max');
함수명(매개변수);
function add(num1, num2) {
const result = num1 + num2;
alert('The result is ' + result);
}
add(1, 2);
add(5, 5);
function add(num1, num2) {
const result = num1 + num2;
return result;
}
rerturn;
을 통해 함수 실행을 종료할 수 있다. (반환값은 없다.)// 전역
const defaultResult = 0;
let currentResult = defaultResult;
function add(num1, num2) {
// 로컬 or 블록 스코프(block scope)
const result = num1 + num2;
return result;
}
currentResult = add(1, 2);
let result;
function add(num1, num2) {
result = num1 + num2;
return result;
}
function add(num1, num2) {
const result = num1 + num2;
return result;
}
currentResult = add(1, 2);
전역적으로 정의되어 있는 변수를 함수 내부에서 지역적으로도 생성하면 어떻게 될까?
변수를 두 번 이상 선언할 수 없다. 그러나 이는 동일한 수준/ 동일한 범위에서 허용되지 않는다. 함수의 변수는 자체 범위를 갖기 때문에 JavaScript는 섀도잉이라는 작업을 수행한다.
let userName = 'Max';
function greetUser(name) {
let userName = name;
alert(userName);
}
userName = 'Manu';
greetUser('Max');
const defaultResult = 0;
let currentResult = defaultResult;
function add(num1, num2) {
currentResult = currentResult + userInput.value;
outputResult(currentResult, '');
}
addBtn.addEventListener('click', add);
addBtn.addEventListener('click', add);
add
함수가 실행되도록 하는 코드.outputResult()
가 실행되도록 함수 내부에 위치 시킨다.add()
: 함수를 호출할 때 괄호를 추가하여 코드를 실행시킨다.someButton.addEventListener('click', add());
add
: 함수를 직접 바로 실행하는 대신, 미래의 어느 시점(ex. 이벤트 발생 시)에 실행시키고 싶은 경우, JavaScript에게 함수의 이름(add
)을 제공한다.someButton.addEventListener('click', add);
= "버튼이 클릭되면 add를 실행해줘"add
)만 추가하는 경우, JavaScript는 함수 이름으로 무엇을 해야하는지 알 수 없으므로, 해당 문장은 무시된다. let someVar = 5;
add
alert('Do something else...');
// Gets input from input field
function getUserNumberInput() {}
/*
*/
function createAndWriteOutput() {
outputResult() // from vendor.js file
}
const defaultResult = 0;
let currentResult = defaultResult;
function add() {
currentResult = currentResult + parseInt(userInput.value);
outputResult(currentResult, '');
}
addBtn.addEventListener('click', add);
const defaultResult = 0;
let currentResult = defaultResult;
function add() {
const calcDescription = '${currentResult} + ${userInput.value}';
currentResult = currentResult + parseInt(userInput.value);
outputResult(currentResult, '');
}
addBtn.addEventListener('click', add);
currentResult
라는 값이 이후 변경되기 때문에, 변경되기 이전에 calcDescription
라는 변수를 먼저 선언하여 덧셈식을 저장해둔다.const defaultResult = 0;
let currentResult = defaultResult;
function add() {
const enteredNumber = parseInt(userInput.value);
const calcDescription = '${currentResult} + ${enteredNumber}';
currentResult = currentResult + enteredNumber;
outputResult(currentResult, '');
}
addBtn.addEventListener('click', add);
enteredNumber
를 새롭게 선언하여 반복되는 로직을 추출했다.const defaultResult = 0;
let currentResult = defaultResult;
function getUserNumberInput() {
return parseInt(userInput.value);
}
function add() {
const enteredNumber = getUserNumberInput();
const calcDescription = '${currentResult} + ${enteredNumber}';
currentResult = currentResult + enteredNumber;
outputResult(currentResult, '');
}
addBtn.addEventListener('click', add);
getUserNumberInput()
에게 아웃소싱했다. 이제 해당 값이 필요한 경우, 수동으로 함수를 호출하여 얻을 수 있다.const defaultResult = 0;
let currentResult = defaultResult;
function getUserNumberInput() {
return parseInt(userInput.value);
}
function add() {
const enteredNumber = getUserNumberInput();
const calcDescription = '${currentResult} + ${enteredNumber}';
currentResult = currentResult + enteredNumber;
outputResult(currentResult, '');
}
function subtract() {
const enteredNumber = getUserNumberInput();
const calcDescription = '${currentResult} - ${enteredNumber}';
currentResult = currentResult - enteredNumber;
outputResult(currentResult, '');
}
addBtn.addEventListener('click', add);
const defaultResult = 0;
let currentResult = defaultResult;
function getUserNumberInput() {
return parseInt(userInput.value);
}
function createAndWriteOutput(operator, resultBeforeCalc, calcNumber) {
const calcDescription = '${currentResult} ${operator} ${enteredNumber}';
outputResult(currentResult, calcDescription);
}
function add() {
const enteredNumber = getUserNumberInput();
const initialResult = currentResult;
currentResult = currentResult + enteredNumber;
createAndWriteOutput('+', initialResult, enteredNumber);
}
function subtract() {
const enteredNumber = getUserNumberInput();
const initialResult = currentResult;
currentResult = currentResult - enteredNumber;
createAndWriteOutput('-', initialResult, enteredNumber);
}
addBtn.addEventListener('click', add);
createAndWriteOutput()
: 매개변수를 기반으로 출력문 생성 & 출력const defaultResult = 0;
let currentResult = defaultResult;
function getUserNumberInput() {
return parseInt(userInput.value);
}
function createAndWriteOutput(operator, resultBeforeCalc, calcNumber) {
const calcDescription = '${currentResult} ${operator} ${enteredNumber}';
outputResult(currentResult, calcDescription);
}
function add() {
const enteredNumber = getUserNumberInput();
const initialResult = currentResult;
currentResult = currentResult + enteredNumber;
createAndWriteOutput('+', initialResult, enteredNumber);
}
function subtract() {
const enteredNumber = getUserNumberInput();
const initialResult = currentResult;
currentResult = currentResult - enteredNumber;
createAndWriteOutput('-', initialResult, enteredNumber);
}
function multiply() {
const enteredNumber = getUserNumberInput();
const initialResult = currentResult;
currentResult = currentResult * enteredNumber;
createAndWriteOutput('*', initialResult, enteredNumber);
}
function divide() {
const enteredNumber = getUserNumberInput();
const initialResult = currentResult;
currentResult = currentResult / enteredNumber;
createAndWriteOutput('/', initialResult, enteredNumber);
}
addBtn.addEventListener('click', add);
substractBtn.addEventListener('click', substract);
multiplyBtn.addEventListener('click', multiply);
divideBtn.addEventListener('click', divide);
진행한 연산 작업을 로그하고 해당 로그 엔티리를 배열에 저장하자
const defaultResult = 0;
let currentResult = defaultResult;
let logEntries = [];
function getUserNumberInput() {
return parseInt(userInput.value);
}
function createAndWriteOutput(operator, resultBeforeCalc, calcNumber) {
const calcDescription = '${currentResult} ${operator} ${enteredNumber}';
outputResult(currentResult, calcDescription);
}
function add() {
const enteredNumber = getUserNumberInput();
const initialResult = currentResult;
currentResult = currentResult + enteredNumber;
createAndWriteOutput('+', initialResult, enteredNumber);
logEntries.push(enteredNumber);
console.log(logEntries);
}
// ...
logEntries
배열을 추가했다.연산 작업 자체를 객체를 통해 데이터화 하여 저장해보자.
const defaultResult = 0;
let currentResult = defaultResult;
let logEntries = [];
function getUserNumberInput() {
return parseInt(userInput.value);
}
function createAndWriteOutput(operator, resultBeforeCalc, calcNumber) {
const calcDescription = '${currentResult} ${operator} ${enteredNumber}';
outputResult(currentResult, calcDescription);
}
function add() {
const enteredNumber = getUserNumberInput();
const initialResult = currentResult;
currentResult = currentResult + enteredNumber;
createAndWriteOutput('+', initialResult, enteredNumber);
const logEntry = {
operation: 'ADD',
prevResult: initialResult,
number: enteredNumber,
result: currentResult
};
logEntries.push(logEntry);
console.log(logEntries);
}
// ...
필요한 데이터를 logEntry
객체에 구조화하고, 이 객체를 배열에 저장한다.
{}
를 통해 데이터를 구조화한다.,
)로 키-값 쌍을 구분한다.;
)을 작성하면 구문 오류다.:
)으로 키/프로퍼티에 할당한다.=
)를 쓰면 구문 오류다.logEntry.operation
const worstPossibleUser = {
name = 'Max';
age = 30;
};
const defaultResult = 0;
let currentResult = defaultResult;
let logEntries = [];
function getUserNumberInput() {
return parseInt(userInput.value);
}
function createAndWriteOutput(operator, resultBeforeCalc, calcNumber) {
const calcDescription = '${currentResult} ${operator} ${enteredNumber}';
outputResult(currentResult, calcDescription);
}
function writeToLog(
operationIdentifier,
prevResult,
operationNumber,
newResult
) {
const logEntry = {
operation: operationIdentifier,
prevResult: prevResult,
number: operationNumber,
result: newResult
};
logEntries.push(logEntry);
console.log(logEntries);
}
function add() {
const enteredNumber = getUserNumberInput();
const initialResult = currentResult;
currentResult += enteredNumber;
createAndWriteOutput('+', initialResult, enteredNumber);
writeToLog('ADD', initialesult, enteredNumber, currentResult);
}
function subtract() {
const enteredNumber = getUserNumberInput();
const initialResult = currentResult;
currentResult -= enteredNumber;
createAndWriteOutput('-', initialResult, enteredNumber);
writeToLog('SUBTRACT', initialesult, enteredNumber, currentResult);
}
// ...
사칙연산 함수에서 객체 생성 로직이 중복되므로, 이를 함수로 아웃소싱했다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Basics</title>
<link
href="https://fonts.googleapis.com/css?family=Roboto:400,700&display=swap"
rel="stylesheet"
/>
<link rel="stylesheet" href="assets/styles/app.css" />
</head>
<body>
<header>
<h1>The Unconventional Calculator</h1>
</header>
<section id="calculator">
<input type="number" id="input-number" />
<div id="calc-actions">
<button type="button" id="btn-add">+</button>
<button type="button" id="btn-subtract">-</button>
<button type="button" id="btn-multiply">*</button>
<button type="button" id="btn-divide">/</button>
</div>
</section>
<section id="results">
<h2 id="current-calculation">0</h2>
<h2>Result: <span id="current-result">0</span></h2>
</section>
<script src="assets/scripts/vendor.js"></script>
<script src="assets/scripts/app.js"></script>
</body>
</html>
app.js
파일의 이벤트 리스너를 연결하기 위해서는 브라우저가 모든 HTML 코드를 구문 분석하고 렌더링한 이후에 스크립트가 실행되어야 한다. 그래야만 연결하려는 BUTTON이 존재한다. F5
버튼으로) 기록을 중지한다.index.HTML파일 하단에 스크립트 import문이 있어 모든 코드가 구문 분석 될 때까지 기다렸다가 스크립트 로딩을 시작한다. 코드가 작고 서버를 거치지 않고 로컬에서 작업하고 있기 때문에 페이지가 빠르게 로드되었지만, 만약 스크립트가 길어진다면 시간이 많이 요구된다.
이를 해결하기 위해선, 빨리 스크립트를 로드하고 구문 전체가 분석된 후 실행하도록 하면 된다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Basics</title>
<link rel="stylesheet" href="assets/styles/app.css" />
<script src="assets/scripts/vendor.js"></script>
<script src="assets/scripts/app.js"></script>
</head>
<body>
<header>
<h1>The Unconventional Calculator</h1>
</header>
<section id="calculator">
<input type="number" id="input-number" />
<div id="calc-actions">
<button type="button" id="btn-add">+</button>
<button type="button" id="btn-subtract">-</button>
<button type="button" id="btn-multiply">*</button>
<button type="button" id="btn-divide">/</button>
</div>
</section>
<section id="results">
<h2 id="current-calculation">0</h2>
<h2>Result: <span id="current-result">0</span></h2>
</section>
</body>
</html>
스크립트를 head 섹션으로 옮겼다.
스크립트 다운로드를 먼저 시작한 것은 좋으나, 스크립트를 연결할 요소가 랜더링 되기 전, 다운로드 후 바로 스크립트가 실행된다는 것이 문제점이다.
이런 경우, script의 defer 속성을 이용할 수 있다.
<!DOCTYPE html>
<html lang="en">
<head>
//...
<script src="assets/scripts/vendor.js" defer></script>
<script src="assets/scripts/app.js" defer></script>
</head>
//....
app.js
가 먼저 설치되더라도 vendor.js
가 먼저 실행된다. <script src="assets/scripts/vendor.js" async></script>
<script src="assets/scripts/app.js" async></script>
app.js
코드가 밑에 있지만, 다운로드가 먼저 된다면 vendor.js
보다 먼저 실행된다.vendor.js
가 먼저 실행됨)defer와 async는 외부 스크립트에서만 사용 가능하다. 그 외의 방식에서는 두 설정을 무시한다.
<!DOCTYPE html>
<html lang="en">
<head>
//...
<script defer>
alert('Hi!');
</script>
</head>
//....
스크립트가 HTML 파일에 포함되어 있으므로 HTML 파일 다운로드 시 사용 가능하다. 애초에 다운로드할 파일이 없어 defer, async 설정이 무시된다.
또한, 이 같은 스크립트 코드는 늘 바로 실행된다. 따라서 HTML 코드에 의존한다면 (첫번째 index.html과 같이) 함수 본문 섹션의 끝 부분으로 이동시켜야 한다.
Tip) HTML 파일에 중요하거나 긴 스크립트 파일을 포함시키는 것은 권장되지 않는다. 항상 외부 파일을 이용해 HTML 파일을 작고 집중적으로 유지해야 하며, 스크립트 수가 많아선 안된다.