자바스크립트 요약 정리1

728x90

자바스크립트 요약 정리1


<script> 구문은 어디에 위치해있든 상관없음

 

브라우저 출력: document.write()

콘솔 출력: console.log()

입력창: prompt("...")

알림창: alert("...")

 

 

소스 작성 규칙

 

첫글자는 영문자, _, $

공백 사용 불가, 연결시에는 -, _ 가능

예약어는 식별자 사용 불가

 

 

html 특정 요소 찾기

 

document.querySelector("#id") -> #은 id 속성을 대상으로 

document.getElementById("id")

document.getElementsByname("name") -> 배열 형태로 받아짐

 

 

특정 요소에 값 할당하기

 

document.querySelector("#id").innerHTML

요소의 HTML 내용을 가져오거나 설정함 

 

document.querySelector("#id").value

input, select, textarea와 같은 양식 요소의 값을 가져오거나 설정함

 

 

자료형

자료형 확인: typeof(...)

변수에 값이 할당되지 않아도 undefined가 됨. null은 값이 없어진 상태 혹은 변수를 초기화하는 용도로 사용됨.

 

 

템플릿 문자열

 

`(백틱) 기호 사용

`...`내부에 ${함수 혹은 변수} 형태로 문자열과 함수 혹은 변수를 섞어쓸 수 있음

 

console.log(`올해는 ${new Date().getFullYear()}년 입니다.`)

 

 

형변환 특이사항

 

숫자형과 문자형을 더하면 숫자를 문자열로 인식함

곱하기나 나누기, 나머지 연산에서는 문자형 자료를 모두 숫자로 자동 인식함

 

비교 연산자 특이사항

== !== -> 두 개의 값이 같은지 같지 않은지 확인

===, !== -> 두 개의 값이 자료형까지 완벽히 같은지 아닌지 확인

 

 

연산자 우선 순위

 

 

<!DOCTYPE html>
<html lang="ko">
  <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>할인 가격 구하기</title>
    <link rel="stylesheet" href="css/bargain.css" />
  </head>
  <body>
    <div id="contents">
      <img src="images/sale.png" />
      <ul>
        <li>
          <label for="n1">첫번째 수 </label>
          <input type="text" id="n1" /><br />
        </li>
        <li>
          <label for="n2">두번째 수 </label>
          <input type="text" id="n2" />
        </li>
        <li>
          <button onclick="showPrice()">나누기 n1/n2</button>
        </li>
      </ul>
      <div id="showResult"></div>
    </div>

    <script>
      function showPrice() {
        var n1 = document.querySelector('#n1').value; // 원래 가격
        var n2 = document.querySelector('#n2').value; // 할인율

        if (!n1 || !n2) { // 하나라도 undefined, null, 빈 문자열, 0과 같은 falsy 값이면 실행됨.
          console.log(!n1);
          alert('아무것도 입력안함 다시 입력 바람');
          return;
        }

        if (isNaN(n1) || isNaN(n2)) { // NaN은 숫자가 아닌 경우. isNaN()으로 숫자 판단 가능
          console.log(n1);
          alert('숫자가 입력되지 않았습니다. 숫자를 입력하세에');
          return;
        }

        if (n2 <= 0) {
          alert('두번째 수가 0입니다. 0보다 큰 수를 입력하세요.');
        }

        var resultPrice = Number(n1) / Number(n2); // 원래 가격에서 할인 금액을 뺀 최종 가격
        // Number() : 숫자 자료형으로 변환
        document.querySelector('#showResult').innerHTML =
          'n1/n2 는 ' + resultPrice + '입니다';
      }
      // if문 삭제했습니다.
    </script>
  </body>
</html>

 

|| 연산자: bool이 아닌 자료에 이용하기

A||B에서 A가 참이면 A를, 거짓이면 B를 return

 

배열 선언 법

 

let info=[123, "홍길동", true, 19.2];

 

let info2=new Array();

info2[0]=2;

info2[3]=4;

 

* 할당 안된 인덱스에는 undefined 출력

 

 

메모리는 차지하나, 값을 전달받지 못했으므로 undefined라고 출력되는 것임. 문법적이나 실행으로는 문제가 되지 않는다는 것 알아두기.

 

undefined, NaN, null은 bool처리시에 전부 false가 됨! 호출부에서 인수를 전달하지 않은경우 undefined가 전달되므로, !count는 true가 되어서 count에 1을 할당하게 됨.

다른 방식의 예

필수적인 매개변수는 보통 맨 앞에, 생략이 상관없는 경우에는 매개변수를 뒤쪽에 두는 것이 정석

 

 

concat, join, slice는 비파괴적 메소드

 

 

array.join("구분자") : 배열안의 모든 요소를 문자열로 만들어 return하되, 구분자로 각 요소들을 구분한다.

 

slice(beginIndex, endIndex(미포함))

 

splice(startIndex, deleteCount, item1, item2 ...)

let months = ["January", "February", "Monday", "Tuesday"];
let days = months.splice(2, 2, "March", "April"); // 원본에서 요소 두 개를 제외하고 리턴, 원본에 다른 요소를 추가

console.log(days); // ["Monday", "Tuesday"]
console.log(months); // ["January", "February", "March", "April"]
let months = ["January", "February", "Monday", "Tuesday"];
months.splice(2, 0, "March"); // 두 번째 매개변수가 0이므로 기존 요소 모두 유지

console.log(months); 
// ["January", "February", "March", "Monday", "Tuesday"]

 

첫번째 매개변수는 각 요소의 값을, 두번째 매개변수는 각 요소의 인덱스가 할당된다.

let array1 = [10, 22, 34, 50, 30];
let array2 = [1, 1, 0, 0, 1];
let array3 = new Array(array1.length);	// length()가 아니라는 것에 주의!

array1.forEach((item, i) => {
  array3[i] = item * array2[i];
});

console.log(array3);

let array1 = [10, 22, 34, 50, 30];
      let array2 = [1, 1, 0, 0, 1];
      let array3 = array1.map((item, index) => {
        return item * array2[index];
      });
      console.log(array3);

반복문

 

for in : 객체 값 또는 배열 인덱스 순환
for of : 배열 값 순환

var obj = {
  a: 1,
  b: 2,
  c: 3,
};

for (let item in obj) {
  // for of의 경우 에러발생
  // item은 객체의 값
  console.log(item); // a, b, c
}

var arr = [1, 2, 3];

for (let item of arr) {
  // item은 배열의 요소
  console.log(item); // 1, 2, 3
}

for (let item in arr) {	// 0, 1, 2
  // item은 배열의 인덱스
  console.log(item);
}

 

스코프(블록): 변수 사용할 수 있는 범위

출력 결과: 3 1 2 1

호이스팅은 코드가 실행하기 전 변수선언/함수선언이 해당 스코프의 최상단으로 끌어 올려진 것 같은 현상을 말한다.

 

두 변수는 블록 범위가 다르므로 별개의 변수로 취급된다.

console.log(a)문의 실행 전에 두번째 a 변수가 TDZ(시간적 사각지대: Temporal Dead Zone)라는 영역으로 이동된다.

TDZ의 영역은 블록 범위의 시작과 let 키워드를 사용한 변수 선언 사이의 기간을 의미한다.

 

블록 시작부터 let 선언 전 줄까지의 영역

이 영역 안에서 변수에 접근하게 되는 경우 ReferenceError가 발생하게 된다. 위의 코드에서는 TDZ 영역에서 console.log(a)로 a 변수에 대해 접근하게 되었기 때문에 에러가 발생한 것이다.

따라서 코드를 다음과 같이 수정해야한다.

let a = 1;
{	
// TDZ
  let a = 2;
  console.log(a);
}

TDZ 범위 밖에서 a에 대해 접근하기 때문에 에러가 발생하지 않게 된다.

 

이처럼 TDZ 영향을 받는 구문에는 let, const, class가 있다.

이 구문들을 이용할 때에는 반드시 선언 후에 사용하도록 코드를 구성해야 한다.

 

 

  • 자바스크립트의 모든 선언에는 호이스팅이 일어난다.
  • 그런데 let, const, class를 이용한 선언문 호이스팅이 발생하지 않는 것처럼 동작한다.
  • var 키워드로 선언된 변수와는 달리 let 키워드로 선언된 변수를 선언문 이전에 참조하면 참조 에러(ReferenceError)가 발생한다.
  • 이는 let 키워드로 선언된 변수는 스코프의 시작에서 변수의 선언까지 *일시적 사각지대(Temporal Dead Zone; TDZ)에 빠지기 때문이다.

여기서 중요한 지점은 이 호이스팅이라는 용어가 ‘선언이 먼저 메모리에 저장되었다.’는 것을 의미하기 때문에 즉, ‘선언이 끌어올려진다’는 의미이기 때문에 모든 선언은 호이스팅이 일어난다는 말은 참이된다.

즉, 호이스팅이 파일의 맨 위로 끌어올려진 것 같은 현상을 의미할 때 선언문 이전에 참조해서 에러를 발생시킨다고 호이스팅이 일어나지 않은 것은 아니라는 의미이다.

애초에 호이스팅이 일어나지 않는다면 에러가 발생하지도 않을 것이다...

 

 

왼쪽 코드의 경우 caught ReferenceError: a is not defined 발생(블록 제한 에러)

 

var, function 선언은 TDZ 영향을 받지 않고 현재 스코프에서 호이스팅 된다.

 

var 변수는 선언전에 접근하면 undefined를 얻는다.

value; // => undefined
var value;

그러나 함수는 선언 위치와 상관없이 호이스팅에 의해 동일하게 호출된다.

// Works!
greet('World'); // => 'Hello, World!'
function greet(who) {
  return `Hello, ${who}!`;
}

// Works!
greet('Earth'); // => 'Hello, Earth!'

var 또한 호이스팅이 되지만 블록에 제한이 되지 않기 때문에 참조 에러가 나타나지 않는다는 문제가 있다.

따라서 블록에 제한이 되면서 참조 에러가 발생하는 let을 선호하는 것이다.

 

또한, var는 재선언이 가능하기 때문에 얘기치 못한 에러를 맞닥뜨릴 수 있다.

 

 var greeter = "hey hi";
    var times = 4;

    if (times > 3) {
        var greeter = "say Hello instead"; 
    }
    
    console.log(greeter) // "say Hello instead"

변수를 이미 정의했다는 것을 망각하고 같은 이름으로 var형 변수를 선언하게 될 수 있기 때문이다.

 

 

 

 

prompt로 입력값을 받아서 숫자는 내림차순으로, 문자는 오름차순으로 정렬하도록 출력하기.

각 요소는 ,로 구분되어야 하고 숫자, 문자 순서로 출력되어야 함.

취소를 누를 경우 입력 받았던 값을 모두 출력.

확인을 누를 경우 입력한 값을 배열에 넣고 다시 prompt를 띄움.

 

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <script>
      const inputArr = [];
      const numbers = [];
      const letters = [];

      while (true) {
        const input = prompt('배열에 값 추가.(취소 누르면 분류 시작함.)');

        if (input === null) {
          break;
        } else {
          inputArr.push(input);
        }
      }

      inputArr.forEach((item) => {
        if (!isNaN(item)) {
          // 숫자일 경우
          numbers.push(item);
        } else {
          letters.push(item);
        }
      });

      let sortedNumbers = numbers.sort((a, b) => b - a); // 내림차순, 오름차순은 a-b
      let sortedLetters = letters.sort();
      let finalArr = [sortedNumbers + sortedLetters];
      const outputElement = document.createElement('div');
      outputElement.innerText = finalArr.join(', ');
      document.body.appendChild(outputElement);
    </script>
  </body>
</html>

 

 

익명함수

함수에 이름을 붙이지 않고 생성하는 방식

let 함수 이름 = function () {};

대입 연산자는 런타임 때 실행된다. 실행 단계에서 문자처럼 저장이 되는 것이다.

익명함수도 마찬가지로 오른쪽의 연산하는 방법이 왼쪽의 리터럴 함수로 지정된 것이므로

익명함수는 런타임 때 변수에 저장되는 것으로 인지하면 된다. (핵심은 익명함수가 호이스팅이 되지 않는다는 것이다!)

* 리터럴: 변수 안에 들어있는 상태가 아니라 문자 그대로 자료를 나타내는 것 

 

익명함수는 ES6에서 화살표 함수로 사용이 가능하다.

 

 

노드 같은 개발 환경에서 화살표함수는 global객체가 리턴되는 것이 아니라 빈 객체가 리턴된다. (크롬에서는 둘 다 윈도우가 반환된다)

따라서 this를 쓸 것 같으면 웬만해서는 화살표함수말고 그냥 익명함수 양식으로 쓰는 것이 좋다.
화살표함수의 this사용에 대해서 동적으로 처리가 안되어 있기 때문이다.

 

 

선언함수

이름을 붙여서 함수를 선언하는 방식.

익명함수와 다르게 호이스팅이 된다.

function 함수 이름 () {}

 

 

익명함수는 런타임 때 생성된다고 했다. 대입이 이루어지는 순간에 생성되는 것이다.

따라서 이는 호이스팅이 되지 않음을 의미한다.

두 함수는 순서대로 실행되므로, 첫 번째 함수가 메모리에 올라갔다가 지워지고 두번째 함수가 할당되어 결국 함수 호출에 의해

2nd function이 출력된다.

 

 

먼저 선언적 함수가 호이스팅 되어 처리된다.

익명함수는 호이스팅이 안되므로 두번째로 처리된다.

마지막으로 f2()가 처리된다.

 

맨 첫째줄에 선언 없이 f2를 썼는데도 에러가 나지 않은 이유? > 선언적 함수 f2가 호이스팅 될 때 그 이름이 메모리에 먼저 올라가게 되었기 때문에 에러가 나지 않는다.

 

f2();
f2 = function () {
	console.log('f1');
};
f2();
function f2() { // 먼저 호이스팅 되었으므로 실행되지 않고 건너뜀
	console.log('f2');
}
f2(); 
//따라서 실행결과는 f2 f1 f1

맨 처음 선언적 함수 f2가 호이스팅 되므로

처음 나오는 f2();에는 f2가 출력된다.

뒤이어 익명함수 f2에 의해 다음 f2();에는 f1이 출력된다.

 

처음에 선언적 함수 f2가 호이스팅 되었기 때문에 이후에는 실행되지 않고 그냥 건너뛴다.

따라서 마지막 f2();는 f1이 그대로 출력되는 것이다.

 

출력 결과는 1st, 3이다.

먼저 선언적 함수 f2("2nd")가 호이스팅 된다.

그러나 뒤이어 나오는 익명함수가 같은 이름으로 나오기 때문에 f2에는 익명함수의 내용이 메모리에 재할당된다.

따라서 f2()에는 1st...가 출력되고, f2=3으로 재할당 한 이후의 f2는 3이 출력되는 것이다.

 

처음에 let f2가 호이스팅 되어 TDZ에 f2라는 이름이 올라간다.

선언전 함수 f2가 호이스팅 되어 메모리에 등록되려는 순간 TDZ에 이미 등록된 f2와 중복 문제가 발생한다.

* TDZ에 올라간 이름과 동일한 이름의 선언적 함수를 선언하면 에러가 발생한다.

* TDZ에 올라간 이름과 동일한 이름의 익명 함수를 선언하면 상관없다. 값이 재할당 될 것이다.

 

var 또한 호이스팅이 되지만 블록에 제한이 되지 않기 때문에 참조 에러가 나타나지 않는다는 문제가 있다.

따라서 블록에 제한이 되면서 참조 에러가 발생하는 let을 선호하는 것이다.

 

선언적 함수 f2("2nd 1st")가 호이스팅 되어 먼저 메모리에 들어간다

뒤이어 let이 호이스팅 되려는 순간, 메모리에 있는 f2와 중복 문제가 발생한다.

* 결국 TDZ는 이중 선언을 방지하는 역할을 하기도 한다.

 

언급했듯, let, const, class는 TDZ에 들어가지만 선언적 함수는 메모리에 들어가는 것이기 때문에 이중 선언을 하더라도 덮어쓰기가 일어날 뿐 문제가 일어나지 않는다.

 

* 참고로 TDZ에 들어갈 때는 이름만 들어가지만 메모리에 들어갈 때는 이름과 값까지 다 들어감.

 

선언적 함수 두개가 먼저 호이스팅 되고, 최종적으로 호이스팅 된 값으로 덮어씌워졌기 때문에 모두 2nd..가 출력된다.

 

* 호이스팅 우선 순위: 변수 선언이 함수 선언보다 우선적으로 끌어올려진다!

* var 변수 호이스팅은 이름만 메모리로 들어간다.(TDZ가 아니다.)

var s가 먼저 호이스팅 > 선언적함수 s("s1") 호이스팅 > 선언적함수 s("s2") 호이스팅

따라서 처음과 두번째 console.log(s)에는 s2가 호이스팅 된다.

 

다시 var s=10;으로 왔을 때, 이전에 변수 이름 s만 호이스팅 되었기 때문에 이번에는 값이 할당된다.

기존에 함수 s2가 10으로 재할당되므로

다음 console.log(s)에는 10이 할당된다.

console.log(s())는 에러가 발생한다. s에는 현재 함수가 아니라 변수 s의 값이 할당되었기 때문이다.

 

정리하자면, var는 호이스팅시 변수 이름만 먼저 끌어 올려지고 다시 원 위치로 코드 실행 순서가 돌아왔을 때 값이 할당된다.

 

var를 let으로 바꾼 코드이다.

변수 선언이 함수 선언보다 우선적으로 끌어올려지므로 let이 TDZ로 먼저 올라간다.

TDZ에 먼저 올라간 이름과 동일한 이름의 선언적 함수가 호이스팅되면 충돌에러가 발생한다.

따라서 위의 코드는 에러가 발생된다.

 

함수도 자료형이므로 매개변수로 전달 가능하다. 매개변수로 전달되는 함수를 콜백함수라고 한다.

 

 

 

내부함수 inner()의 결과 값이 전역 변수 a에 의해 참조가 되고 있다.

내부함수가 외부함수 내의 지역 변수 x를 참조할 수 있게 된다.

결국, 전역 변수 a가 내부함수의 결과 값을, 내부함수가 외부 함수 내의 지역 변수를 참조하게 되면서 가비지 콜렉션이 돌아가지 않아 메모리에 값이 남아있는 상태가 된 것이다.

 

클로저는 캡슐화를 하기 위해 사용된다.

 

parseInt할 수 있는 정수부분만 return. 다만, 원본이 바뀌지는 않음.
이진수로 인식해서 10진수로 바꾸라는 의미임
콜백함수를 활용한다.

 

prompt로 입력값을 받으면, 1초마다 1씩 감소하면서 0에 멈추도록 하는 예시 코드

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <script>
      function main() {
        let input = prompt('1~10 사이의 정수 입력 받기');
        input = Number(input);
        const outputElement = document.createElement('div');
        document.body.appendChild(outputElement);
        let countDown = setInterval(() => {
          outputElement.innerText = input--;
        }, 1000);
        setTimeout(() => {
          clearInterval(countDown);
        }, input * 1000);
      }
    </script>
    <button onclick="main()">입력값 받기</button>
  </body>
</html>
728x90