javascript 빠른 요약
기본과 동작원리
인터프리터와 컴파일
컴퓨터(CPU)가 이해할 수 있는 언어인 기계어는 어셈블리어를 거쳐 짜여지게된다. 이 어셈블리어, 기계어는 인간이 이해하기 어렵기 때문에
인간이 작성하기 쉬운 고급 프로그래밍 언어의 구문을 이용해 작성하고, 컴파일러 혹은 인터프리터라는 번역기를 통해 기계어로 번역해 컴퓨터에게 전달한다
- 컴파일러
- 컴파일러는 고급 언어로 작성된 프로그램 전체를 목적 프로그램으로 번역한 후, 링킹 작업을 통해 컴퓨터에서 실행 가능한 실행 프로그램을 생성.
- 번역 실행 과정을 거쳐야 하기 때문에 번역 과정이 번거롭고 번역 시간이 오래 걸리지만, 한번 번역한 후에는 다시 번역하지 않으므로 실행 속도가 빠르다.
- 인터프리터
- 인터프리터는 고급 언어로 작성된 프로그램을 한 줄 단위로 받아들여 번역하고, 번역과 동시에 프로그램을 한 줄 단위로 즉시 실행시키는 프로그램.
- 프로그램이 직접 실행되므로 목적 프로그램은 생성되지 않는다.
- 줄 단위로 번역, 실행되기 떄문에 시분할 시스템에 유용하며 원시 프로그램의 변화에 대한 반응이 빠르다.
- 번역 속도는 빠르지만 프로그램 실행 시 매번 번역해야 하므로 실행 속도는 느리다.
javascript란
javascript 표준
js는 웹 브라우저에서 동작하는 프로그래밍언어.
한 때 브라우저 시장 점유율 경쟁으로 해당 브라우저에만 동작하는 기능들이 경쟁적으로 추가된 적이 있다. 이 때 브라우저에 따라 비정상동작하는 기능들이 존재하는 크로스 브라우징 이슈 가 발생, 표준화 필요성이 제기되어, ECMA 에서 javascript를 표준화하였고 이를 EMCAScript라고 한다. (HTML5, CSS3와 함께 표준 제정)
js 대략적 역사
- 초창기 js
브라우저(웹 페이지)동작 보조적 기능하기위한 언어. 로직은 웹서버에서. - Ajax : Asynchronous javascript and xml)(1999)
비동기적으로(Async) 서버와 브라우저가 데이터를 교환할 수 있는 통신기능. ajax의 등장은 웹페이지의 변경이 필요없는 부분은 다시 렌더링하지 않고 서버로부터 필요한 데이터만을 전송받아 변경 필요한 부분만 재렌더링이 가능해짐. (기존에는 html이 단위였기에 조금이라도 변경되면 서버로부터 html을 받아 재렌더링했음)
-> ajax의 의의는 웹 브라우저에서도 빠른 퍼포먼스와 부드러운 화면전환이 가능하게 해줌.(서버로부터 필요한 데이터만 받아 재렌더링이 가능했기 때문) - JQuery (2006)
엘리먼트를 선택하는 강력한 방법, 선택된 엘리먼트들을 효율적으로 제어할 수 있는 다양한 수단을 제공하는 자바스크립트 라이브러리
Dom(Document object model)을 쉽게 제어, 크로스 브라우징 이슈도 어느정도 해결. - V8 자바스크립트 엔진 (2008)
빠른 성능의 js실행해주는 프로그램(엔진). 웹어셈블리로 작성됨. 크롬 브라우저, nodejs에서 사용되며 자바스크립트를 바이트 코드로 컴파일하고 실행하는 방식을 사용한다. -> JIT(Just in time) 컴파일방식을 사용한다. -> 자바스크립트를 인터프리팅 하지 않고 컴파일하기 때문에 속도가 빠르다.
- js : single thread
하나의 힙과 하나의 콜 스택만 존재.(싱글스레드) : 하나의 콜 스택을 가지므로 한 번에 하나의 일만 처리한다.
그러나 실제 자바스크립트가 실행되는 환경(js runtime, 브라우저, nodejs)에서는 주로 multi thread를 사용한다.(싱글thread인 js 자체를 여러개 구동, call stack은 각 1개.) - js 동작방식
js는 싱글 thread 방식이므로 여러 작업들을 동시에 처리할 수 없다. sync(동기)방식에서는 여러 작업들이 쌓이면 후순위 작업은 다음 작업을 하지 못하고 무작정 기다려야한다. 하지만 js는 async(비동기) 작업이 기본으로, 여러 작업을 요청하고 완료되지 않았더라도 할일을 할 수 있게 해준다.(callback, promise, async/await으로 동기 작업 구현 가능)
- js : single thread
- nodejs(2009)
브라우저에서만 동작하던 js를 브라우저 이외 환경에서 동작시킬 수 있도록 하는 js 런타임(js 실행환경) -> 서버 사이드 어플리케이션 또한 개발이 가능해짐. - SPA
js의 규모가 커지면서 개발 규모와 복잡도가 상승했고, 복잡해진 개발 과정에 따라 여러 패턴들과 라이브러리들이 생겨났다. 해당 개발을 유연하면서 확장성있게 구현하기 위한 프레임워크가 자연스럽게 생겨났는데, 대표적인 근래 트렌드가 single page application이다.
웹의 전체 페이지를 하나의 페이지에 담아 동적으로 화면을 바꿔가며 표현하는 것이 spa이다.(component기반). 개발 시 보면 html파일은 index(main) 파일 1개 뿐이고 안의 내용들을 런타임에 변경,렌더링한다.- spa 라우팅 : html5의 history api를 이용. js영역에서 history api를 통해 서버로 요청하지 않고 현대 페이지 내에서 화면 이동이 일어난 것 처럼 작동하게 할 수 있다. (back, forward, pushState,.. 세션 기록의 뒤로 이동하거나, 앞으로 이동하거나 데이터를 세션 기록 스택에 넣는 등.)
- spa 프레임워크 : spa 프레임워크인 vue,react 등은 spa를 쉽고 확장성있게 구현할 수 있도록 해준다. 기본 개념은 virtual DOM을 이용해 실제 DOM트리를 흉내낸 가상의 객체 트리로 html 정보를 저장하고있다가, 이 트리에 변경이 발생하면 모든 변화를 모아 단 한번 브라우저를 호출해 화면을 갱신하는 방법을 사용한다. (기존에는 js로인한 dom조작마다 렌더링하여 브라우저 성능을 저하시키는 문제가 있었지만, 정보는 갱신하되 실제 렌더링은 하지 않고있다가 필요할 때 함으로써 빠른 인터랙티브 구현)
- vue
vue는 디자인 패턴 중 mvvm(model, view, viewmodel)과 관련된 프레임워크 중 하나이다. vue가 view model의 역할에 해당하며, vue자체가 mvvm 패턴을 가지는 것은 아니다. view인 DOM과 Model인 js object들 사이 통신을 가능하게 해주는 역할을 한다.
UI와 비지니스 로직을 분리하였다.
- MVVM
Model : 어플리케이션에서 사용되는 데이터, 데이터 처리부
View : 사용자에게 보여지는 UI부분
View Model : View를 표현하기 위해 만든 View를위한 Model. View를 나타내주기 위한 Model을 따로 만든 것이며 View를 나타내기 위한 데이터 처리를 한다.
Command, Databinding 패터을 사용해 view와 view model사이 의존성을 없앰.
사용자 action이 view를 통해 들어오면, view model에 action을 전달하고, view model이 model에게 데이터를 요청하면 model은 view model에게 요청받은 데이터를 응답하고 이 데이터를 view model이 가공하여 저장한다. 최종적으로 view는 view model이 가공하여 저장한 데이터와 view-viewmodel Data binding하여 화면을 나타낸다. - DOM(the Document Object Model) : HTML, XML 문서의 프로그래밍 인터페이스
ES6
ES6에는 let/cost 키워드, 화살표 함수, 클래스, 모듈 기능 등 범용 프로그래밍 언어가 갖추어야할 기능들이 대거 도입되었다. (ES8:2017에는 async/await 도입)
js는 일반적으로 프로그래밍 언어 기본 뼈대인 ECMAscript와 브라우저 별도 지원의 client side web API(DOM,BOM,Canvas, XMLHttpRequst, SVG,WebStorage, Web Component, Web worker) 등을 아우르는 개념.
js 특징
- 인터프리터 언어(Interpreter language) 이지만 속도 단점 완화 ( 모던 자바스크립트 엔진(v8) -> 인터프리터는 소스코드를 즉시 실행하고 컴파일러는 빠르게 동작하는 머신 코드를 생성하고 최적화한다. 이를 통해 컴파일 단계에서 추가적인 시간이 필요함에도 불구하고 보다 빠른 코드의 실행이 가능)
- 자바스크립트는 명령형(imperative), 함수형(functional), 프로토타입 기반(prototype-based) 객체지향 프로그래밍을 지원하는 멀티 패러다임 프로그래밍 언어 : 클래스는 ES6에 도입. 상속,정보,은닉을 위한 키워드인 private는 존재하지 않지만 객체지향 언어이다.
브라우저 동작 원리
javascript : 브라우저에서 동작하는 언어
-
대부분의 프로그래밍 언어는 운영체제(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을 조작한다면 에러가 발생)
JS data type
primitive vs reference type
- primitive data type : 해당 주소에 실제 값을 저장. 변경 불가능한 값(immutable value)이며 pass-by-value(값에 의한 전달)
- number : 부동소수점(실수형)만 존재.
- string : 타 언어와 다른 점은 js에서 string은 primitive type.(문자열 인덱스 접근은 가능하지만 인덱스 접근 수정은 불가능하다.-> 변경 시 재할당해야함)
- boolean : null, undefined,0은 false로 간주.
- undefined : 타입. 유일값. 선언 이후 할당하지 않은 변수. 해당 값이 반환된다면 할당한 적이 없는 변수라는 것을 파악해야함. 이를 위해 값이 없음을 명시할 때에는 null을 할당해줌.
- null : 변수에 값이 없음을 명시할 때 사용. (garbage collection을 위해 사용하지 않는 경우 null을 할당해주어야 이전 값이 메모리에서 제거됨.), null의 경우 일치연산자 (===)을 사용해야함(typeof x) null은 typeof 연산에서 object로 반환되기 때문.
- instanceof 연산자는 피연산자인 객체가 우항에 명시한 타입의 인스턴스인지 여부를 알려준다. 이때 타입이란 constructor를 말하며 프로토타입 체인에 존재하는 모든 constructor를 검색하여 일치하는 constructor가 있다면 true를 반환
- reference type : 해당 주소에 주소값을 저장. 데이터를 의미하는 프로퍼티(property)와 동작을 의미하는 메소드(method)를 포함할 수 있는 독립적 주체. js는 객체 기반 스크립트 언어로 , 원시 타입(Primitives)을 제외한 나머지 값들(배열, 함수, 정규표현식 등)은 모두 객체이다. 또한 객체는 pass-by-reference(참조에 의한 전달) 방식으로 전달
타입 변환
- 명시적 타입 변환(Explicit coercion) 또는 타입 캐스팅(Type casting)
개발자에 의해 의도적으로 값의 타입을 변환 - 암묵적 타입 변환(Implicit coercion) 또는 타입 강제 변환(Type coercion)
자바스크립트 엔진에 의해 암묵적으로 자동 변환( 동적 타입 언어 )
자바스크립트 엔진은 표현식을 평가할 때 문맥, 즉 컨텍스트(Context)에 고려하여 암묵적 타입 변환을 실행
호이스팅
호이스팅이란, var선언문이나 function선언문 등 모든 선언문이 해당 Scope의 선두로 옮겨진 것 처럼 동작하는 특성. (코드 실행 시(전) 선언문 변수들을 미리 메모리에 할당해놓는 것)
- 변수 생성 및 할당 단계
- 선언 단계(Declaration phase)
변수 객체(Variable Object)에 변수를 등록. 이 변수 객체는 스코프가 참조하는 대상이 된다. - 초기화 단계(Initialization phase)
변수 객체(Variable Object)에 등록된 변수를 메모리에 할당. 이 단계에서 변수는 undefined로 초기화. - 할당 단계(Assignment phase)
undefined로 초기화된 변수에 실제값을 할당.
- 선언 단계(Declaration phase)
var로 선언된 변수는 선언 단계와 초기화 단계가 한 번에 이루어진다. scope가 변수에 등록되고 변수는 메모리에 공간 확보 후 undefined로 초기화. = = 프로그램 실행 전 변수들의 선언과 초기화가 미리 이루어지는 것 = 변수 호이스팅.
스코프
스코프는 참조 대상 식별자(identifier, 변수, 함수의 이름과 같이 어떤 대상을 다른 대상과 구분하여 식별할 수 있는 유일한 이름)를 찾아내기 위한 규칙
- 전역 스코프 (Global scope)
코드 어디에서든지 참조할 수 있다. - 지역 스코프 (Local scope or Function-level scope)
함수 코드 블록이 만든 스코프로 함수 자신과 하위 함수에서만 참조할 수 있다.
대부분의 C-family language는 블록 레벨 스코프(block-level scope)를 따른다. 블록 레벨 스코프란 코드 블록({…})내에서 유효한 스코프를 의미한다. 여기서 “유효하다”라는 것은 “참조(접근)할 수 있다”라는 뜻
하지만 자바스크립트는 함수 레벨 스코프(function-level scope)
-> ES6에서 지원하는 let키워드를 사용하면 블록 레벨 스코프를 사용할 수 있다.
- lexical scope
렉시컬 스코프는 함수를 어디서 호출하는지가 아니라 어디에 선언하였는지에 따라 결정된다. 자바스크립트는 렉시컬 스코프를 따르므로 함수를 선언한 시점에 상위 스코프가 결정된다. 함수를 어디에서 호출하였는지는 스코프 결정에 아무런 의미를 주지 않는다.
함수레벨 스코프, 블록레벨 스코프
자바스크립트의 변수는 다른 C-family와는 달리 블록 레벨 스코프(block-level scope)를 가지지 않고 함수 레벨 스코프(function-level scope)를 가짐. 단 ES6의 let, const 키워드 사용 시 block level scope 사용 가능.
- 함수 레벨 스코프(Function-level scope)
함수 내에서 선언된 변수는 함수 내에서만 유효하며 함수 외부에서는 참조할 수 없다. 즉, 함수 내부에서 선언한 변수는 지역 변수이며 함수 외부에서 선언한 변수는 모두 전역 변수이다. - 블록 레벨 스코프(Block-level scope)
코드 블록 내에서 선언된 변수는 코드 블록 내에서만 유효하며 코드 블록 외부에서는 참조할 수 없다.
var , let, const
-
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변수 참조하는 함수가 존재하는 한 계속 유지된다.
객체
Javascript의 객체
자바스크립트는 객체(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 프로퍼티
함수 객체만 가지고 있는 프로퍼티이다.
함수 객체가 생성자로 사용될 때 이 함수를 통해 생성될 객체의 부모 역할을 하는 객체(프로토타입 객체)를 가리킨다.
- [[Prototype]]
-
프로토타입 객체는 constructor 프로퍼티를 갖는다. 이 constructor 프로퍼티는 객체의 입장에서 자신을 생성한 객체를 가리킨다.
-
Prototype chain
프로토타입 체인 : 자바스크립트는 특정 객체의 프로퍼티나 메소드에 접근하려고 할 때 해당 객체에 접근하려는 프로퍼티 또는 메소드가 없다면 [[Prototype]]이 가리키는 링크를 따라 자신의 부모 역할을 하는 프로토타입 객체의 프로퍼티나 메소드를 차례대로 검색.- 샘성자함수, 객체 리터럴을 이용해서 person이라는 객체를 생성했다면, Object 객체를 부모로 갖게된다.(자바스크립트 엔진은 객체 리터럴로 객체를 생성하는 코드를 만나면 내부적으로 Object() 생성자 함수를 사용하여 객체를 생성한다.)
- 샘성자함수, 객체 리터럴을 이용해서 person이라는 객체를 생성했다면, Object 객체를 부모로 갖게된다.(자바스크립트 엔진은 객체 리터럴로 객체를 생성하는 코드를 만나면 내부적으로 Object() 생성자 함수를 사용하여 객체를 생성한다.)
-
프로토타입 체인 동작 조건
객체의 프로퍼티를 참조하는 경우, 해당 객체에 프로퍼티가 없는 경우, 프로토타입 체인이 동작
가장 일반적인 자바스크립트의 객체 생성 방식
-
객체 리터럴
중괄호({})를 사용하여 객체를 생성하는데 {} 내에 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)에 저장
js function(함수)
일급 객체(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 생성자 함수 : 일반적으로 잘 사용하지 않음.
-
함수 호이스팅
함수 선언의 위치와는 상관없이 코드 내 어느 곳에서든지 호출이 가능한데 이것을 함수 호이스팅(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)에 사용된다. (비동기식 처리 모델이란 처리가 종료하면 호출될 함수(콜백함수)를 미리 매개변수에 전달하고 처리가 종료하면 콜백함수를 호출하는 것)
콜백함수는 콜백 큐에 들어가 있다가 해당 이벤트가 발생하면 호출.
콜백 함수는 클로저이므로 콜백 큐에 단독으로 존재하다가 호출되어도 콜백함수를 전달받은 함수의 변수에 접근할 수 있다.
이벤트 루프는 콜 스택에 현재 실행 중인 실행 컨텍스트가 있는지, 태스크 큐에 대기중인 함수(콜백 함수, 이벤트 핸들러..)가 있는지 반복해서 확인한다. 콜스택이 비어 있고 태스크 큐에 대기중인 함수가 있다면 이벤트 루프는 순차적으로 태스크 큐에 대기 중인 함수를 콜스택으로 이동시킨다. 이때 콜 스택으로 이동한 함수는 실행된다.
this
C++에서의 this는 인스턴스 자신(self)을 가리키는 참조변수이다. this가 객체 자신에 대한 참조 값을 가지고 있다는 뜻.
하지만 자바스크립트의 경우 Java와 같이 this에 바인딩되는 객체는 한가지가 아니라 해당 함수 호출 방식에 따라 this에 바인딩되는 객체가 달라진다.
this 기본 바인딩 : 전역객체
this는 전역 객체(window)를 context 객체로 갖는다.
전역 스코프에서 정의한 변수들은 전역 객체에 등록된다.
this 임시적 바인딩
어떤 객체를 통해 함수가 호출된다면 그 객체가 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)에 접근 가능한 것이다
this 명시적 바인딩
function test() {
console.log(this);
}
var obj = { name: "yuddomack" };
test.call(obj); // { name: 'yuddomack' }
test.call("원시 네이티브 자료들은 wrapping 됩니다"); // [String: '원시 네이티브 자료들은 wrapping 됩니다']
함수 객체는 call이라는 메소드를 가지고있는데, call의 첫 번째 인자로 넘겨주는 것이 context 객체가 된다. context를 명시해주는 것.
this new 바인딩
새 객체가 만들어지고, 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(문서 객체 모델, Document Object Model)
DOM TREE
브라우저의 렌더링 엔진은 웹 문서를 로드한 후, 파싱하여 웹 문서를 브라우저가 이해할 수 있는 구조로 구성하여 메모리에 적재하는데 이를 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
동기 처리 모델 vs 비동기 처리 모델
동기 vs 비동기
동기식 처리 모델(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
Ajax(Asynchronous JavaScript and XML)는 자바스크립트를 이용해서 비동기적(Asynchronous)으로 서버와 브라우저가 데이터를 교환할 수 있는 통신 방식을 의미
서버로부터 웹페이지가 반환되면 화면 전체를 갱신해야 하는데 페이지 일부만을 갱신하고도 동일한 효과를 볼 수 있도록 하는 것이 Ajax이다. 페이지 전체를 로드하여 렌더링할 필요가 없고 갱신이 필요한 일부만 로드하여 갱신하면 되므로 빠른 퍼포먼스와 부드러운 화면 표시 효과를 기대할 수 있다.
JSON (JavaScript Object Notation)
클라이언트와 서버 간에는 데이터 교환이 필요하다. JSON(JavaScript Object Notation)은 클라이언트와 서버 간 데이터 교환을 위한 규칙 즉 데이터 포맷을 말한다.
JSON은 일반 텍스트 포맷보다 효과적인 데이터 구조화가 가능하며 XML 포맷보다 가볍고 사용하기 간편하며 가독성도 좋다.
자바스크립트의 객체 리터럴과 매우 흡사하다. 하지만 JSON은 순수한 텍스트로 구성된 규칙이 있는 데이터 구조.
XMLHttpRequest
브라우저는 XMLHttpRequest 객체를 이용하여 Ajax 요청을 생성하고 전송한다. 서버가 브라우저의 요청에 대해 응답을 반환하면 같은 XMLHttpRequest 객체가 그 결과를 처리.
이벤트
이벤트(event)는 어떤 사건을 의미한다. 브라우저에서의 이벤트란 예를 들어 사용자가 버튼을 클릭했을 때, 웹페이지가 로드되었을 때와 같은 것인데 이것은 DOM 요소와 관련.
이벤트가 발생하는 시점이나 순서를 사전에 인지할 수 없으므로 일반적인 제어 흐름과는 다른 접근 방식이 필요하다. 즉, 이벤트가 발생하면 누군가 이를 감지할 수 있어야 하며 그에 대응하는 처리를 호출해 주어야 한다.
이벤트 루프와 동시성
브라우저는 단일 쓰레드(single-thread)에서 이벤트 드리븐(event-driven) 방식으로 동작
단일 쓰레드는 쓰레드가 하나뿐이라는 의미이며 이말은 곧 하나의 작업(task)만을 처리할 수 있다는 것을 의미 ->
동시에 task들이 진행되는 것 처럼 느껴지게 해주는 것(동시성 지원) : 자바스크립트의 동시성(Concurrency)을 지원하는 것이 바로 이벤트 루프(Event Loop)
V8비롯한 자바스크립트 엔진들은 크게 2개의 영역으로 나뉜다.
js 엔진
- Call Stack(호출 스택)
작업이 요청되면(함수가 호출되면) 요청된 작업은 순차적으로 Call Stack에 쌓이게 되고 순차적으로 실행된다. 자바스크립트는 단 하나의 Call Stack을 사용하기 때문에 해당 task가 종료하기 전까지는 다른 어떤 task도 수행될 수 없다. - Heap
동적으로 생성된 객체 인스턴스가 할당되는 영역이다.
자바스크립트 엔진은 단순히 작업이 요청되면 Call Stack을 사용하여 요청된 작업을 순차적으로 실행할 뿐이다. 앞에서 언급한 동시성(Concurrency)을 지원하기 위해 필요한 비동기 요청(이벤트를 포함) 처리는 자바스크립트 엔진을 구동하는 환경 즉 브라우저(또는 Node.js)가 담당
자바스크립트 엔진 실행환경(브라우저, nodejs)
- Event Queue(Task Queue)
비동기 처리 함수의 콜백 함수, 비동기식 이벤트 핸들러, Timer 함수(setTimeout(), setInterval())의 콜백 함수가 보관되는 영역으로 이벤트 루프(Event Loop)에 의해 특정 시점(Call Stack이 비어졌을 때)에 순차적으로 Call Stack으로 이동되어 실행된다. - Event Loop(이벤트 루프)
Call Stack 내에서 현재 실행중인 task가 있는지 그리고 Event Queue에 task가 있는지 반복하여 확인한다. 만약 Call Stack이 비어있다면 Event Queue 내의 task가 Call Stack으로 이동하고 실행된다.
REST API / SPA
REST
웹의 장점을 최대한 활용할 수 있는 아키텍쳐로서 REST를 소개하였고 이는 HTTP 프로토콜을 의도에 맞게 디자인하도록 유도하고 있다. REST의 기본 원칙을 성실히 지킨 서비스 디자인을 “RESTful”이라고 표현.
REST : URI는 정보의 자원을 표현해야한다.
REST : 자원에 대한 행위는 HTTP Method(GET, POST, PUT, DELETE 등)으로 표현
SPA
단일 페이지 애플리케이션(Single Page Application, SPA)는 모던 웹의 패러다임.
SPA 장점
- SPA는 기본적으로 단일 페이지로 구성되며 기존의 서버 사이드 렌더링과 비교할 때, 배포가 간단하며 네이티브 앱과 유사한 사용자 경험을 제공할 수 있다는 장점.
- SPA는 기본적으로 웹 애플리케이션에 필요한 모든 정적 리소스를 최초 접근시 단 한번만 다운로드.
- 새로운 페이지 요청 시, 페이지 갱신에 필요한 데이터만을 JSON으로 전달받아 페이지를 갱신하므로 전체적인 트래픽을 감소시킬 수 있고, 전체 페이지를 다시 렌더링하지 않고 변경되는 부분만을 갱신하므로 새로고침이 발생하지 않음.
SPA 단점
- 초기 구동 속도
SPA는 웹 애플리케이션에 필요한 모든 정적 리소스를 최초 접근시 단 한번 다운로드하기 때문에 초기 구동 속도가 상대적으로 느리다. 하지만 SPA는 웹페이지보다는 애플리케이션에 적합한 기술이므로 트래픽 감소와 속도, 사용성, 반응성의 향상 등의 장점을 생각한다면 결정적인 단점이라고 할 수는 없다. - SEO(검색엔진 최적화) 이슈
SPA는 일반적으로 서버 사이드 렌더링(SSR) 방식이 아닌 자바스크립트 기반 비동기 모델의 클라이언트 사이드 렌더링(CSR) 방식으로 동작한다. 클라이언트 사이드 렌더링(CSR)은 일반적으로 데이터 패치 요청을 통해 서버로부터 데이터를 응답받아 뷰를 동적으로 생성하는데 이때 브라우저 주소창의 URL이 변경되지 않는다. 이는 사용자 방문 history를 관리할 수 없음을 의미하며 SEO 이슈의 발생 원인이기도 하다. SPA의 SEO 이슈는 언제나 단점으로 부각되어 왔다. SPA는 정보 제공을 위한 웹페이지보다는 애플리케이션에 적합한 기술이므로 SEO 이슈는 심각한 문제로 취급할 수 없다고 생각할 수도 있지만 블로그와 같이 애플리케이션의 경우 SEO는 무시할 수 없는 중요한 의미를 갖는다. Angular나 React 등의 SPA 프레임워크는 서버 사이드 렌더링(SSR)을 지원하는 기능이 이미 존재하고 있고 크롬 등의 모던 브라우저는 SPA의 SEO 문제를 해결하고 있는 것으로 알려져 있다.
멀티 페이지 어플리케이션 : SSR(Server Side Rendering)
서버사이드 렌더링의 약자로 서버로부터 완전하게 만들어진 html파일을 받아와 페이지 전체를 렌더링 하는 방식
싱글 페이지 어플리케이션 : CSR(Client Side Rendering)
클라이언트 사이드 렌더링 이란 사용자의 요청에 따라 필요한 부분만 응답 받아 렌더링 하는 방식
Author And Source
이 문제에 관하여(javascript 빠른 요약), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@jeongsunyong/javascript-빠른-요약저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)