컴퓨터(CPU)가 이해할 수 있는 언어인 기계어는 어셈블리어를 거쳐 짜여지게된다. 이 어셈블리어, 기계어는 인간이 이해하기 어렵기 때문에
인간이 작성하기 쉬운 고급 프로그래밍 언어의 구문을 이용해 작성하고, 컴파일러 혹은 인터프리터라는 번역기를 통해 기계어로 번역해 컴퓨터에게 전달한다
js는 웹 브라우저에서 동작하는 프로그래밍언어.
한 때 브라우저 시장 점유율 경쟁으로 해당 브라우저에만 동작하는 기능들이 경쟁적으로 추가된 적이 있다. 이 때 브라우저에 따라 비정상동작하는 기능들이 존재하는 크로스 브라우징 이슈 가 발생, 표준화 필요성이 제기되어, ECMA 에서 javascript를 표준화하였고 이를 EMCAScript라고 한다. (HTML5, CSS3와 함께 표준 제정)
ES6에는 let/cost 키워드, 화살표 함수, 클래스, 모듈 기능 등 범용 프로그래밍 언어가 갖추어야할 기능들이 대거 도입되었다. (ES8:2017에는 async/await 도입)
js는 일반적으로 프로그래밍 언어 기본 뼈대인 ECMAscript와 브라우저 별도 지원의 client side web API(DOM,BOM,Canvas, XMLHttpRequst, SVG,WebStorage, Web Component, Web worker) 등을 아우르는 개념.
대부분의 프로그래밍 언어는 운영체제(Operating System, OS) 위에서 실행되지만 웹 애플리케이션의 자바스크립트는 브라우저에서 HTML, CSS와 함께 실행. ( Node.js의 등장으로 자바스크립트는 웹 브라우저를 벗어나 서버 사이드 애플리케이션 개발에서도 사용되는 범용 개발 언어가 됨)
브라우저의 핵심 기능은 사용자가 참조하고자 하는 웹페이지를 서버에 요청(Request)하고 서버의 응답(Response)을 받아 브라우저에 표시하는 것
동작 과정 : 동기적(Sync)으로 html,css,js 처리.
1.브라우저는 서버로부터 HTML, CSS, Javascript, 이미지 파일 등을 응답
2.HTML, CSS 파일은 렌더링 엔진의 HTML 파서와 CSS 파서에 의해 파싱(Parsing)되어 DOM, CSSOM 트리로 변환되고 렌더 트리로 결합
3.생성된 렌더 트리를 기반으로 브라우저는 웹페이지를 표시 (렌더링)
4.HTML 파서는 script 태그를 만나면 자바스크립트 코드를 실행하기 위해 DOM 생성 프로세스를 중지하고 자바스크립트 엔진으로 제어 권한을 넘김. (렌더링 엔진이 html,css담당, js엔진이 js담당)
5.제어 권한을 넘겨 받은 자바스크립트 엔진은 script 태그 내의 자바스크립트 코드 또는 script 태그의 src 어트리뷰트에 정의된 자바스크립트 파일을 로드하고 파싱하여 실행
6.자바스크립트의 실행이 완료되면 다시 HTML 파서로 제어 권한을 넘겨서 브라우저가 중지했던 시점부터 DOM 생성을 재개
script 태그의 위치에 따라 블로킹이 발생하여 DOM의 생성이 지연될 수 있음,script 태그의 위치는 중요한 의미 : body요소 가장 아래에 위치 -> (HTML 요소들이 스크립트 로딩 지연으로 인해 렌더링에 지장 받는 일이 발생하지 않아 페이지 로딩 시간이 단축,DOM이 완성되지 않은 상태에서 자바스크립트가 DOM을 조작한다면 에러가 발생)
호이스팅이란, var선언문이나 function선언문 등 모든 선언문이 해당 Scope의 선두로 옮겨진 것 처럼 동작하는 특성. (코드 실행 시(전) 선언문 변수들을 미리 메모리에 할당해놓는 것)
var로 선언된 변수는 선언 단계와 초기화 단계가 한 번에 이루어진다. scope가 변수에 등록되고 변수는 메모리에 공간 확보 후 undefined로 초기화. = = 프로그램 실행 전 변수들의 선언과 초기화가 미리 이루어지는 것 = 변수 호이스팅.
스코프는 참조 대상 식별자(identifier, 변수, 함수의 이름과 같이 어떤 대상을 다른 대상과 구분하여 식별할 수 있는 유일한 이름)를 찾아내기 위한 규칙
대부분의 C-family language는 블록 레벨 스코프(block-level scope)를 따른다. 블록 레벨 스코프란 코드 블록({…})내에서 유효한 스코프를 의미한다. 여기서 “유효하다”라는 것은 “참조(접근)할 수 있다”라는 뜻
하지만 자바스크립트는 함수 레벨 스코프(function-level scope)
-> ES6에서 지원하는 let키워드를 사용하면 블록 레벨 스코프를 사용할 수 있다.
자바스크립트의 변수는 다른 C-family와는 달리 블록 레벨 스코프(block-level scope)를 가지지 않고 함수 레벨 스코프(function-level scope)를 가짐. 단 ES6의 let, const 키워드 사용 시 block level scope 사용 가능.
var
: ES6이전, ES5에서는 var가 유일한 변수 키워드이다.
함수 레벨 스코프이므로 전역 함수 외부에서 생성한 변수는 모두 전역 변수이며 for문의 변수 선언문에서 선언한 변수를 for문 외부에서 참조할 수 있다.
또한 var는 키워드 생략이 가능하고, 변수 중복 선언이 허용되어 의도하지 않은 변수값 변경이 이뤄질 가능성이 크다. 전역 변수는 유효 범위가 넓어 어디에서 어떻게 사용될지 파악하기 힘들며 의도치않게 변경될 수 있고, 복잡성을 증가시키는 원인이 된다.
const
: const는 재할당이 금지. 이 때 객체 property는 보호되지 않기 때문에 객체 재할당은 불가능하지만 객체의 내용은 변경 가능하다.
let
let : var,let,const 모두 호이스팅은 진행하지만, 선언문 이전 접근 시 ReferenceError: bar is not defined를 발생시킨다.
let으로 선언된 변수는 선언단계와 초기화단계가 분리되어 진행된다. 초기화단계를 변수 선언문에 도달했을 때 초기화한다. 그 이전에 접근 시 참조에러를 발생시키는 것.
또한 let은 동일 이름을 갖는 변수를 중복 선언할 수 없다.(Uncaught SyntaxError: Identifier 'bar' has already been declared)
let foo = 1; // 전역 변수
{
console.log(foo); // ReferenceError: foo is not defined
let foo = 2; // 지역 변수
}
let으로 선언된 변수는 블록레벨 스코프를 가지므로 코드 블록 내에서 선언된 foo는 지역변수이고, 해당 스코프에서 호이스팅되므로,(애초에 중복선언 불가) -> 전역 foo와 별개로 선언된다. 해당 블록스코프에서는 foo 접근 시 호이스팅 된 지역변수 foo에 접근되는 것(참조에러)이고 만약 코드 블럭 내에 foo가 없다면 전역변수를 참조하게되는 것.
변수 선언에는 기본적으로 const를 사용하고 let은 재할당이 필요한 경우에 한정해 사용하는 것이 좋다.
렉시컬 스코핑 : 스코프는 함수를 호출할 때가 아니라 함수를 어디에 선언하였는지에 따라 결정.
클로저 : 반환된 내부함수가 자신이 선언됐을 때의 환경(Lexical environment)인 스코프를 기억하여 자신이 선언됐을 때의 환경(스코프) 밖에서 호출되어도 그 환경(스코프)에 접근할 수 있는 함수
= 클로저는 자신이 생성될 때의 환경(Lexical environment)에 실행 context(스코프)를 가지는 함수.
closure 형태 예시 1)
// 클로저를 만드는 형태 1. - 중첩함수
function outerFn() {
let x = 10;
return function innerFn(y) { // innerFn 함수는 클로저다.
return x = x + y;
}
}
let a = outerFn(); // 외부함수 호출은 한번만. 이제 a 변수는 innerFn 함수를 참조한다.
a(5); // 15;
a(5); // 20;
a(5); // 25;
innerFn이 클로저. let변수는 블록스코프이다. outerFn은 innerFn을 참조할 수 없다. 그러나 outerFn 안에 선언된 innerFn은 클로저로, 자신이 렉시컬 스코프를 기억하여 바깥에서 호출(a)하여도 해당 환경을 기억하기 때문에 outerFn안에 선언된 x값이 항상 10이 아니라 호출될 때 마다 5가 누적된 형태로 나타나는 것이다.
closure 형태 예시 2)
// 클로저를 만드는 형태 2. - 전역에 선언한 변수를 박스 안에서 함수로 정의하고 전역에서 호출
let globalFunc;
{
let x = 10;
globalFunc = function(y) { // globalFunc 함수는 클로저다.
return x = x + y;
}
}
globalFunc(5); // 15;
globalFunc(5); // 20;
globalFunc(5); // 25;
globalFunc가 클로저. let변수는 블록스코프이다. globalFunc는 블록스코프에서 할당되지만, 변수 선언이 전역에서 되었기 때문에 외부에서 호출이 가능하다. 이 때 블록스코프에 할당된 x변수는 외부에서 접근이 불가능하지만, 블록스코프에서 함수를 할당하였기 떄문에 해당 렉시컬 스코프를 기억하여 x의 값이 누적된 형태로 나타남.
-> 클로저는 상태유지(데이터 보존), 정보 접근 제한(캡슐화) 등으로 활용 가능하다.
클로저 실수 예제
var arr = [];
for (var i = 0; i < 5; i++) {
arr[i] = function () {
return i;
};
}
for (var j = 0; j < arr.length; j++) {
console.log(arr[j]()); //5,5,5,5,5
}
i는 전역 변수이기 때문에 값이 누적되어 5,5,5,5,5가 출력된다.
var funcs = [];
// 함수의 배열을 생성하는 for 루프의 i는 전역 변수다.
for (var i = 0; i < 3; i++) {
(function (index) { // index는 자유변수다.
funcs.push(function () { console.log(index); });
}(i));
}
// 배열에서 함수를 꺼내어 호출한다
for (var j = 0; j < 3; j++) {
funcs[j]();
}
위 예제는 var가 전역으로 선언되기 때문에 발생하는 현상.(함수레벨 스코프)
(자유변수 : 클로저를 포함하고 있는 외부 함수의 읹, 지역변수. 클로저를 통해서만 사용 가능하고 외부 함수가 종료된 후에도 해당 함수를 참조하고있다면 사라지지 않음)
const arr = [];
for (let i = 0; i < 5; i++) {
arr[i] = function () {
return i; //arr[0]에는 function() {return 0}이 저장. i는 자유변수이기 때문에 바깥에서 참조하지 않고 해당 value를 저장한 새로운 메모리에 저장되어 함수 호출 시 반환되는 것이다.
};
}
for (let i = 0; i < arr.length; i++) {
console.log(arr[i]());
}
let을 사용하는 것이 훨씬 깔끔. let은 블록레벨 스코프이기 때문 : for loop에서만 유효한 지역변수이면서 자유변수로서 for loop 생명주기 종료되어도 i변수 참조하는 함수가 존재하는 한 계속 유지된다.
자바스크립트는 객체(object) 기반의 스크립트 언어이며 원시 타입(Primitives)을 제외한 나머지 값들(함수, 배열, 정규표현식 등)은 모두 객체.
자바스크립트의 객체는 키(key)과 값(value)으로 구성된 프로퍼티(Property)들의 집합.
자바스크립트의 함수는 일급 객체이므로 값으로 취급할 수 있다
프로퍼티 값으로 함수를 사용할 수도 있으며 프로퍼티 값이 함수일 경우, 일반 함수와 구분하기 위해 메소드라 부른다.
자바스크립트의 객체는 객체지향의 상속을 구현하기 위해 “프로토타입(prototype)”이라고 불리는 객체의 프로퍼티와 메소드를 상속받을 수 있다. 이 프로토타입은 타 언어와 구별되는 중요한 개념
프로토타입 기반 프로그래밍은 클래스가 존재하지 않는 객체지향 프로그래밍 스타일
프로토타입 체인과 클로저 등으로 객체 지향 언어의 상속, 캡슐화(정보 은닉) 등의 개념을 구현
ES6에는 클래스 개념 도입. 클래스가 새로운 객체지향 모델을 제공하는 것이 아니며 클래스도 사실 함수이고 기존 프로토타입 기반 패턴을 구현한 문법적인 지원임.
자바스크립트의 모든 객체는 자신의 부모 역할을 담당하는 객체와 연결되어 있다. 그리고 이것은 마치 객체 지향의 상속 개념과 같이 부모 객체의 프로퍼티 또는 메소드를 상속받아 사용할 수 있게 한다. 이러한 부모 객체를 Prototype(프로토타입) 객체 또는 줄여서 Prototype(프로토타입)이라 한다.
자바스크립트의 모든 객체는 [[Prototype]]이라는 인터널 슬롯(internal slot)를 가진다. [[Prototype]]의 값은 null 또는 객체이며 상속을 구현하는데 사용된다. [[Prototype]] 객체의 데이터 프로퍼티는 get 액세스를 위해 상속되어 자식 객체의 프로퍼티처럼 사용할 수 있다. set 액세스는 허용되지 않는다.
주의해야 할 것은 prototype 프로퍼티는 프로토타입 객체를 가리키는 [[Prototype]] 인터널 슬롯은 다르다는 것이다. prototype 프로퍼티와 [[Prototype]]은 모두 프로토타입 객체를 가리키지만 관점의 차이가 있다.
- [[Prototype]]
함수를 포함한 모든 객체가 가지고 있는 인터널 슬롯이다.
객체의 입장에서 자신의 부모 역할을 하는 프로토타입 객체를 가리키며 함수 객체의 경우 Function.prototype를 가리킨다.- prototype 프로퍼티
함수 객체만 가지고 있는 프로퍼티이다.
함수 객체가 생성자로 사용될 때 이 함수를 통해 생성될 객체의 부모 역할을 하는 객체(프로토타입 객체)를 가리킨다.
프로토타입 객체는 constructor 프로퍼티를 갖는다. 이 constructor 프로퍼티는 객체의 입장에서 자신을 생성한 객체를 가리킨다.
Prototype chain
프로토타입 체인 : 자바스크립트는 특정 객체의 프로퍼티나 메소드에 접근하려고 할 때 해당 객체에 접근하려는 프로퍼티 또는 메소드가 없다면 [[Prototype]]이 가리키는 링크를 따라 자신의 부모 역할을 하는 프로토타입 객체의 프로퍼티나 메소드를 차례대로 검색.
프로토타입 체인 동작 조건
객체의 프로퍼티를 참조하는 경우, 해당 객체에 프로퍼티가 없는 경우, 프로토타입 체인이 동작
객체 리터럴
중괄호({})를 사용하여 객체를 생성하는데 {} 내에 1개 이상의 프로퍼티를 기술하면 해당 프로퍼티가 추가된 객체를 생성할 수 있다.
var emptyObject = {};
console.log(typeof emptyObject); // object
var person = {
name: 'Lee',
gender: 'male',
sayHello: function () {
console.log('Hi! My name is ' + this.name);
}
};
console.log(typeof person); // object
console.log(person); // {name: "Lee", gender: "male", sayHello: ƒ}
person.sayHello(); // Hi! My name is Lee
Object 생성자 함수
new 연산자와 Object 생성자 함수를 호출하여 빈 객체를 생성할 수 있다. 빈 객체 생성 이후 프로퍼티 또는 메소드를 추가하여 객체를 완성하는 방법.
생성자(constructor) 함수란 new 키워드와 함께 객체를 생성하고 초기화하는 함수.
생성자 함수를 통해 생성된 객체를 인스턴스(instance)
// 빈 객체의 생성
var person = new Object();
// 프로퍼티 추가
person.name = 'Lee';
person.gender = 'male';
person.sayHello = function () {
console.log('Hi! My name is ' + this.name);
};
console.log(typeof person); // object
console.log(person); // {name: "Lee", gender: "male", sayHello: ƒ}
person.sayHello(); // Hi! My name is Lee
객체 리터럴 방식으로 생성된 객체는 결국 빌트인(Built-in) 함수인 Object 생성자 함수로 객체를 생성하는 것을 단순화시킨 축약 표현(short-hand)
생성자 함수
생성자 함수를 사용하면 마치 객체를 생성하기 위한 템플릿(클래스)처럼 사용하여 프로퍼티가 동일한 객체 여러 개를 간편하게 생성할 수 있다.
// 생성자 함수
function Person(name, gender) {
var married = true; // private
this.name = name; // public
this.gender = gender; // public
this.sayHello = function(){ // public
console.log('Hi! My name is ' + this.name);
};
}
var person = new Person('Lee', 'male');
console.log(typeof person); // object
console.log(person); // Person { name: 'Lee', gender: 'male', sayHello: [Function] }
console.log(person.gender); // 'male'
console.log(person.married); // undefined
프로퍼티 또는 메소드명 앞에 기술한 this는 생성자 함수가 생성할 인스턴스(instance)를 가리킨다.this에 연결(바인딩)되어 있는 프로퍼티와 메소드는 public(외부에서 참조 가능)하다.
생성자 함수 내에서 선언된 일반 변수는 private(외부에서 참조 불가능)
객체 타입은 동적으로 변화할 수 있으므로 어느 정도의 메모리 공간을 확보해야 하는지 예측할 수 없기 때문에 런타임에 메모리 공간을 확보하고 메모리의 힙 영역(Heap Segment)에 저장
일급 객체(first-class object)란 다른 객체들에 일반적으로 적용 가능한 연산을 모두 지원하는 객체를 가리킨다. 보통 함수에 인자로 넘기기, 수정하기, 변수에 대입하기와 같은 연산을 지원할 때 일급 객체라고 함.
함수 정의
function square(number) {
return number * number;
}
// 기명 함수 표현식(named function expression)
var foo = function multiply(a, b) {
return a * b;
};
// 익명 함수 표현식(anonymous function expression)
var bar = function(a, b) {
return a * b;
};
변수는 함수명이 아니라 할당된 함수를 가리키는 참조값을 저장하게 된다
함수가 할당된 변수를 사용해 함수를 호출하지 않고 기명 함수의 함수명을 사용해 호출하게 되면 에러가 발생한다. 이는 함수 표현식에서 사용한 함수명은 외부 코드에서 접근 불가능하기 때문
함수 호이스팅
함수 선언의 위치와는 상관없이 코드 내 어느 곳에서든지 호출이 가능한데 이것을 함수 호이스팅(Function Hoisting)이라 한다 (호이스팅이란 var 선언문이나 function 선언문 등 모든 선언문이 해당 Scope의 선두로 옮겨진 것처럼 동작하는 특성)
함수 선언문으로 정의된 함수는 자바스크립트 엔진이 스크립트가 로딩되는 시점에 바로 초기화하고 이를 VO(variable object)에 저장한다. 즉, 함수 선언, 초기화, 할당이 한번에 이루어진다. 그렇기 때문에 함수 선언의 위치와는 상관없이 소스 내 어느 곳에서든지 호출이 가능하다.
var res = square(5); // TypeError: square is not a function
var square = function(number) {
return number * number;
}
함수 표현문의 경우 함수 호이스팅이 아니라 변수 호이스팅이 발생하고, 변수 생성 초기화와 할당이 분리되므로 호이스팅 된 변수는 undefined로 함수가 아니다. 그러므로 square(5)를 호출할 수 없다.
즉시 실행 함수 : 함수의 정의와 동시에 실행되는 함수를 즉시 실행 함수(IIFE, Immediately Invoke Function Expression)
// 기명 즉시 실행 함수(named immediately-invoked function expression)
(function myFunction() {
var a = 3;
var b = 5;
return a * b;
}());
// 익명 즉시 실행 함수(immediately-invoked function expression)
(function () {
var a = 3;
var b = 5;
return a * b;
}());
// SyntaxError: Unexpected token (
// 함수선언문은 자바스크립트 엔진에 의해 함수 몸체를 닫는 중괄호 뒤에 ;가 자동 추가된다.
function () {
// ...
}(); // => };();
// 따라서 즉시 실행 함수는 소괄호로 감싸준다.
(function () {
// ...
}());
(function () {
// ...
})();
즉시 실행 함수 내에 처리 로직을 모아 두면 혹시 있을 수도 있는 변수명 또는 함수명의 충돌을 방지할 수 있어 이를 위한 목적으로 즉시실행함수를 사용되기도 한다.
내부 함수(inner function) : 함수 내부에 정의된 함수를 내부함수(Inner function)
콜백 함수(Callback function)는 함수를 명시적으로 호출하는 방식이 아니라 특정 이벤트가 발생했을 때 시스템에 의해 호출되는 함수, 콜백 함수가 자주 사용되는 대표적인 예는 이벤트 핸들러 처리
콜백 함수는 매개변수를 통해 전달되고 전달받은 함수의 내부에서 어느 특정시점에 실행.
setTimeout(function () { //function : 콜백함수
console.log('1초 후 출력된다.'); //콜백함수 내용 : 출력
}, 1000);
콜백 함수는 주로 비동기식 처리 모델(Asynchronous processing model)에 사용된다. (비동기식 처리 모델이란 처리가 종료하면 호출될 함수(콜백함수)를 미리 매개변수에 전달하고 처리가 종료하면 콜백함수를 호출하는 것)
콜백함수는 콜백 큐에 들어가 있다가 해당 이벤트가 발생하면 호출.
콜백 함수는 클로저이므로 콜백 큐에 단독으로 존재하다가 호출되어도 콜백함수를 전달받은 함수의 변수에 접근할 수 있다.
이벤트 루프는 콜 스택에 현재 실행 중인 실행 컨텍스트가 있는지, 태스크 큐에 대기중인 함수(콜백 함수, 이벤트 핸들러..)가 있는지 반복해서 확인한다. 콜스택이 비어 있고 태스크 큐에 대기중인 함수가 있다면 이벤트 루프는 순차적으로 태스크 큐에 대기 중인 함수를 콜스택으로 이동시킨다. 이때 콜 스택으로 이동한 함수는 실행된다.
C++에서의 this는 인스턴스 자신(self)을 가리키는 참조변수이다. this가 객체 자신에 대한 참조 값을 가지고 있다는 뜻.
하지만 자바스크립트의 경우 Java와 같이 this에 바인딩되는 객체는 한가지가 아니라 해당 함수 호출 방식에 따라 this에 바인딩되는 객체가 달라진다.
this는 전역 객체(window)를 context 객체로 갖는다.
전역 스코프에서 정의한 변수들은 전역 객체에 등록된다.
어떤 객체를 통해 함수가 호출된다면 그 객체가 this의 context 객체가 된다.
var b = 100;
function test() {
console.log(this.b);
}
var obj = {
a: 20,
func1: test,
func2: function() {
console.log(this.b);
}
};
obj.func1(); // undefined
obj.func2(); // undefined
var gFunc1 = obj.func1;
gFunc1(); // 100
obj객체에서 호출한 func1, func2는 this로 obj를 가지므로, b는 undefined가 된다.
그러나 gFunc는 전역에서 생성한 변수이자, 함수이므로=객체 이므로, 해당 함수를 호출한 객체는 전역객체이고, 전역 context에서 this는 window로 전역 변수인 b(100)에 접근 가능한 것이다
function test() {
console.log(this);
}
var obj = { name: "yuddomack" };
test.call(obj); // { name: 'yuddomack' }
test.call("원시 네이티브 자료들은 wrapping 됩니다"); // [String: '원시 네이티브 자료들은 wrapping 됩니다']
함수 객체는 call이라는 메소드를 가지고있는데, call의 첫 번째 인자로 넘겨주는 것이 context 객체가 된다. context를 명시해주는 것.
새 객체가 만들어지고, prototype 체인에 의해 호출된 함수의 프로토타입과 연결,
만들어진 새 객체를 this context로 사용하여 함수가 실행되는 것. (함수가 객체를 반환한다면 해당 값이 반환값이 된다.)
function foo(a) {
this.a = a;
this.qwer = 20;
}
var bar1 = new foo(2);
console.log(bar1.a); // 2
console.log(bar1.qwer); // 20
// 1. 새 객체가 만들어짐
var obj = {};
// 2. 새로 생성된 객체의 Prototype 체인이 함수의 프로토타입과 연결됨
Object.setPrototypeOf(obj, foo.prototype); // 프로토타입을 연결합니다. 이 글에서는 무시해도 상관없습니다.
// 3. 1에서 생성된 객체를 context 객체로 사용(명시적으로)하여 함수가 실행됨
foo.call(obj, 2);
// 4. 이 함수가 객체를 반환하지 않는 한 1에서 생성된 객체가 반환됨
var bar2 = obj; // 여기서 foo는 반환(return)이 없으므로 인스턴스가 생성(된 것처럼 동작)
console.log(bar2.a); // 2
console.log(bar2.qwer); // 20
클래스와 유사하게 동작하도록 만들어진 것.
브라우저의 렌더링 엔진은 웹 문서를 로드한 후, 파싱하여 웹 문서를 브라우저가 이해할 수 있는 구조로 구성하여 메모리에 적재하는데 이를 DOM이라 한다
DOM은 자바스크립트를 통해 동적으로 변경할 수 있으며 변경된 DOM은 렌더링에 반영.
DOM tree node
- 문서 노드(Document Node)
트리의 최상위에 존재하며 각각 요소, 어트리뷰트, 텍스트 노드에 접근하려면 문서 노드를 통해야 한다. 즉, DOM tree에 접근하기 위한 시작점(entry point)이다.- 요소 노드(Element Node)
요소 노드는 HTML 요소를 표현한다. HTML 요소는 중첩에 의해 부자 관계를 가지며 이 부자 관계를 통해 정보를 구조화한다. 따라서 요소 노드는 문서의 구조를 서술한다고 말 할 수 있다. 어트리뷰트, 텍스트 노드에 접근하려면 먼저 요소 노드를 찾아 접근해야 한다. 모든 요소 노드는 요소별 특성을 표현하기 위해 HTMLElement 객체를 상속한 객체로 구성된다. (그림: DOM tree의 객체 구성 참고)- 어트리뷰트 노드(Attribute Node)
어트리뷰트 노드는 HTML 요소의 어트리뷰트를 표현한다. 어트리뷰트 노드는 해당 어트리뷰트가 지정된 요소의 자식이 아니라 해당 요소의 일부로 표현된다. 따라서 해당 요소 노드를 찾아 접근하면 어트리뷰트를 참조, 수정할 수 있다.- 텍스트 노드(Text Node)
텍스트 노드는 HTML 요소의 텍스트를 표현한다. 텍스트 노드는 요소 노드의 자식이며 자신의 자식 노드를 가질 수 없다. 즉, 텍스트 노드는 DOM tree의 최종단이다.
DOM Query
동기식 처리 모델(Synchronous processing model)은 직렬적으로 태스크(task)를 수행
비동기식 처리 모델(Asynchronous processing model 또는 Non-Blocking processing model)은 병렬적으로 태스크를 수행 : 자바스크립트의 대부분의 DOM 이벤트 핸들러와 Timer 함수(setTimeout, setInterval), Ajax 요청은 비동기식 처리 모델로 동작
function func1() {
console.log('func1');
func2();
}
function func2() {
setTimeout(function() {
console.log('func2');
}, 0);
func3();
}
function func3() {
console.log('func3');
}
func1();
함수 func1이 호출되면 함수 func1은 Call Stack에 쌓인다. 그리고 함수 func1은 함수 func2을 호출하므로 함수 func2가 Call Stack에 쌓이고 setTimeout가 호출된다. setTimeout의 콜백함수는 즉시 실행되지 않고 지정 대기 시간만큼 기다리다가 “tick” 이벤트가 발생하면 태스크 큐로 이동한 후 Call Stack이 비어졌을 때 Call Stack으로 이동되어 실행된다.
func3->2->1 순서대로 call stack에서 pop되고 callback function이 callstack에 push된다.
Ajax(Asynchronous JavaScript and XML)는 자바스크립트를 이용해서 비동기적(Asynchronous)으로 서버와 브라우저가 데이터를 교환할 수 있는 통신 방식을 의미
서버로부터 웹페이지가 반환되면 화면 전체를 갱신해야 하는데 페이지 일부만을 갱신하고도 동일한 효과를 볼 수 있도록 하는 것이 Ajax이다. 페이지 전체를 로드하여 렌더링할 필요가 없고 갱신이 필요한 일부만 로드하여 갱신하면 되므로 빠른 퍼포먼스와 부드러운 화면 표시 효과를 기대할 수 있다.
클라이언트와 서버 간에는 데이터 교환이 필요하다. JSON(JavaScript Object Notation)은 클라이언트와 서버 간 데이터 교환을 위한 규칙 즉 데이터 포맷을 말한다.
JSON은 일반 텍스트 포맷보다 효과적인 데이터 구조화가 가능하며 XML 포맷보다 가볍고 사용하기 간편하며 가독성도 좋다.
자바스크립트의 객체 리터럴과 매우 흡사하다. 하지만 JSON은 순수한 텍스트로 구성된 규칙이 있는 데이터 구조.
브라우저는 XMLHttpRequest 객체를 이용하여 Ajax 요청을 생성하고 전송한다. 서버가 브라우저의 요청에 대해 응답을 반환하면 같은 XMLHttpRequest 객체가 그 결과를 처리.
이벤트(event)는 어떤 사건을 의미한다. 브라우저에서의 이벤트란 예를 들어 사용자가 버튼을 클릭했을 때, 웹페이지가 로드되었을 때와 같은 것인데 이것은 DOM 요소와 관련.
이벤트가 발생하는 시점이나 순서를 사전에 인지할 수 없으므로 일반적인 제어 흐름과는 다른 접근 방식이 필요하다. 즉, 이벤트가 발생하면 누군가 이를 감지할 수 있어야 하며 그에 대응하는 처리를 호출해 주어야 한다.
브라우저는 단일 쓰레드(single-thread)에서 이벤트 드리븐(event-driven) 방식으로 동작
단일 쓰레드는 쓰레드가 하나뿐이라는 의미이며 이말은 곧 하나의 작업(task)만을 처리할 수 있다는 것을 의미 ->
동시에 task들이 진행되는 것 처럼 느껴지게 해주는 것(동시성 지원) : 자바스크립트의 동시성(Concurrency)을 지원하는 것이 바로 이벤트 루프(Event Loop)
V8비롯한 자바스크립트 엔진들은 크게 2개의 영역으로 나뉜다.
자바스크립트 엔진은 단순히 작업이 요청되면 Call Stack을 사용하여 요청된 작업을 순차적으로 실행할 뿐이다. 앞에서 언급한 동시성(Concurrency)을 지원하기 위해 필요한 비동기 요청(이벤트를 포함) 처리는 자바스크립트 엔진을 구동하는 환경 즉 브라우저(또는 Node.js)가 담당
웹의 장점을 최대한 활용할 수 있는 아키텍쳐로서 REST를 소개하였고 이는 HTTP 프로토콜을 의도에 맞게 디자인하도록 유도하고 있다. REST의 기본 원칙을 성실히 지킨 서비스 디자인을 “RESTful”이라고 표현.
단일 페이지 애플리케이션(Single Page Application, SPA)는 모던 웹의 패러다임.
서버사이드 렌더링의 약자로 서버로부터 완전하게 만들어진 html파일을 받아와 페이지 전체를 렌더링 하는 방식
클라이언트 사이드 렌더링 이란 사용자의 요청에 따라 필요한 부분만 응답 받아 렌더링 하는 방식