[DB연결 웹앱 JS] 1. JS / var, let, const / 연산자 / 문자열 / 함수 선언문, 함수 표현식 / 함수호출과 스택
부스트코스 스크랩, 상세한 내용은 여기!!
연산자
학습 목표
- 자바스크립트 변수 선언, 연산자 사용, Type을 이해한다.
핵심 개념
- 변수선언
- 연산자
- Type 종류
- Type 확인 방법
자바스크립트의 버전
- 자바스크립트 버전은 ECMAScript(줄여서ES)의 버전 따라 결정, 이를 자바스크립트 실행 엔진이 반영
- 버전 : ES5, ES6(ES2015)..
- ES6문법이 2018년을 중심으로 ES6를 지원하는 브라우저(파이어폭스, 크롬)가 많아져 표준으로 사용
- ES6는 ES5문법을 포함하여 하위호환성 문제 없음
- 다만 feature별로 지원하지 않는 브라우저가 있을 수 있어 조심
변수
- 변수는 var, let, const 로 선언할 수 있습니다. (var,let,const의 차이점이 궁금하다면 여기!)
var | let | const |
function-scope단위 hoisting | block-scoped 단위 hoisting | |
hoisting으로 인해 ReferenceError발생 안함 |
값 할당 전, let 변수 선언해야함 | 선언과 동시에 값 할당 |
let 선언 후, 값 할당 가능 | ||
이미 만들어진 변수이름 재선언가능 | 변수 재선언 불가 / 재할당 가능 | 변수 재선언 재할당 불가 |
- 어떤 것을 사용하는가에 의해서 scope, 즉 변수의 유효범위가 달라집니다.
- ES6이전까지는 var를 사용해서 변수를 선언할 수 있습니다.
var a = 2;
var a = "aaa";
var a = 'aaa';
var a = true;
var a = [];
var a = {};
var a = undefined;
연산자
연산자 우선순위를 표현하기 위해서는 ()를 사용하면 됩니다.
수학연산자는 +,-,*,/,%(나머지) 등이 있습니다.
그리고 논리 연산자, 관계연산자, 삼항연산자도 있습니다.
//or 연산자 활용
const name = "crong";
const result = name || "codesquad";
console.log(result);
var name = "";
var result = name || "codesquad";
console.log(result);
연산자 - 삼항연산자
간단한 비교와 값 할당은 삼항연산자를 사용할 수 있습니다.
const data = 11;
const result = (data > 10) ? "ok" : "fail";
console.log(result);
연산자 - 비교연산자
비교는 == 보다는 ===를 사용한다.
==로 인한 다양한 오류 상황이 있는데 아래 결과를 참고해봅시다.
0 == false;
"" == false;
null == false;
0 == "0";
null==undefined;
자바스크립트의 Type
자바스크립트 타입에는 다양한 것이 존재합니다.
> undefined, null, boolean, number, string, object, function, array, Date, RegExp
타입은 선언할 때가 아니고, 실행타임에 결정됩니다.
함수안에서의 파라미터나 변수는 실행될 때 그 타입이 결정됩니다.
타입을 체크하는 또렷한 방법은 없습니다.
정확하게는 toString.call 함수를 이용해서 그 결과를 매칭하곤 하는데, 문자, 숫자와 같은 자바스크립트 기본 타입은 'typeof' 키워드를 사용해서 체크할 수 있습니다.
배열은 타입을 체크하는 isArray함수가 표준으로 생겼습니다.
IE와 같은 구 브라우저를 사용해야 한다면 지원범위를 살펴보고 사용해야 합니다.
JS 비교-반복 문자열
학습 목표
- 분기, 반복문을 다룬다.
- 간단한 자바스크립트 문자열 조작(parsing)을 할 수 있다.
핵심 개념
- If
- switch
- for
- while
- String replace메서드
팁. 자바스크립트의 구현방법에 따라 (for 가 빠를까 while 빠를까? 등) 성능차이는 그리 크지 않습니다. 일반적으로는 코드의 가독성에 좀더 우선집중하는 게 좋습니다.
비교문
if , else if, else 를 통해서 다양한 비교문을 사용할 수 있습니다.
분기 - switch
로직을 분기하기 위해서 if문 이외에도 switch 문을 통해서도 해결할 수 있습니다.
반복
for 문이나 while문을 사용해서 반복문을 구현할 수 있습니다.
function howMany(selectObject) {
var numberSelected = 0;
for (var i = 0; i < selectObject.options.length; i++) {
if (selectObject.options[i].selected) {
numberSelected++;
}
}
return numberSelected;
}
배열의 경우 forEach와 같은 메서드도 있고, for-of를 통한 탐색도 자주 사용됩니다.
(for-in은 객체를 탐색할때 사용합니다)
forEach와 같은 메서드의 사용법이 익숙하지 않다면, 우선은 for문으로 배열을 탐색하는 것으로 충분합니다.
문자열 처리
자바스크립트의 문자와 문자열은 같은 타입으로 모두 문자열입니다.
typeof "abc"; //string
typeof "a"; //string
typeof 'a'; //string. single quote도 사용가능.
문자열에 다양한 메서드가 있습니다.
"ab:cd".split(":"); //["ab","cd"]
"ab:cd".replace(":", "$"); //"ab$cd"
" abcde ".trim(); //"abcde"
함수
학습 목표
- 자바스크립트의 선언방식들과 그 차이점, 반환값, hoisting을 이해한다.
핵심 개념
- Function
- Hoisting
- arguments
- 기본 반환값 (undefined)
함수 선언문
함수는 여러 개의 인자를 받아서, 그 결과를 출력. 파라미터의 개수와 인자의 개수가 일치하지 않아도 오류 없음.
만약, 파라미터 1개가 정의된 함수를 부를 때, 인자의 개수를 0개만 넣어 실행하면, 이미 정의된 파라미터(매개변수)는 undefined 값 가짐. 이는 변수는 초기화됐지만, 값이 할당되지 않았기 때문.
또한 매개변수와 인자 값의 개수가 일치 하지 않아도 오류 발생하지 않음. 다만 매개변수의 갯수에 맞게 인자 값 매핑.
// 함수 선언문
// 함수의 호출. firstname인자는 내부적으로 undefined라고 할당이 됨
function printName(firstname) {
var myname = "jisu";
return myname + " " + firstname;
}
위와 같은 형식의 함수 선언코드는 함수선언문이라고 합니다.
함수 표현식과 달리 함수 호출이 함수 선언보다 더 빨라도 오류없이 잘 실행된다. 왜냐하면 함수 내에서는 함수 선언문을 함수로 인식하기 때문.
그런데 JS는 한 라인씩 해석되는데 왜 그럴까라고 생각할 수 있다. 사실 JS는 함수가 한번 실행될 때 첫 번째 함수가 실행되기전, 파서가 함수안의 코드를 한번 훑는데 이때, 무엇이 변수고 함수인지를 모두 다 모아서 기억,선언하기에 함수 호출보다 함수 선언이 코드 아래쪽에 있어도 모두 다 끌어올리게 되어있는것. 즉, 함수 안에 있는 변수들을 모두 끌어올려서 선언한다. 이를 hoisting이라고 부른다.
하단을 예시로 설명하자면,
function printName(firstname) {
var result = inner();
console.log("name is " + result);
// 함수 선언문이 호출보다 밑에 존재
function inner() {
return 'inner!!!';
}
}
printName();
function printName(firstname) {
// JS파서가 한번 훑어서 함수 선언문의 함수 전체를 위로 당겨서 인식한뒤 printName함수를 동작시킨다.
function inner() {
return 'inner!!!';
}
var result = inner();
console.log("name is " + result);
}
즉, 함수선언을 함수호출보다 먼저 작성한 것과 같은 것이 된다.
arrow function (es6에 추가된 함수 선언문)
ES2015에는 arrow function 추가
간단하게 함수를 선언할 수 있는 문법으로 점점 많이 사용되고 있는 syntax이므로 같이 알아두어도 좋을 것 같습니다.
function getName(name) {
return "Kim " + name ;
}
//위 함수는 아래 arrow함수와 같다.
var getName = (name) => "Kim " + name;
함수 표현식
변수값에 함수 표현식을 담아 놓은 것을 의미한다. 함수는 하단의 printName의 익명함수처럼 표현 가능. 이렇게 표현하면 함수선언문과 달리 선언과 호출순서에 따라서(함수 선언보다 더 빨리 함수를 호출한 경우, 아직 순서상 선언되지 않은 함수는 undefined되기 때문) 정상적으로 함수가 실행되지 않을 수 있다. 함수 표현식으로 작성을 하게 되면 파서가 함수 코드를 한 번 훑었을 때, var result(변수)만을 위로 끌어올려서 인식하기에 함수란 것을 모른다. 반면 함수 선언문으로 작성한 function printName()은 function printName()라는 함수통쨰로 끌어올려서 인식하기에 함수란 것을 안다.
// 정상적으로 실행됨
function printName(firstname) {
//함수 표현식 : 변수값에 함수 표현식을 담아 놓은 것
var inner = function() {
return 'inner!!!';
}
var result = inner();
console.log("name is " + result);
}
printName();
// 오류 발생
function printName(firstname) {
var result = inner();
console.log("name is " + result);
//함수 표현식이 함수 호출보다 아래에 있으므로 오류발생
var inner = function() {
return 'inner!!!';
}
}
printName();
Tip.
함수 표현식보다 함수 선언문을 더 자주 사용하지만, 어떤 코딩컨벤션에서는 함수 표현식을 권장하기도 합니다.
어떤 컨벤션을 갖던지 한가지만 정해서 사용하는 게 좋습니다.
함수 - 표현식과 호이스팅
앞선 코드에서, printName이 오류("printName이 is not defined")가 나오지 않고, function이 아니라고 나온 이유는 printName이 실행되는 순간 'undefined'으로 지정됐기 때문.
함수 안에 있는 변수들을 모두 끌어올려서 선언한다고 해서, 이를 hoisting이라고 합니다.
따라서 아래 코드 역시 함수를 값으로 가지지만 어쨌든 printName도 변수이므로 끌어올려지고, 값이 할당되기 전에 실행됐으므로 undefined가 할당된 상태입니다.
printName(); //아직, printName이 undefined으로 할당된 상태다.
var printName = function(){}
printName이라는 변수가 존재하고 아직 값이 할당되기 전이므로 printName에는 'undefined'이라는 기본 값이 할당된 셈입니다.
함수 - 반환값과 undefined
아래 함수의 반환값은 무엇일까요?
function printName(firstname) {
var myname = "jisu";
var result = myname + " " + firstname;
}
정답은 undefined입니다.
- 자바스크립트 함수는 반드시 return값이 존재
- 없을 때는 기본 반환값인 'undefined'가 반환
- 자바스크립트에서는 void 타입이 없습니다.
함수 - arguments 객체
- 함수가 실행되면 그 안에는 arguments라는 특별한 지역변수가 자동 생성
- arguments의 타입은 객체
- 자바스크립트 함수는 선언한 파라미터보다 더 많은 인자를 보낼 수도 있습니다.
- 이때 넘어온 인자를 arguments로 배열의 형태로 하나씩 접근할 수가 있습니다.
- arguments는 array like이지만 배열타입은 아닙니다. 따라서 배열의 메서드를 사용할 수가 없습니다.
// arguments
function a() {
// 이 함수가 arguments의 개수 체크하는게 굉장히 중요한 역할을한다.
// 현재 console.log에 arg[2]를 입력했는데 만약 인자값으로 [2]에 해당되는 값이 없다면 반환값이 없어짐
// arg는 필요한 경우, 체크를 할 때 쓰는 것이지 지금처럼 코드에서 짜면 의모를 몰라.
// 특히 인자값이 바뀌는 경우, 변경되는 경우 약한 코드가 되는 것이 arguments
// arguments를 수정시켜서 값을 바꾸는 것도 좋지 않은 방법
if(arguments.length < 3) return ;
console.log('my name is ', arguments[2]);
}
a(1,2,"JB");
이 함수가 arguments의 개수 체크하는게 굉장히 중요한 역할을한다.
현재 console.log에 arg[2]를 입력했는데 만약 인자값으로 [2]에 해당되는 값이 없다면 반환값이 없어짐
arg는 필요한 경우, 체크를 할 때 쓰는 것이지 지금처럼 코드에서 짜면 의모를 몰라.
특히 인자값이 바뀌는 경우, 변경되는 경우 약한 코드가 되는 것이 arguments
arguments를 수정시켜서 값을 바꾸는 것도 좋지 않은 방법
< 함수 호출 스택 call stack >
함수 호출
자바스크립트 함수 호출은 이렇게 불려집니다.
이 함수를 실행해보세요.
run이 호출되고 그 다음에 printName이 호출됩니다.
// 함수의 호출.
function printName(firstname) {
var myname = "jisu";
return myname + " ," + firstname;
}
function run(firstname) {
firstname = firstname || "Youn";
var result = printName(firstname);
console.log(result);
}
함수호출과 stack
아래 그림을 마우스로 클릭해서, 내용이 변경되는 것을 차분히 이해해보세요.
한 번에 보기 어렵다면 여러 번 돌려보며 이해해보세요.
함수 호출 관계는 다음과 같습니다.
bar() → foo()
메모리에서는 우측의 Call Stack에서와같이 순서대로 쌓이게 됩니다.
bar 함수에서 foo를 호출한 후 foo 함수의 결과를 받아올 때까지 bar함수는 메모리 공간에서 사라지지 못하고 기다리고 있는 것이죠.
이를 당연히 생각할 수 있습니다.
foo의 경우에는 실행이 끝나고 return문이 실행되면 메모리 공간에서 사라집니다.
다시 말해서 Call Stack에서 없어지는 것이죠.
call stack은 이렇게 동작하지만, 함수를 연속적으로 계속 호출하면 call stack이 꽉 차버리면서 더 실행되지 못하고 오류가 발생할 겁니다.
브라우저에서는 대부분 지정된 횟수만큼만 call stack을 쌓게 미리 설정해둔 경우가 많다고 합니다.
따라서 혹시 개발 중에 Maximum call stack size exceeded 오류를 발견해도 너무 놀라지 말고, 대처하도록 하세요.
참고 자료
[참고링크] Understanding Javascript Function Executions — Call Stack, Event Loop , Tasks & more