📝 JavaScript 기초 강좌 기록 (상)
서론
3주 차(1)가 밝았다! ☀️
(상) 편은 1강부터 9강까지의 강의를 듣고 새롭게 알거나 잘못 알고 있었던 것 등 정보들을 기록했다.
자바스크립트의 역사
자바스크립트의 역사는 ECMAScript 문서의 등장부터 흥미로워진다. (ECMAScript : 언어의 문법적인 사항들을 정리해 둔 문서)
1997년 초판을 시작으로 1년마다 새 판이 출판되다가 2000년도 당시 점유율 95%를 차지하던 IE, 마이크로소프트사가 표준안 참가를 거부하게 되면서 표준안 작업이 더뎌지게 된다.
그러던 와중 2004년 모질라 사에서 Firefox 브라우저를 출시.
마이크로소프트 - 모질라 - 넷스케이프 3사가 표준안을 두고 엎치락뒤치락하게 된다.
그 사이 개발자들은 ... 표준안이 정해지지 않았으니 한 프로그램을 만들 때 모든 브라우저에 맞도록 각각의 버전을 만들어야 했다. (🤮)
계속해서 엎치락 뒤치락 어떻게 할 거냐~ 지지부진되고 있는 중 획기적인 것들이 등장한다.
1. AJAX Asynchronous JavaScript and XML : 비동기적으로 서버에서 데이터를 받아오고 처리할 수 있도록 도와주는 시스템
2. 개발자 커뮤니티 등에서 JQuery 같은 라이브러리 등장(API) : 더 이상 다른 브라우저들의 구현상황을 신경 쓰지 않아도 되기 위해
3. 2008년 드디어! 구글 Chrome 출시 : JS의 실행속도가 굉장히 빠른 JIT 컴파일러를 사용한 V8 엔진이 포함.
특히나 구글 크롬의 등장은 다른 브라우저들에게 있어 커다란 자극제가 되어주었고, 결국 표준안을 만들기로 합의한다. (서로 윈윈!)
2009년 드디어 ECMAScript5 !! 가 출판 이어서 2015년에는 6판이 출판되었다.
라이브러리의 도움 없이 Web API 만으로도 모든 브라우저에서 잘 동작하는 스크립트를 만들 수 있게 되었다.
<script... async vs defer >?
html 파일에 script 파일을 연결할 때, <script> 요소를 사용한다.
<script> 요소의 위치, 속성의 유무에 따라 안전성과 효율성의 차이가 생기기 때문에 각각의 차이를 잘 이해하자.
(기본 : html 코드를 위에서 아래로 한 줄씩 분석한다.)
1. <head> 안 <script> 의 경우
script 요소를 만나면 한줄씩 분석하던 걸 멈추고, 연결되어 있는 js 파일 다운을 시작한다.
다운이 끝나면 실행 -> 그 다음에 다시 한 줄씩 분석 시작.
❗️단점 : js 파일이 크거나 인터넷이 느리다면 페이지 로드 시간이 오래 걸린다.
2. <body>의 맨 마지막에 <script>를 사용하는 경우
js를 다운로드하지 않더라도 페이지 콘텐츠를 모두 볼 수 있다. (js 다운은 가장 마지막에 이루어지기 때문에)
❗️단점 : 자바스크립트에 굉장히 의존적인 웹사이트의 경우 (= 의미 있는 콘텐츠가 자바스크립트에 포함되어 있는 경우) 사용자가 정상적인 사이트를 볼 때까지 오랜 시간을 기다려야 한다. (js 다운로드하는 시간 + js 실행하는 시간)
🤔 js 다운과 실행, html 코드 읽기가 같이 이루어질 수는 없는 걸까? (-> 속성을 사용한다)
3. <head> 안 async 속성 값 사용
<script src=".js" async></script>
(async 는 boolean 타입의 속성값으로 선언하는 것만으로도 true 값을 가진다.)
- script 요소를 만나면 연결된 js 파일 다운을 시작하면서! 멈추지 않고! 한 줄씩 분석을 이어간다.
- js 파일의 다운로드가 완료되면 분석을 잠시 멈추고, js 파일을 실행한다.
- 실행 후 분석이 다시 시작된다.
장점 : 다운로드하는 시간 절약 가능
❗️단점 :
- 예를 들어 html의 DOM 요소를 사용하는 js 파일의 경우, 원하는 요소가 아직 정의되어 있지 않을 수 있어 위험 (html 분석이 다 끝나기 전에 js파일이 실행되므로)
- js 파일 실행 시간으로 사이트가 멈출 수도 있기 때문에 시간이 오래 걸릴 수 있다.
- 복수의 js 파일을 사용하는 경우, 다운로드가 끝난 순서대로 실행시키기 때문에 순서가 중요한 js 파일이라면 문제가 생길 수 있다.
4. <head> 안 defer 속성 값 사용
<script src=".js" defer></script>
defer 속성을 확인하면 js 파일 다운 명령을 내린다. html을 모두 분석 후 바로 js 파일을 실행한다.
복수의 js 파일을 사용하는 경우, 다운로드는 모두 함께 하고 써져 있는 순서대로 실행된다.
=> 즉, defer 속성을 사용하는 게 가장 안전하고 효율적이다.
+) "use strict" (ECMAScript5에서 추가)
바닐라 자바스크립트의 경우 js 파일의 가장 위에 정의해 주면 좋다.
왜? 자바스크립트는 유연한 언어이기 때문!
유연한 언어 = 위험하다는 특징을 갖고 있다. 선언하지도 않은 변수에 값을 할당한다든지...라는 비상식적인 상황을 막아준다.
또한 엔진이 더 효율적이고 빠르게 분석할 수 있게 한다.
Object
한두 가지 이상의 데이터를 묶어둔 것 (예: 함수, 리스트...)
(data type: number, string, boolean, null, undefined, symbol.. 작은 단위의 데이터들을 제외한 모든 것)
✨중요
object를 변수에 할당했을 때, 변수는 할당한 object 그 자체를 가지고 있는 게 아니다.
변수가 갖고 있는 값은 (어딘가 따로 저장되어 있는) object를 가리키는 주소(reference)이다.
❗️값을 할당하는 변수와 달리 오브젝트를 할당한 변수, 그리고 그 변수를 다른 변수에 할당했을 경우 :
가리키는 주소를 복사한 것이므로 두 변수 모두 오브젝트 원본을 가리키는 주소를 담고 있다.
어떤 쪽이든 수정하면 모두 값이 변경되는 걸 확인할 수 있다.
❗️object 안에 key의 유무를 확인하는 방법
console.log("name" in burger); // true
console.log("random" in burger); // false
Function
왜 함수를 사용할까?
반복해서 사용하는 혹은 수행하는 로직이 있다면 그때그때 또 똑같은 걸 쓰는 게 아니라 함수로 만들어서 호출 -> 재사용할 수 있기 때문
Function is object in JS!!!
잊지 말아야 할 사실. 함수는 object이다. => object의 특징들을 가지고 있다.
즉, 함수 이름(like 변수)에는 함수가 정의된 곳을 가리키고 있는 주소(reference)가 들어있다.
1. 변수를 선언함과 동시에 함수를 할당한다.
2. 변수이름(); 로 함수를 호출할 수 있다. (실행)
3. 또 다른 변수를 선언하고, 변수이름을 할당한다.
4. 또 다른 변수(); 로 할당되어 있는 값(주소)을 통해 함수를 호출한다 (실행)
Class
클래스는 다양한 object를 만들기 위한 청사진(틀)이다.
무언가를 설명하기 위해 필요한 데이터가 class라는 틀 안에 들어가면 object가 된다.
1) 클래스 선언
class Person {
// constructor 생성자
constructor(name, age) {
// fields
// 전달된 데이터 바로 할당
this.name = name;
this.age = age;
}
// methods
speak() {
console.log(`${this.name}: hello!!`);
}
}
2) 오브젝트 생성
const burger = new Person("burger", 72);
console.log(burger.name);
console.log(burger.age);
burger.speak();
3) Getter와 Setter
예를 들어 사용자의 나이를 입력받아야 할 때, 사용자가 -1라고 잘못 썼다고 생각해 보자.
-1살...? 그런 건 존재하지 않는다.
이러한 상황을 방지하기 위해 getter와 setter를 사용한다.
4) public, private
5) 상속과 다양성
class 끼리 상속받을 수 있다.
class Shape {
constructor(width, height, color) {
this.width = width;
this.height = height;
this.color = color;
}
draw() {
console.log(`drawing ${this.color} color!!`);
}
getArea() {
return width * this.height;
}
}
Shape라는 클래스가 존재한다고 했을 때, Shape를 상속받아 부분적으로만 추가 변경 하고 싶을 때 어떻게 해야 할까?
// 자동적으로 Shape이 Rectangle에 포함됨
class Rectangle extends Shape {}
class Triangle extends Shape {
draw() {
super.draw(); // 부모의 draw가 출력
console.log("🔺");
}
getArea() {
return (width * this.height) / 2;
}
}
extends를 사용하면 된다!
+) class... 어떻게 해야 효율적으로 사용할 수 있을까?
클래스 안에 모든 정보, 함수를 담으려고 하지 말자.
콜백함수를 받아오는 등 적절히 이용, 조립하여 사용하는 편이 수정, 추가, 삭제에도 편리하다.
// * 클래스 (다양한 오브젝트를 만들기 위한 청사진!)
// 생성이 되면 counter라는 변수가 있고 0부터 시작한다.
// Counter라는 클래스에는 자체적으로 counter라는 변수가 있고, 0으로 초기화된다.
class Counter {
constructor(runEveryFiveTimes) {
this.counter = 0;
this.callback = runEveryFiveTimes;
}
// class 내에서 함수 선언할 때는 function 안써도 된다
increase() {
this.counter++;
console.log(this.counter);
// 1번째 방법 if문 안에서 출력 console.log() (문제: 출력이 아니라 다른 방법으로 보여주고 싶다면? yo말고 다른 걸 출력하고 싶다면? -> 즉, 컨트롤할 수 없다)
if (this.counter % 5 === 0) {
// 2번째 방법 콜백함수 사용. (장점 : 원하는 기능 추가 변경 등 손쉬움.)
// runIf5Times(this.counter);
this.callback && this.callback(this.counter); // undefined가 아닐 때 실행
}
}
}
// constructor 실행 > counter = 0 초기화
function printSomething(num) {
console.log(`wow! ${num}`);
}
function alertNum(num) {
alert(num);
}
// class 에 원하는 콜백함수를 전달하는 방법
const coolCounter = new Counter(printSomething);
// ? 만약 클래스를 생성할 때 콜백함수를 전달하지 않는다면 (undefined) -> TypeError!
// ! 하나의 클래스로 다양한 오브젝트를 만들어서 서로 다른 기능을 수행하는 오브젝트를 만들 수 있다 -> 재사용률이 높아진다!
const printCounter = new Counter(printSomething);
const alertCounter = new Counter(alertNum);
coolCounter.increase(); //1
coolCounter.increase(); //2
coolCounter.increase(); //3
coolCounter.increase(); //4
coolCounter.increase(); //5 > 출력
coolCounter.increase();
coolCounter.increase();
coolCounter.increase();
coolCounter.increase();
coolCounter.increase(); // alert 10