랄지 IT
자바스크립트 정리 본문
브라우저 동작원리
- 브라우저의 핵심기능은 웹페이지를 서버에 요청(request)하고, 서버의 응답(response)받아 브라우저에 표시하는 것이다
- HTML, CSS 파일은 파서에 의해 파싱되어 DOM, CSSOM 트리로 변환되고, 렌더 트리로 결합된다. 렌더트리를 기반으로 브라우저는 웹페이지를 표시한다.
- HTML 파서는 script 태그를 만나면 DOM 생성 프로세스를 중지하고, 자바스크립트 엔진으로 제어 권한을 넘긴다. 자바스크립트 실행이 완료되면, 다시 HTML 파서로 제어 권한을 넘겨서 DOM 생성을 재개한다.
- 브라우저는 동기적으로 HTML, CSS, JS를 처리한다. 이것은 script 태그 위치에 따라 블로킹이 발생하여 DOM생성이 지연될 수 있다는 것을 의미한다.
자바스크립트 기본 문법
- 데이터 타입: 값의 종류
- 변수: 값이 저장된 메모리 공간의 주소를 가리키는 식별자
- 리터럴: 값 자체를 말함
- 변수에 할당된 값의 타입에 의해 동적으로 변수 타입이 결정된다. 이를 동적타이핑 이라 한다.
- 프로그램은 수행될 명령들의 집합이다. 각각의 명령을 문(statement)라 한다. 문은 연산차, 표현식, 키워드 등으로 구성된다.
- 표현식은 하나의 값으로 평가 된다. 표현식은 결국 하나의 값이 된다. 예) 5*50은 50으로 평가된다.
- 문은 하나의 완전한 문장이고, 표현식은 문을 구성하는 요소이다.
- 함수란 문들의 집합을 정의한 코드 블록이다. 매개변수를 갖고, 호출하여 실행할 수 있다.
데이터 타입과 변수
- 프로그래밍은 값을 저장하고 참조하며 값을 연산, 평가하고 데이터의 흐름을 제어하며 함수로 재사용이 가능한 구문의 집합을 만들어 자료를 구조화 하는 것이다.
- 원시타입의 값은 변경 불가능한 값이며, pass-by-value(값에 의한 전달)이다.
- 자바스크립트의 숫자타입은 모든 수를 실수 처리한다. 예) 1 === 1.0 //true
- undefined: 선언이후, 값을 할당하지 않은 변수 혹은 존재하지 않는 객체 프로퍼티
- null: 의도적으로 변수에 값이 없다는 것을 명시할때 사용. 메모리 어드레스의 참조 정보를 제거하는 것을 의미함.
- 객체 타입: 원시타입을 제외한 나머지 값들(배열, 함수 등)은 모두 객체이다. 객체는 pass-by-reference(참조에 의한 전달)방식이다.
- 값을 할당하지 않은 변수(선언만 되어 있는 변수)는 undefined로 초기값을 갖는다. 선언하지 않은 변수에 접근하면 참조에러(ReferenceError)가 발생한다.
- 변수는 3단계에 걸쳐 생성된다.
1. 선언 단계: 변수 객체(VO)에 변수를 등록함
2. 초기화 단계: VO에 등록된 변수를 메모리에 할당함 (undefined로 초기화)
3. 할당 단계: 실제값을 할당함
- var 키워드로 선언된 변수는 1,2단계(선언,초기화)가 한번에 이루어진다. 즉, 메모리에 공간을 확보한후 undefined으로 초기화 됨.
연산자
- 표현식은 (리터럴, 식별자, 연산자, 함수 호출 등의) 조합을 말한다.
- 표현식은 평가하여 하나의 값을 만든다.
- 연산자 표현식: 표현식을 결합해 새로운 값을 만들어 내는 가장 일반적인 표현식이다. 예) x + 30
- 자바스크립트의 모든 코드는 문 또는 표현식이다. 문이 완전한 문장이라고 한다면, 표현식은 문을 구성하는 요소이다.
- 표현식의 역할은 값을 생성하는 것이고, 문의 역할은 값을 사용해 컴퓨터에게 명령을 내리는 것이다.
- 선언문은 (표현식이 아닌) 문이다. 할당문은 그 자체가 (문이기도 하면서 동시에) 표현식이다.
선언문 예) var x = 5*10
할당문 예) x = 100
- 단항 산술 연산자: 1개의 피연산자를 대상으로 연산한다. 예) ++, --, +, -
- 산술연산자 예제 중,
1 + null // 1
1 + undefined // NaN
- 동등 비교(==) 연산자는 암묵적 타입 변환을 통해 타입을 일치시킨 후 같은 값을 갖는지 비교한다.
- NaN은 자신과 일치하지 않는 유일한 값이다. 예) NaN === NaN // false
숫자가 NaN인지 조사하려면 빌트인 함수 isNaN을 사용한다. 예) isNaN(NaN) // true
- 숫자 0 주의 예) 0 === -0
- 삼항 조건 연산자 표현식은 값으로 평가할 수 있는 표현식이다. 다른 표현식의 일부가 될 수 있어 유용하다.
- 논지 부정(!) 연산자는 언제나 불리언 값을 반환한다. 하지만 논리합(||) 연산자와 논리곱(&&) 연산자는 반드시 불리언 값을 반환하는 것은 아니다.
예) false && false // false
- 단축 평가: 결과를 결정한 값을 반환
예) 'Cat' && 'Dog' // 'Dog'
예) 'Cat' || 'Dog' // 'Cat'
예) var el = null; el.value => Error // el && el.value => null
예) str = str || '' // 단축평가를 이용한 매개변수의 기본값을 설정해줄 수 도 있음
- 쉼표(,) 연산자는 차례대로 평가하고 마지막 피연산자의 평가가 끝나면 마지막 피연산자의 평가결과를 반환한다.
예) var x, y, z;
x =1, y=2, z= 3; // 3
- typeof 연산자는 7가지 문자열 중 하나를 반환한다. 선언하지 않은 식별자를 typeof 하면 undefined를 반환함
: string, number, boolean, undefined, symbol, object, function
제어문
- 블록문{}은 단독으로 사용할 수도 있으나, 일반적으로 제어문이나 함수 선언문 등에서 사용한다.
- switch문에 break를 상요하지 않으면 탈출하지 않고 switch문이 끝날때까지 모든 case문과 default문을 실행하는데 이를 풀스루라 한다.
- while문을 true로 무한루프할때, 탈출을 위해서는 while문 내에 if문을 부여하고, break문으로 코드블록을 탈출 한다.
- break문은 레이블 문, 반복문, switch문의 코드블록 이외에 사용하면 문법에러(SyntaxError)가 발생한다.
- 레이블 문은 식별자가 붙은 문이다. 레이블 문은 일반적으로 권장하지 않는다.
예) foo: {...}
- continue문은 반복문을 중단하고 반복문의 처음(증감식)으로 이동한다. 중단되지는 않는다.
- if문에서 실행해야할 코드가 길다면 continue문을 사용하는 것이 가독성이 좋다.
타입 변환
- 개발자에 의해 의도적으로 값의 타입을 변환하는 것을 명시적 타입 변환 또는 타입 캐스팅 이라고 한다. 예) toString
- 개발자의 의도와 상관없이 자바스크립트 엔진에 의해 암묵적으로 타입이 자동 변환 되는 것을 암무적 타입 변환 또는 타입 강제 변환 이라고 한다. 예) 1+''
- 암묵적 타입 변환은 기존 값을 바탕으로 새로운 타입의 값을 만들어 단 한번 사용하고 버린다. 표현식의 평가가 끝나면 아무도 참조하지 않으므로 메모리에서 제거된다.
- 코드에서 암묵적 타입변환이 발생하는지... 예측할 수 있어야 한다.
- 자바스크립트 엔진은 표현식을 평가할때 문맥, 즉 컨텍스트에 고려하여 암묵적 타입 변환을 실행한다.
예) '10' + 2 // 102
5 * '10' // 50
+연산자는 하나 이상이 문자열이면 문자열 연결 연산자로 동작한다
-, *, / 산술연산자의 역할은 숫자 값을 만드는 것이다. 따라서 문맥, 즉 컨텍스트 상 숫자타입이어야 한다. 피연산자를 숫자타입으로 변환할 수 없는 경우는 NaN을 반환한다
비교(>) 연산자의 역할은 불리언 값을 만드는 것이다.
+단항 연산자는 피연산자가 숫자타입의 값으로 암묵적 타입 변환을 수행한다. 예) +null // 0
- 빈 문자열'', 빈 배열[], null, false는 0으로 true는 1로 변환된다. 객체와 (빈배열이 아닌)배열, undefined는 변환되지 않아 NaN이 된다.
객체
- 자바스크립트의 객체는 객체지향의 상속을 구현하기 위해 프로토타입 이라고 불리는 객체의 프로퍼티와 메소드를 상속 받을 수 있다.
- 객체는 (배열과 달리) 순서를 보장하지 않는다.
- 자바스크립트는 프로토타입 기반 객체 지향 언어로서 클래스라는 개념이 없고 별도의 객체 생성 방법이 존재한다.
* ES6에서 새롭게 클래스 도입. 사실 클래스도 함수이고, 기존 프로토타입 기반 패턴의 문법적 설탕이다.
- 객체를 생성하는 방법은 객체 리터럴을 사용하는 것이 더 간편하다. 예) var obj = {}
- 생성자 함수를 사용하면 마치 객체를 생성하기 위한 템플릿(클래스)처럼 사용하여 프로퍼티가 동일한 객체 여러개를 간편하게 생성할 수 있다.
예) function Person(){}
var p1 = new Person('lee')
- 생성자 함수에서 this는 생성할 인스턴스를 가리킨다.
this.name // public
var name // private
- 예약어를 프로퍼티키로 사용한다고 해서 에러가 발생하는 것은 아니나, 예상치 못한 에러가 발생할 가능성이 있으므로 예약어를 프로퍼티키로 사용해서는 안된다.
- 잘 모르는 예약어 리스트: abstract, debugger, double, final, finally, implements, in, instanceof, long, native, short, throw, throws, transient, volatile, with
- 객체의 프로퍼티 값에 접근하는 방법은 마침표 표기법(객체.키)와 대괄호 표기법(객체['키'])가 있다.
- delete 연산자를 사용하면 객체의 프로퍼티를 삭제할 수 있다. 예) delete person.gender;
- for-in문을 사용하면 객체에 포함된 모든 프로퍼티에 대해 루프를 수행할 수 있다. 객체의 키를 순회하기 위해 사용하고, 배열에 (사용은 가능하지만, 순서 보장X 배열요소만 순회하는 것X) 사용하지 않는 것이 좋다.
- for-in은 객체의 프로퍼티를 순회하기 위해 사용하고, (ES6에서 추가된) for-of문은 배열의 요소를 순회하기 위해 사용한다.
- Pass-by-reference: object type을 객체 타입 또는 참조 타입이라 한다. 변경 가능한 값이다. 힙영역에 저장.
- Pass-by-value: 원시타입은 값으로 전달 된다. (복사되어 전달됨). 스택영역에 저장.
예) var a = {}, b= {}, c = {} // 각각 다른 빈 객체를 참조
a = b = c = {} // 모두 같은 빈객체를 참조
- 오브젝트는 빌트인 오브젝트(내장 객체)와 호스트 오브젝트(사용자가 만든 객체)로 나뉜다.
- 빌트인 오브젝트는 1. 스탠다드 빌트인 오브젝트와 2. 네이티브 오브젝트(BOM, DOM)으로 나뉜다.
객체와 변경불가성
- Immutability(변경 불가성)은 객체가 생성된 이후 그 상태를 변경할 수 없는 디장니 패턴으로, 함수형 프로그래밍의 핵심 원리이다.
- var user2 = user1인 경우, 변경하지도 않은 객체 user1도 동시에 변경되는데 이는 같은 어드레스를 참조하고 있기 때문이다.
- 의도치 않은 객체 변경을 방지하기 위해 객체를 불변 객체로 만들어 프로퍼티의 변경을 방지하는 방법.
1. 객체의 방어적 복사: Object.assign({}, obj) => 객체 내부의 객체는 Shadow copy됨
2. 불변객체화를 통한 객체 변경 방지: Object.freeze(obj) => 객체 내부의 객체는 Shadow copy됨, Deep freeze해야 한다
3. facebook이 제공하는 Immutable.js를 사용 => npm으로 설치후, Map모듈을 임포트하여 사용
=> 1,2방법은 번거로울 뿐더러 성능상 이슈도 있어서 3번 사용을 추천함.
함수
- 함수도 객체이므로 다른 값들처럼 사용할 수 있음. 즉 변수나 객체, 배열등에 저장하거나 다른 함수에 전달되는 인수로도 사용하능하고, 함수의 반환값이 될 수도 있음.
- 함수 선언식: function test(){...}
- 함수 표현식 var square = function (){...}
- 함수 표현식은 함수명을 생략하는 것이 일반적이다.
- 함수 선언문의 경우, 함수 선언의 위치와는 상관없이 코드 내 어느 곳에서든지 호출이 가능한데, 이것을 함수 호이스팅 이라고 한다. (초기화와 할당이 한번에 이루어짐)
* 호이스팅이란, 모든 선언문이 해당 스코프의 선두로 옮겨진 것처럼 동작하는 특성을 말함. 즉, 선언되기 이전에 참조 가능함.
- 함수 표현식은 변수 호이스팅이 발생함 (초기화와 할당이 분리되어 진행)
- 되도록이면 함수 표현식만을 사용할 것을 권고하고 있음
- 일급객체란, 프로그래밍 언어의 기본적 조작을 제한 없이 사용할 수 있는 대상을 의미한다. 다음의 네가지를 만족해야 함. (자바스크립트 함수는 모두 해당되어 일급객체임 )
1. 무명의 리터럴로 표현 가능
2. 변수나 자료구조에 저장 가능
3. 함수의 매개변수에 전달 가능
4. 반환값으로 사용 가능
- 매개변수(parameter, 인자) => 추가적인 정보가 필요할 경우 지정함
- 인수(argument) => 호출하는 함수에 전달함
- 원시타입 인수는 call-by-value(값에 의한 호출)로 동작하여 함수내에서 매겨변수를 통해 값이 변경되어도 전달이 완료된 원시타입값은 변경되지 않는다.
- 객체형(참조형) 인수는 call-by-reference(참조에 의한 호출)로 동작하여 객체의 참조값이 매개변수에 저장되어 함수로 전달될때, 함수내에서 객체의 값을 변경할 경우, 전달되어진 참조형의 인수값도 같이 변경된다.
- 함수도 프로퍼티를 가질 수 있다. 다음은 함수의 프로퍼티들 이다
1. arguments: 함수 호출시 전달된 인수들의 정보를 담고 있는 유사 배열 객체이고, 함수 내부에서 지역변수처럼 사용된다. 매개변수 갯수가 확정되지 않은 가변 인자 함수를 구현할 때 유용하게 사용된다
2. caller: 자신을 호출한 함수를 의미함
3. length: 함수 정의시 작성된 매개변수 갯수 // argument는 호출시 인자의 갯수임 length는 인수의 갯수
4. name: 함수명 // 익명함수의 경우 빈문자열
5. __proto__ : 프로토타입 객체는 상속을 구현하기 위해 사용되며, 다른 객체에 공유프로퍼티를 제공하는 객체임. __proto__프로퍼티는 프로토타입 객체에 (간접적으로)접근하기 위해 사용되는 접근자 프로퍼티임.
6. prototype: 함수 객체만이 소유하는 프로퍼티임. 함수가 객체를 생성하는 생성자 함수로 사용될때, 생성자 함수가 생성한 인스턴스의 프로토타입 객체를 가리킴.
- 즉시 실행 함수(IIFE): 즉시실행 함수 내에 처리 로직을 모아두면 혹시 있을 수도 있는 변수명 또는 함수명의 충돌을 방지할 수 있다. 그리고 제이쿼리와 같은 라이브러리의 경우, 코드를 즉시실행 함수 내에 정의해 두면, 라이브러리의 변수들이 독립된 영역 내에 있게 되므로 여러 라이브러리들을 동시에 사용하더라도 변수명 충돌과 같은 문제를 방지할 수 있다.
- 재귀 함수는 반복연산을 간단히 구현할 수 있다는 장점이 있지만, 무한 반복에 빠질 수도 있고 스톡오버플로우 에러를 발생시킬 수 있으므로 주의하여야 한다. 대부분의 재귀함수는 반복문으로 구현이 가능하므로, 필요한 경우에 한하여 한정적으로 적용하는 것이 바람직하다.
- 콜백함수는 특정이벤트가 발생했을 때 시스템에 의해 호출되는 함수이다. 대표적인 예는 이벤트 핸들러 처리이다. 어느 특정 시점에 실행된다. 콜백함수는 주로 비동기식 처리 모델에 사용된다. 비동기식 처리 모델이란, 처리가 종료하면 호출될 함수(콜백함수)를 미리 매개변수에 전달하고 처리가 종료하면 콜백함수를 호출하는 것이다.
콜백함수는 콜백 큐에 들어가 있다가 해당 이벤트가 발생하면 호출된다. 콜백 함수는 클로저이므로 콜백 큐에 단독으로 존재하다가 호출되어도 콜백함수를 전달받은 함수의 변수에 접근할 수 있다.
타입 체크
- 자바스크립트의 동적 타이핑 때문에 타입체크가 필요함.
*동적타이핑: 변수나 반환값의 타입을 사전에 지정하지 않는 특성, 어떤 값이 할당될지 예측 어려움
- Function.prototype.call 메소드를 사용하면 모든 타입의 값을 알아낼 수 있다
*ex) Object.prptotype.toString.call('') // [object String]
- HTMLDocument
ㄴ HTMLHeadElement
ㄴ HTMLBodyElement
ㄴ HTMLTitleElement
ㄴ HTMLParagraphElement
ㄴ HTMLInputElement
ㄴ HTMLTableElement
ㄴ etc...
- 유사 배열 객체(array-like-object)는 length프로퍼티를 갖는 객체로 문자열, arguments, HTMLCollection, NodeList 등이 있다. 순회할 수 있으며 call, apply 함수를 사용하여 배열의 메소드를 사용할 수 있다.
프로토타입
- 자바스크립트의 모든 객체는 자신의 부모 역할을 담당하는 객체와 연결되어 있다.
객체 지향의 상속 개념과 같이 부모객체의 프로퍼티 또는 메소드를 상속받아 사용할 수 있게 한다.
이러한 부모 객체를 Prototype(프로토타입) 객체 또는 Prototype이라고 한다.
- 자바스크립트의 모든 객체는 [[Prototype]]이라는 인터널슬롯을 가진다.
[[Prototype]]의 값은 null 또는 (프로토타입)객체이며 상속을 구현하는데 사용되고,
__proto__프로퍼티로 접근할 수 있다.
*인터널슬롯: 내부속성, 은닉속성
- 함수도 객체이므로 [[Prototype]] 인터널 슬롯을 갖는다.
함수는 일반 객체와는 달리 prototype 프로퍼티도 소유하게 된다.
*prototype 프로퍼티와 [[Prototype]] 인터널슬롯은다르다.
*[[Prototype]]: 함수를 포함한 모든 객체가 가지고 있는 인터널 슬롯, 자신의 부모 역할을 하는 프로토타입 객체를 가리킴
*prototype 프로퍼티: 함수 객체만이 가지고 있는 프로퍼티, 함수 객체가 생성자로 사용될 때 생성될 객체(인스턴스)의 부모 역할을 하는 객체
- var foo = new Person('Lee')
foo 객체 입장에서 자신을 생성한 객체는 Person()생성자 함수이며,
foo 객체의 프로토타입 객체는 Person.prototype이다.
따라서 프로토타입 객체 Person.prototype의 constructor 프로퍼티는 Person() 생성자 함수를 가리킨다.
foo.constructor === Person
Person.constructor === Function()
- 프로토타입 체인:
특정 객체의 프로퍼티나 메소드에 접근하려고 할때, 해당 객체에 없으면,
[[Prototype]]이 가리키는 링크를 따라 자신의 부모 역할을 하는 프로토타입 객체의 프로퍼티나 메소드를 차례대로 검색한다.
결국 모든 객체의 부모 객체인 Object.prototype 객체에서 프로토타입 체인이 끝난다.
*해당 객체에 프로퍼티가 없는 경우, 프로토타입 체인이 동작한다.
- Object.prototype 객체는프로토타입 체인의 종점으로 모든 객체가 사용할 수 있는 메소드를 갖는다.
- 자바스크립트는 표준 내장 객체(ex. Array 등)의 프로토타입 객체에 개발자가 정의한 메소드의 추가를 허용한다.
스코프
- 스코프는 참조 대상 식별자(ex. 변수 이름 등)을 찾아내기 위한 규칙이다.
식별자는 자신이 어디에서 선언됐는지에 의해 자신이 유효한(다른코드가 자신을 참조하는)범위를 갖는다.
전역에 선언된 변수는 어디에든 참조할 수 있고,
함수 내에서 선언된 변수는 함수 내부에서만 참조 할 수 있다. 라는 규칙이 스코프이다.
- 모든 변수는 스코프를 갖는다.
- 전역 변수의 사용은 억제하여야 한다.
변수 이름이 중복될 수 있고, 의도치 않은 재할당에 의한 변화로 코드 예측을 어렵게 만든다.
- 함수 밖에서 선언된 변수는 코드 블록 내에서 선언되었다할지라도 모두 전역 스코프를 갖게 된다.
(ex. 블록{}안에서 선언되었더라도 함수블록이 아니라면 전역 변수란 말임)
- 중첩 스코프는 가장인접한 지역을 우선하여 참조한다.
- 함수의 실행결과는 상위 스코프가 무엇인지에 따라 결정된다.
1. 동적 스코프: 함수를 어디서 호출하였는지에 따라 상위 스코프를 결정함.
2. 렉시컬(정적) 스코프: 함수를 어디에서 선언하였는지에 따라 상위 스코프를 결정함.
- 암묵적전역: 선언하지 않은 식별자는 전역 객체의 프로퍼티가 된다.
- 전역 변수는 프로퍼티지만, delete 연산자로 삭제할 수 없다.
하지만 암묵적 전역변수의 경우는 delete 연산자로 삭제가 가능하다.
- 전역 변수 사용을 최소화하는 방법 중 하나는, 전역 변수 객체를 하나 만들어서 사용하는 것이다.
ex) var MYAPP = {}
MYAPP.student = {...}
- 전역 변수 사용을 억제하기 위해 즉시실행함수(IIFE)을 사용할 수 있다.
(라이브러리 등에서 자주 사용하는 방식으로) 즉시 실행디ㅗ고, 그 후 전역에서 바로 사라진다.
strict mode
- 보다 안정적인 스크립트 개발 환경을 위해 자바스크립트 문법을 보다 엄격히 적용하는 것이다.
- ESLint와 같은 린트 도구를 사용하여도 유사한 효과를 얻을 수 있다.
- 전역의 선두 또는 함수 몸체의 선두에 'use strict';를 추가한다.
*전역에 strict mode 적용은 바람직하지 않다.
- 스크립트 단위로 적용된 strict mode는 다른 스크립트에 영향을 주지 않고, 자신의 스크립트에 한정되어 적용된다.
- 바람직한 사용방법은 즉시실행함수로 스크립트 전체를 감싸서 스코프를 구분하고 즉시실행함수의 선두에 strict mode를 적용하는 것이다.
- strict mode를 사용하면
1. 암묵적 전역변수 X
2. 변수, 함수, 매개변수의 삭제(delete) X
3. 함수를 일반 함수로서 호출하면 this에 undefined가 바인딩 된다.
- IE9이하는 지원하지 않는다.
this
- 함수는 호출 될때, arguments 객체와 this를 암묵적으로 전달 받는다.
- this에 바인딩 되는 객체는 함수 호출 방식에 따라 달라진다.
- 함수 호출 방식
1. 함수 호출 foo();
2. 메소드 호출 obj.foo();
3. 생성자 함수 호출 new Foo();
4. appy/call/bind 호출 foo.call(bar);
- 기본적으로 this는 전역객체에 바인딩 된다.
(메소드의 내부함수, 콜백 함수 등 전역객체에 바인딩 됨)
- 내부 함수의 this가 전역 객체를 참조하는 것을 회피하려면 var that = this 이런식으로 (부모)함수내에서 잡아 준다음에 내부 함수 자신의 블록안에서 that을 받으면 된다. var that = this
또는, this를 명시적으로 바인딩 할 수 있는 appy, call, bind 메소드를 내부함수 선언 후 잡아 주면 된다. bar.appy(obj, [1,2])
- 객체 리터럴 방식(var obj = {...})의 경우, 생성된 객체의 프로토타입 객체는 Object.prototype 이다.
생성자 함수 방식(var p = new Person())의 경우, 생성된 객체의 프로토 타입 객체는 Person.prototype 이다.
- 일반적으로 생성자 함수 명은 첫문자를 대문자로 기술하여 혼란을 방지하려는 노력을 하지만,
이러한 규칙을 사용한다 하더라도 실수는 발생할 수 있다.
이러한 위험성을 회피하기 위해 사용되는 패턴(Scope-Safe Constructor)은 arguments.callee을 사용하는 것이다.
- this에 바인딩될 객체는 함수 호출 패턴에 의해 결정된다.
this를 특정 객체에 명시적으로 바인딩하는 방법도 제공된다. (apply, call, bind 호출)
ex) func.appy(객체, [인수arr])
- appy()메소드의 대표적인 용도는 유사 배열 객체에 배열 메소드를 사용하는 경우이다. 유사 배열 객체는 배열이 아니기 때문에 splice() 같은 배열의 메소드를 사용할 수 없으나, appy() 메소드를 이용하면 가능하다.
- 콜백 함수를 호출하는 외부 함수 내부의 this와 콜백 함수 내부의 this가 상이하기 때문에 문맥상 문제가 발생할 수 있다. 따라서 콜백함수 내부의 this를 콜백함수를 호출하는 함수 내부의 this와 일치시켜주어야 하는 번거로움이 발생한다. (call이나 bind 사용)
ex) callback.call(this);
callback.bind(this)(); //bind는 명시적으로 함수를 호출해줘야 함
실행 컨텍스트
- 실행 컨텍스트는 스코프, 호이스팅, this, function, 클로저 등의 동작원리를 담고 있는 자바스크립트의 핵심원리이다.
- 실행 컨텍스트는 실행 가능한 코드가 실행되기 위해 필요한 환경이라고 말할 수 있다.
* 실행가능한 코드: 전역코드, Eval 코드, 함수 코드
- 자바스크립트 엔진은 코드를 실행하기 위해 필요한 여러가지 정보(변수, 함수선언, 변수의 유효범위:스코프, this)를 알고 있어야 한다.
- 코드를 실행하면 실행 컨텍스트 스택이 생성하고 소멸한다. 함수가 실행되게 되면, 새 컨텍스트가 생성된다. 이 컨텍스트는 스택에 쌓이게 되고 컨트롤(제어권)이 이동한다.
*스택: LIFO(후입 선출: 나중에 들어온 것이 먼저 빠지는)의 나열 구조이다.
- 전역 실행 컨텍스트는 애플리케이션이 종료(창을 닫을때)될때까지 유지된다.
- 함수를 호출하면 해당 함수의 실행 컨텍스트가 생성되며, 직전에 실행된 코드 블록의 실행 컨텍스트위에 쌓인다.
- 함수 실행이 끝나면 해당 함수의 실행 컨텍스트를 파기하고, 직전의 실행컨텍스트에 컨트롤을 반환한다.
- 실행 컨텍스트의 3가지 객체는 변수 오브젝트(VO), 스코프 체인, thisValue 이다.
1. VO: 실행에 필요한 여러 정보(변수, 매개변수, 인수정보, 함수 선언)를 담을 객체
*전역 코드 실행시 생성되는 전역 컨텍스트의 경우와
함수 실행시 생성되는 함수 컨텍스트의 경우 가리키는 객체(VO)가 다르다.
*전역 컨텍스트의 경우 전역 변수와 전역 함수를 가리키는 GO이고,
함수 컨텍스트의 경우 활성객체(AO)를 가리키며 매개변수와 인수들의 정보를 배열 형태로 담고 있는 객체인 arguments object가 추가된다.
2. 스코프 체인(SC): 일종의 리스트이다. 해당 전역 또는 함수가 참조할 수 있는 변수와 GO 혹은 AO의 리스트를 가리킨다.
스코프 체인은 식별자인 변수를 검색하는 메커니즘(작동원리)이다.
변수를 만나면 현재 스코프에서 검색해보고 검색 실패시 스코프 체인에 담겨진 순서대로 그 검색을 이어가는 것.
함수의 감추어진 프로퍼티인 [[Scope]]로 참조할 수 있다.
3. this value: this 프로퍼티에는 this값이 할당되고, 할당되는 값은 함수 호출 패턴에 의해 결정된다.
초기 상태의 전역 객체에는 빌트인 객체(Math, String, Array 등)와 BOM, DOM이 설정되어 있다.
- 전역 코드의 함수 foo가 실행되기 시작하면, 새로운 함수 실행 컨텍스트가 생성된다. 함수 foo 로 컨트롤이 이동하면 전역 코드의 경우와 마찬가지로 1. 스코프 체인의 생성과 초기화 2. 변수 객체화 실행, 3. this value 결정이 순차적으로 실행된다.
* Variable Instantiation(변수 객체화) : VO에 프로퍼티와 값을 추가하는 것.
클로저
- 외부함수내에 내부 함수가 선언되고, 내부함수는 외부 함수의 변수에 접근할 수 있다.
- 내부함수가 상위 스코프에 접근할 수 있는 것은 렉시컬 스코프(함수를 어디에 선언?)의 레퍼런스를 차례대로 저장하고 있는 실행 컨텍스트의 스코프 체인을 자바스크립트 엔진이 검색하였기에 가능한 것이다.
- 자신을 포함하고 있는 외부함수보다 내부함수가 더 오래 유지되는 경우 외부 함수 밖에서 내부함수가 호출되더라도 외부함수의 지역변수에 접근할 수 있는데, 이러한 함수를 클로저 라고 부른다.
- 클로저는 함수와 그 함수가 선언됐을 때의 렉시컬 환경과의 조합이다.
* 함수: 반환된 내부 함수
* 렉시컬 환경: 내부 함수가 선언됐을 때의 스코프
- 클로저는 반환된 내부함수가 자신이 선언되었을 때의 환경인 스코프를 기억하여 (선언 환경)밖에서 호출되어도 그 환경(스코프)에 접근할 수 있는 함수를 말한다. 즉, 자신이 생성됐을 때의 환경(렉시컬 환경)을 기억하는 함수다.
- 클로저에 의해 참조되는 외부함수의 변수를 자유변수라고 부른다.
- 외부 함수가 이미 반환되었어도 외부함수내의 변수는 이를 필요로하는 내부함수가 하나 이상 존재하는 경우, 계속 유지된다. 이때 (외부 함수)변수의 복사본이 아니라, 실제 변수에 접근한다.
- 클로저의 활용
1. 상태유지 : 현재 상태를 기억하고 변경된 최신상태를 유지하는 것이다.
var toggle = (function(){
var isShow = false;
return function(){
box.style.display = isShow ? 'block' : 'none';
isShow = !isShow;
}
})();
=> 변수 isShow는 클로저에 의해 참조되고 있기 때문에 유효하며 자신의 변경된 최신 상태를 계속해서 유지한다.
만약, 클로저라는 기능이 없다면 상태를 유지하기 위해 전역변수를 사용해야 하는데, 전역변수는 여러 오류의 원인이 되므로 사용을 억제해야 한다.
2. 전역변수의 사용 억제
var increase = (function(){
var counter = 0;
return function(){
return ++counter;
}
}());
btn.onclick = function(){
cnt.interHTML = increase();
}
=> 스크립트가 실행되면 즉시실행함수가 호출되고 변수 increase에는 함수가 할당된다. 이 함수는 렉시컬 환경을 기억하는 클로저다. 따라서 즉시실행함수의 변수 counter에 접근할 수 있고 변수 counter는 자신을 참조하는 함수가 소멸될 때까지 유지된다. 또한 변수 counter는 외부에서 직접 접근할 수 없는 private 변수이므로 ㅇ의도되지 않은 변경을 걱정할 필요가 없어 안정적인 프로그래밍이 가능하다.
* 불변성을 지향하는 함수형 프로그래밍에서 부수효과를 최대한 억제하고 프로그램의 안정성을 높이기 위해 클로저는 적극적으로 사용된다.
3. 정보의 은닉
function Counter(){
var counter = 0;
this.increase = function(){
return ++counter;
}
}
const counter = new Counter();
counter.increase();
=> 생성자 함수는 클로저인 메소드를 갖고, 렉시컬 환경을 공유한다.
이런식으로 클로저의 특징을 사용해 클래스 기반 언어의 private 키워드를 흉내낼 수 있다.
- 클로저를 이용하여 배열의 값에 함수 리턴으로 값을 주거나 할때(?) 주의하여야 한다. for안에서 사용된 var i는 전역변수이기때문에 의도치않은 값이 들어갈 수 있다. 즉시실행함수로 감싼 다음에 (i)를 넣어서 리턴해주는 식으로 사용해야 한다.
자바스크립트 객체지향프로그래밍
- 객체지향이라는 개념은 명확한 정의가 없기 때문에 객체지향의 특성을 통해 이해할 수 밖에 없다.
- 실세계의 객체(Object)를 표현하기 위해 핵심적인 개념 또는 기능만을 추출하는 추상화를 통해 모델링하려는 프로그래밍 패러다임이다.
*패러다임: 인식체계, 틀
- 관계성 있는 객체들의 집합이라는 관점으로 접근하는 소프트웨어 디자인
- 각체는 독립적인 기능 또는 부품임
- 보다 유연하고 유지보수 하기 쉬우며 확장성 측면에서도 유리함
- 자바스크립트는 프로토타입 기반의 객체지향 언어이다.
이미 생성된 인스턴스의 자료구조와 기능을 동적으로 변경할 수 있다.
객체지향의 상속, 캡슐화(정보 은닉) 등의 개념은 프로토타입 체인과 클로저 등으로 구현할 수 있다.
- 인스턴스를 따로따로 생성하게 되면 각각의 인스턴스에 메소드가 중복되어 생성된다. 즉, 인스턴스가 내용이 동일한 메소드를 각자 소유하는데 이는 메모리 낭비이다. 이때 다른 접근 방식으로 프로토타입을 사용한다.
- 모든 객체는 프로토타입이라는 다른 객체를 가리키는 내부 링크를 가지고 있다. 즉, 프로토타입을 통해 직접 객체를 연결 할 수 있는데, 이를 프로토타입 체인이라한다.
*프로토타입: 일종의 공유 객체로 인식중임....
- 상속: 자바스크립트는 기본적으로 프로토타입을 통해 상속을 구현한다.
1. 의사클래스 패턴 상속: prototype 프로퍼티를 부모 생성자 함수의 인스턴스로 교체하여 상속을 구현하는 방법. (이슈 몇개 있음, 알아만 둘것)
2. 프로토타입 패턴 상속: Object.create 함수를 사용하여 객체에서 다른 객체로 직접 상속을 구현하는 방식. (권장)
var child = Object.create(Parent.prototype)
* Object.create 함수는 IE9이상에서 정상적으로 동작하므로 크로스 브라우징에 주의하여야 한다. (폴리필 사용 권장)
- 캡슐화:
관련있는 멤버 변수와 메소드를 클래스와 같은 하나의 틀안에 담고 외부에 공개될 필요가 없는 정보는 숨기는 것을 말한다. 캡슐화 혹은 정보은닉이라고 말함. 다른 부분들에 영향을 미치지 않고 변경될 수 있다.
var 를 사용하면 private 변수가 된다. this를 사용하면 public 멤버가 된다.
- 모듈 패턴:
객체내의 메소드(get..., set...)을 클로저로서 사용하여 private에 접근할 수 있는데, 이런 방식을 모듈패턴이라고 하며 캡슐화와 정보은닉을 제공한다. private 멤버가 객체나 배열일 경우 반환된 해당 멤버의 변경이 가능하므로 주의할 것.
객체를 반환하는 경우, 얕은 복사로 private멤버의 값을 외부에서 변경할 수 있으므로, 객체를 그대로 반환하지 않고 반환해야할 객체의 정보를 새로운 객체에 담아서 반환해야 한다.
- 캡슐화를 구현하는 패턴은 다양하며, 각각의 패턴에는 장단점이 있다. 다양한 패턴의 장단점을 분석하고 파악하는 것이 보다 효율적인 코드를 작성하는 데 중요하다.
- 자바스크립트는 클래스 기반 언어가 아니므로 기존의 전통적 방식으로 구현하려는 시도는 바른 판단이 아니다. 다만 객체지향 프로그래밍이 추구하는 재사용성, 유지보수의 용이성등을 극대화하기 위한 노력의 일환으로 보아야 한다.
빌트인(내장) 객체
1. 네이티브 객체
: ECMAScript 명세에 정의된 객체를 말하며, 전역의 공통 기능을 제공한다.
Object, String, Number, Function, Array, RegExp, Date, Math와 같은 객체 생성에 관계가 있는 함수 객체와 메소드로 구성된다.
2. 호스트 객체
: 브라우저 환경에서 제공하는 DOM 노드 객체와 같이 호스트 환경에 정의된 객체를 말한다. 브라우저 외부에서 동작하는 환경의 자바스크립트(Node.js)는 다른 호스트 객체를 사용할 수 있다.
브라우저 객체 모델(BOM)은 최상위 객체는 window이고, 그 밑으로 document(웹페이지), history(브라우저 히스토리에 기록된 웹페이지들), locate(현재 페이지 URL), navigator(브라우저 관련 정보), screen(장치의 디스플레이 정보)가 있다.
전역 객체
- 글로벌 영역에 선언한 함수도 전역 객체의프로퍼티로 접근할 수 있다. 전역함수는 전역 객체의 메소드이다.
표준 빌트인 객체도 역시 전역 객체의 자식 객체 이다.
- 전역 프로퍼티: Infinity, NaN, undefined 등
- 전역 함수:
eval(), inFinite(), isNaN(), parseFloat(), parseInt(), encodeURI(), decodeURI() 등
* eval()은 문자열 구문or표현식을 평가 또는 실행한다. 사용자로부터 입력받은 콘텐츠를 eval()로 실행하는 것은 보안에 매우 취약하다. eval()의 사용은 가급적으로 금지되어야 한다.
* 인코딩이란, URI의 문자들을 이스케이프 처리하는 것을 의미한다.
* 이스케이프 처리란, 어떤 시스템에서도 읽을 수 있는 ASCII Character-set으로 변환하는 것이다.
Number
- number를 다룰때 유용한 프로퍼티와 메소드를 제공하는 래퍼(Wrapper) 객체이다.
* 래퍼 객체: 기본 자료형에 대해서 객체로서 인식되도록 '포장'을 했다는 뜻. 객체라는 상자에 기본 자료형을 넣은 상태
- Number.EPSILON: 가장 작은 수, 부동 소수점 산술 연산비교는 무한 소수가 되어 미세한 오차가 발생하는 구조적 한계를 갖는데, 이때 오차의 차이가 EPSILON보다 작으면 같은 수로 인정할 수 있도록 활용할 수 있다.
- Number.MAX_VALUE
- Number.MIN_VALUE
- Number.NaN
- Number.isFinite(n): 전역함수 isFinite()과 차이가 있음 전역함수 isFinite()은 인수를 숫자로 변환하여 검사를 수행하지만, Number.isFinite()은 인수를 변환하지 않으므로 숫자가 아니면 무조건 false임
- Number.isNaN(n): isFinite()와 전역변수 차이 동일
- Number.isSafeInteger(n): 안전한 정수값인지 확인(무한대X, 소수X)
- Number.prototype.toExponential(n): 대상을 지수표기법으로 변환하여 문자열로 반환함.
* 지수표기법: 매우 큰 숫자를 표기할때 주로 사용, e(Exponent)앞에 있는 숫자에 10의 n승이 곱하는 형식으로 수를 나타냄
- Number.prototype.toFixed(n): 소숫점 자리 반올림하여 문자열로 반환
- Number.prototype.toPrecision(n): 나머지 자릿수를 반올림(?)하여 문자열로 반환함(?)
- Number.prototype.toString(n): 문자열로 반환
- Number.prototype.valueOf(n): 원시타입값을 반환
Math
- 수학상수와 함수를 위한 프로퍼티와 메소드를 제공하는 빌트인 객체임. 생성자함수가 아님(=> new 사용X)
- Math.PI
- Math.abs(n): 절대값 반환 (0또는 양수)
- Math.round(n): 소수점이하 반올림한 정수 반환
- Math.ceil(n): 소수점 이하 올림한 정수 반환, 음수인경우 소수점 이하 떼버림
- Math.floor(n): 소수점 이하 내림한 정수 반환, 음수인 경우 소수점 이하 떼버린다음 -1함
- Math.sqrt(n): 인수의 제곱근 반환
- Math.randomI(): 임의의 부동 소수점 반환 0부터 1미만
ex) 1~10까지 랜덤수 뽑으려면
const random = Math.floor((Math.random()*10)+1);
- Math.pow(밑, 지수): 거듭제곱근을 반환함
- Math.max([arr]): 가장 큰수 반환
- Math.min([arr]): 가장 작은수 반환
Date
- 날짜와 시간을 제공하는 빌트인 객체이면서 생성자 함수임
- UTC(협정 세계시)는 GMT라고 불리기도 함,
KST(한국 시간)은 UTC에 비해 9시간을 더한 시간임
- 기본적으로 현재 날짜와 시간을 나타내는 값을 가짐. 다른 날짜를 가리키고 싶은 경우 명시적으로 인수로 지정해주면 됨
new Date(년,월,일,시,분,초,밀리초)
- 년,월은 반드시 지정하여야함
- month는 월을 의미하는 0~11까지의 정수임. 0부터 시작하므로 주의 필요(현재달 얻으려면 +1해줘야한다는 것임)
정규 표현식(RegExp)
- 문자열에서 특정 내용을 찾거나 대체 또는 발췌하는데 사용함
- /패턴/i
/ => 시작, 종료 기호
i => 플래그
- 정규표현식 메소드
1. RegExp.prototype. - exec, test (ex. 패턴.exec(문자열))
* exec (첫번째) 매칭 결과['is', ...]만를 반환
* test 매칭 결과(true, false) 반환
2. String.prototype. - match, replace, search, split (ex. 문자열.match(패턴))
- 플래그 종류
i : 대소문자 구별 없이 검색,
g : 문자열 내 모든 패턴 검색(반복 검색, g없으면 한번만 검색됨),
m : 행이 바뀌더라도 검색
* 플래그는 옵션, 중첩 가능(ex. /is/ig)
- 패턴: 검색하고 싶은 문자열을 지정한다
.은 임의의 문자 한개를 의미 ...은 3자리문자
+ 최소 한번 반복하려면 +를 붙일것
(ex. /A+/g => A가 한번이상 반복되는 문자열 A, AA, AAA... 을 반복검색함)
| 또는
(ex. /A|B/g => A또는B를 반복검색함)
[]내의 문자는 or로 동작함
(ex. /[AB]+/g => A또는B가 한번이상 반복되는 문자열을 반복검색)
[-]범위 지정
(ex. /[A-Z]+/g => A~Z가 한번이상 반복되는 문자열을 반복검색)
역슬러쉬d는 숫자를 의미함: 0~9
역슬러쉬D는 반대임. 0~9가 아닌 문자열임
역슬러쉬w는 알파벳과 숫자를 의미함
역슬러쉬W는 반대임
^특정단어 로 시작하는지 검사
특정단어$ 로 끝나는지 검사
[^] 부정(not)임
(ex. [^a-z] => 알파벳소문자로 시작하지 않는 모든 문자 검색)
*[]바깥에 ^는 위에 쓴대로 문자열의 처음
역슬러쉬s는 공백문자 =>역슬러쉬t,r,n,v,f 와 같음
{} 자리수
(ex. {4,10} => 4~10자리인지 검사)
String 래퍼 객체
- String 생성자 함수(new String('Lee'))로 문자열 생성할 수 있음, 이럴경우 typeof 는 object
* 일반적으로 문자열 생성시에는 원시타입 문자열을 사용함(var str = '문자열' typeof는 string)
- 문자열.charAt(인덱스) : 해당 문자 반환
- 문자열.concat(문자열) : 문자열 연결하여 새 문자열 반환함
* 일반적으로 +연산자 사용함
- 문자열.indexOf(문자열) : 인수 문자열을 검색하여 (처음)발견된 곳의 index 반환, 발견못하면 -1
- 문자열.replace(문자열1, 문자열2) : 문자열1을 검색하여 문자열2로 대체함
- 문자열.splite(문자열 혹은 정규표현식): 문자열 혹은 정규표현식을 검색하여 구분한 후, 분리된 배열을 반환함
* 인수가 없는 경우, 문자열 전체를 단일 요소로 하는 배열을 반환
- 문자열.substring(시작번호, 끝번호): 시작번호부터 끝번호-1 번호까지의 문자 모두 반환함, 시작번호가 더 클경우 자동으로 위치 바뀜
- 문자열.slice(시작번호, 끝번호): substring과 동일, 음수의 인수 전달 가능(ex. -5 사용시 뒤에서 5자리 잘라내어 반환)
- toLowerCase(), toUpperCase() : 소,대문자로 변경
- trim() : 공백제거한 문자열 반환
- repeat(숫자) : 숫자만큼 반복해서 반환, 0이면 빈문자열
- includes(문자열) : 문자열 포함되어 있는지 검사후, 결과 불리언으로 반환
Array (배열)
- 배열은 일반적으로 배열 리터럴 방식(var arr = [...])으로 생성하지만, 생성자 함수(new)로도 생성가능함
(ex. new Array(2) => [empty, empty])
- 배열 요소 삭제
1. 값만 삭제: delete number[2] // 빈값으로 자리는 남아있음
2. 요소 완전 삭제: 배열.splice(시작 인덱스, 삭제할 요소수, (그자리에 추가할 요소*옵션임))
- 배열의 순회: forEach 메소드, for문, for...of문
- 배열.length: 요소의 개수(배열의 길이)
* 배열 요소의 개수와 length 프로퍼티 값이 일치하지 않는 배열을 희소배열이라고 함. 즉, 희소배열은 length가 언제나 큼 (요소가 빈값으로 채워져 있음)
* length 프로퍼티의 값은 명시적으로 변경할 수 있음. 랭스 값 보다 크거나 같은 인덱스에 해당하는 요소는 모두 삭제됨 (ex. arr.length = 3)
- Array.from('문자열' 혹은 {객체}) : 유사배열객체(문자열 등) 또는 이터러블 객체를 변환하여 새로운 배열을 생성함
- Array.of(인수) : 인수를 요소로 갖는 배열ㅇ르 생성함
- 배열.indexOf(인수): 인수를 검색하여 (첫번째)인덱스 반환함, 없는경우 -1반환
- 배열.includes(인수): 인수 검색하여 결과값(true, false) 반환
- 배열1.concat(배열2): 배열1+배열2 의 새로운 배열 반환
- 배열.join(구분자): 구분자로 연결한 문자열을 반환함, 구분자 생략할 경우 기본은 ,
- arr.push(요소) : arr(원본 배열)에 요소 추가, 요소 그대로 추가함
* concat은 원본 요소 변경X, 요소가 배열일 경우 해체함
* arr[arr.length] = 3 // arr.push(3) 과 동일한 처리, 이 방법을 추천함
- arr.pop() : 마지막 요소 제거후, 제거한 요소 반환함
- arr.shift() : 첫요소 제거후, 제거한 요소 반환함
- arr.slice(시작숫자, 끝숫자) : 시작숫자 인덱스 부터, 끝숫자-1 인덱스 까지 부분을 복사하여 반환, 원본 배열 변경X
자바스크립트 배열은 배열이 아니다
- 자바스크립트의 배열은 배열의 요소를 위한 각각의 메모리 공간은 동일한 크기를 갖지 않아도 되며, 연속적으로 이어져 있지 않을 수도 있는 등 엄밀히 말해 일반적 의미의 배열이 아니다.
자바스크립트의 배열은 일반적인 배열의 동작을 흉내낸 특수한 객체이다.
- 자바스크립트 배열은 해시 테이블로 구현된 객체 이므로, 성능적인 면에서 느릴 수 밖에 없는 구조적인 단점을 갖는다. 하지만, 특정 요소를 탐색, 삽입, 삭제하는 경우에는 빠른 성능을 가진다.
* 해시테이블: 키를 값에 매핑할 수 있는 구조인, 연관 배열 추가에 사용되는 자료 구조이다. 해시 테이블은 해시 함수를 사용하여 색인을 버킷이나 슬롯의 배열로 계산한다.
배열 고차 함수
- 고차함수: 함수를 인자로 전달받거나 함수를 결과로 반환하는 함수
- arr.sort() : 정렬
arr.sort(function(a,b){ retrun a-b; })
- arr.forEach() : for문 대신 사용, break문 사용못함
numbers.forEach(function(item){
pows.push(item **2);
});
* forEach 메소드는 원본 배열(this)를 변경하지 않지만, 콜백함수는 원본배열을 변경할 수 있다. 원본배열을 직접 변경하려면 콜백함수의 3번째 인자(item, index, 세번째인자 self)를 사용 한다.
- arr.map() : 배열을 순회하며 각 요소에 대하여 인자로 주어진 콜백함수의 반환값(결과값)으로 새로운 배열을 생성하여 반환한다. 배열을 순회하며 요소값을 다른값으로 맵핑하기 위한 함수이다. 반환값이 없으면 새로운 배열은 비어 있다. 2번째 인자로 this를 전달 할 수 있다. (function(){}, this)
- arr.filter() : if문을 대체할 수 있다. 배열을 순회하며 각 요소에 대하여 인자로 주어진 콜백함수의 실행결과가 true인 배열 요소의 값만 추출한 새로운 배열을 반환한다.
- arr.reduce() : 배열을 순회하며 각 요소에 대하여 이전의 콜백함수 실행 반환 값을 전달하여 콜백함수를 실행하고, 그 결과를 반환한다. 결과는 다음 콜백의 첫번째 인자로 전달 된다. 빈 배열을 호출하며 에러가 발생한다. 언제나 초기값을 전달해야 안전함 (f{}, 0)
(예: 1,2,3,4,5인 경우 => 1+2=3, 3+3=6, 6+4=10, 10+5=15가 최종 값)
- arr.some() : 배열내 일부 요소가 콜백함수의 테스트를 통과하는지 확인하여 그 결과를 boolean으로 반환 (배열 요소 중 한개 이상만 통과하면 true)
- arr.every() : 배열내 모든 요소가 콜백함수의 테스트를 통과하는지 확인하여 그 결과를 boolean으로 반환
- arr.find() : 배열을 순회하며 각 요소에 대하여 인자로 주어진 콜백함수를 실행하여 그 결과가 참인 첫번재 요소를 반환한다. find의 결과값은 해당요소 값이다. 참인 요소가 존재하지 않으면 undefined 반환.
- arr.findIndex(): 배열을 순회하며 각 요소에 대하여 인자로 주어진 콜백함수를 실행하여 그 결과가 참인 첫번째 요소의 인덱스를 반환함. 참인 요소가 없으면 -1 반환.
DOM
- 문서 객체 모델
- 브라우저의 렌더링 엔진은 웹 문서를 로드한후, 파싱하여 웹 문서를 브라우저가 이해할 수 있는 구조로 구성하여 메모리에 적재하는데, 이를 DOM이라 한다.
즉, 모든 요소와 요소의 어트리뷰트, 텍스트를 각각의 객체로 만들고 이들 객체를 부자 관계로 표현할 수 있는 트리 구조로 구성한 것이 DOM이다.
정적인 웹페이지에 접근하여 동적으로 웹페이지를 변경하기 위한 유일한 방법은 메모리상에 존재하는 DOM을 변경하는 것이고, DOM에 접근하고 변경하는 프로퍼티와 메소드의 집합이 DOM API이다.
- DOM tree
1. 문서 노드: document(최상위)
2. 요소 노드: element(li, p...)
3. 어트리뷰트 노드: 요소의 어트리뷰트
4. 텍스트 노드: 요소의 텍스트 (최종단)
- DOM Query (요소에의 접근)
1. 하나의 요소 노드 선택:
document.getElementById(id), // 한개 선택
document.querySelector(cssSelector), // (첫번째)한개 선택
2. 여러개의 노드 선택:
document.getElementsByClassName(class)
클래스 모두 선택, 유사배열, 실시간으로 상태 변경 반영,
* 반복문 사용시 주의(역방향으로 하거나, while 반복문(length가 0보다 클경우..), 배열로 변경후 사용하거나)
- DOM Traversing(탐색)
parentNode // 부모노드 탐색
firstChild, lastChild // 자식노드 탐색
hasChildNodes() // 자식노드가 있는지 확인하고 boolean 값 반환.
childNodes // (텍스트 포함 모든)자식 노드의 컬렉션 반환
children // (element 요소만)자식 노드의 컬렉션 반환
previousSibling, nextSibling // (텍스트 포함 모든)형제 노드 탐색
previousElementSibling, nextElementSibling // (element 요소만)형제 노드 탐색
- DOM Manipulation(조작)
nodeValue // 노드의 값 반환(텍스트=>문자열, 요소=> null)
nodeName, nodeType // 노드의 정보
className, classList, id // attribute 노드에의 접근 및 수정
hasAttribute(attribute) // 지정한 어트리뷰트 갖고 있는지 검사
getAttribute(attribute) // 어트리뷰트의 값 취득
setAttribute(attribute, value) // 어트리뷰트와 어트리뷰트 값을 설정
removeAttribute(attribute) // 지정한 어트리뷰트 제거
- HTML 콘텐츠 조작
textContent // 요소의 (순수)텍스트 콘텐츠를 취득 또는 변경
innerText // 요소의 텍스트 콘텐츠에만 접근 *비표준임(사용안하는걸 권장)
innerHTML // (마크업 포함 모든 자식요소 포함)모든 콘텐츠를 하나의 문자열로 취득, *XSS에 취약(스크립트 태그 삽입 시켜서 실행되게 한다던가...)
createElement(tagName) // 요소 생성
createTextNode(text) // 텍스트 노드 생성
appendChild(Node) // 인자 Node를 마지막 자식요소로 DOM트리에 추가함
removeChild(Node) // 인자 Node를 DOM 트리에서 제거함
insertHTML(position, string) // string을 HTML로 파싱하고 생성된 노드를 DOM트리의 지정된 position에 삽입함 *XSS에 취약
- style 프로퍼티를 사용하면 인라인 스타일 선언을 생성함 (ex. elem.style.color='red')
style 프로퍼티 값을 취득하려면 window.getComputedStyle(elem, null)을 사용
동기식 처리 모델 VS 비동기식 처리 모델
- 동기식 처리 모델(Synchronous processing model)은 직렬적으로 태스크를 수행함. 태스크는 순차적으로 실행되며, 어떤 작업이 수행중이면 다음 작업은 대기하게 됨.
예를들어 서버에서 데이터를 가져와서 화면에 표시하는 작업을 수행할 때, 서버에 데이터를 요청하고 데이터가 응답될 때까지 이후 태스크들은 블로킹(작업중단) 됨
- 비동기식(Asynchronous, Non-Blocking) 처리 모델은 병렬적으로 태스크를 수행함. 즉, 태스크가 종료되지 않은 상태라 하더라도 대기하지 않고 다음 태스크를 실행함.
DOM 이벤트 핸들러와 Timer 함수(setTimeout, setInterval), Ajax요청은 비동기식 처리 모델로 동작함
이벤트
- 브라우저에서 이벤트란, DOM요소와 관련이 있다. (버튼 클릭 => 웹페이지 로드)
- 브라우저는 이벤트를 감지할 수 있으며 이벤트 발생 시에는 통지해 준다. 이 과정을 통해 사용자와 웹페이지는 상호작용(인터랙션=소통)이 가능하게 된다.
이벤트가 발생하면 그에 맞는 반응을 하여야 한다. 이를 위해 이벤트는 일반적으로 함수에 연결되며, 그 함수는 이벤트가 발생되면 실행된다.
- 브라우저는 단일 쓰레드에서 이벤트 드리븐 방식으로 동작한다.
단일 쓰레드는 쓰레드가 하나뿐이라는 의미이며, 하나의 작업만을 처리할 수 있따는 것을 의미한다. 이처럼 자바스크립트의 동시성을 지원하는 것이 바로 이벤트 루프이다.
* 단일 쓰레드: 스레드란 프로세스(프로그램) 내 실행단위, 하나일 경우 싱글(단일) 스레드.
* 이벤트 드리븐: 이벤트에 반응하여 동작을 변경하는 방식
- 브라우저환경은 자바스크립트엔진(call stack, heap)과 Event Queue가 있고, 그 둘을 연결하는 web api가 있다.
* 자바스크립트 엔진
1. Call Stack (호출 스택): 작업이 요청(함수 호출)되면 요청된 작업은 순차적으로 call stack 에 쌓이게 되고, 순차적으로 실행된다
2. Heap: 동적으로 생성된 객체 인스턴스가 할당되는 영역
*이벤트 큐: 비동기 함수의 콜백 함수가 보관되는 영역임. 이벤트 루프에 의해 특정 시점(콜 스택이 비어졌을 때)에 순차적으로 Call Stack으로 이동되어 실행된다.
* 이벤트 루프: 이벤트 큐에 태스크가 있는지 반복하여 확인함. 콜 스택이 비어 있다면, 이벤트 큐 내의 태스크가 콜 스택으로 이동하고 실행된다.
- 이벤트의 종류
1. UI Event: load, unload, error, resize, scroll, select
2. Keyboard Event: keydown, keyup, keypress
3. Mouse Event: click, dbclick, mousedown, mouseup, mousemove, mouseover, mouseout
4. Focus Event: focus/focusin, blur/focusout
5. Form Event: input, change, submit, reset
6. Clipboard Event: cut, copy, paste
- 이벤트 핸들러 등록: 이벤트가 발생했을때 동작할 이벤트 핸들러를 이벤트에 등록하는 방법
1. 인라인 이벤트 핸들러 방식: HTML 요소에 <... onclick=""> (*사용안하기를 권장함)
2. 이벤트 핸들러 프로퍼티 방식: 하나의 이벤트 핸들러만을 바인딩(단점)
btn.onclick=function()
3. addEventListener 메소드 방식: 대상 DOM요소에 이벤트를 바인딩하고, 해당 이벤트가 발생했을 때 실행될 콜백 함수(이벤트 핸들러)를 지정한다. 하나이상의 이벤트 핸들러를 추가할 수 있다. 캡쳐링과 버블링을 지원한다. 모든 DOM요소에 대해 동작한다.
btn.addEventListener('click',function(){...})
function foo(){...}
elem.addEventListener('click', foo) // 이벤트 발생시까지 대기
* foo()는 이벤트 발생시까지 대기않고 바로 실행됨
이렇게 함수자체(foo)를 지정하게 되면, 이벤트 핸들러 함수에 인수를 전달할 수 없는 문제가 발생한다. 이를 우회하는 방법은 elem.addEventListener('click',function(){ foo(인수) }) 이런식으로 이벤트 핸들러 내에서 함수를 호출하면서 인수를 전달하는 것이다.
- 이벤트 핸들러 함수 내부의 this
1. 인라인에서는 window를 가리킴
2. 이벤트 핸들러 프로퍼티방식에서는 이벤트에 바인딩된 요소를 가리킴
3. addEventListener 메소드 방식에서는 이벤트 리스너에 바인딩된 요소를 가리킴
- 이벤트가 발생했을 때 캡쳐링과 버블링은 순차적으로 발생한다.
addEventListener 메소드의 세번째 매개변수에 true를 설정하면 캡쳐링으로 전파되는 이벤트를 캐치하고,
false 또는 미설정하면 버블링으로 전파되는 이벤트를 캐치한다.
*버블링(↑): 자식 요소에서 발생한 이벤트가 부모요소로 전파되는 것
*캡쳐링(↓): 자식 요소에서 발생한 이벤트가 부모 요소부터 시작하여 이벤트를 발생시킨 자식요소까지 도달하는 것
- 이벤트 객체: 이벤트를 발생시킨 요소와 발생한 이벤트에 대한 유용한 정보를 제공한다.
이벤트가 발생하면, 이벤트 객체는 동적으로 생성되며 이벤트를 처리할 수 있는 이벤트 핸들러에 인자로 전달된다.
addEventListener('click', function(e){
fuc(e, msg);
})
- e.target: 이벤트를 발생시킨 요소를 가리킨다
- e.currentTarget: 이벤트에 바인딩된 DOM 요소를 가리킨다
- e.type: 이벤트의 종류를 나타내는 문자열을 반환한다
- e.cancelable: 요소의 기본동작을 취소시킬 수 있는 여부(true,false)를 나타냄
- e.preventDefault(): 기본 동작을 중단시킨다
- e.eventPhase: 이벤트 흐름 상에서 어느 단계에 있는지 확인한다 (0없음 1캡쳐링 2타깃 3버블링)
- e.stopPropagation(): 이벤트 전파를 중단한다
window.DeviceOrientationEvent
- HTML5 제공, 디바이스의 물리적 방향의 변화(회전시 이벤트)를 감지함
- 3개의 각도(alpha, beta, gamma)를 사용하여 측정함
비동기식 처리 모델과 Ajax
- Ajax는 비동기적으로 서버와 브라우저가 데이터를 교환할 수 있는 통신 방식이다.
- JSON은 클라이언트와 서버 간 데이터 교환을 위한 규칙, 즉 데이터 포맷이다. 순수한 텍스트로 구성된 규칙이 있는 데이터 구조이다. 키는 반드시 큰 따옴표로 둘러싸야 한다.
JSON.stringify: 객체를 JSON형식의 문자열로 변환함
JSON.parse: JSON 데이터를 가진 문자열을 객체로 변환함
- 브라우저는 XMLHttpRequest 객체를 이용하여 Ajax 요청을 생성하고 전송한다.
const xhr = new XMLHttpRequest();
xhr.open('GET', '/users');
xhr.send();
- opend과 send 사이에 서버로 전송할 데이터의 MIME-type을 지정하여 보낼 수 있음
xhr.setRequestHeader('Content-type', 'application/json');
const data = {...};
xhr.send(JSON.stringify(data));
*setRequestHeader 메소드는 HTTP Request Header의 값을 설정한다
- Ajax 응답 처리의 예
// XMLHttpRequest.readyState가 변경(이벤트 발생)될때마다 onreadystatechange 이벤트핸들러가호출된다.
xhr.onreadystatechange = function(e){
if(xhr.readyState !== XMLHttpRequest.DONE) return;
if(xhr.status === 200){
console.log(xhr.responseText);
}else{
console.log('error!');
}
}
- xhr.onload = function (e){} // load 이벤트는 서버 응답이 완료된 경우에 발생한다.
- 웹서버: 브라우저와 같은 클라이언트로부터 HTTP 요청을 받아들이고 HTML문서와 같은 웹페이지를 반환하는 컴퓨터 프로그램이다
- 역직렬화(Deserializing): 브라우저로 전송된 JSON 데이터는 문자열이다. 이 문자열을 객체화 하여야 하는데 이를 역직렬화라고 한다. JSON.parse()를 사용한다.
- 동일출처원칙(Same-origin policy): 요청에 의해 웹페이지가 전달된 서버와 동일한 도메인의 서버로부터 전달된 데이터는 문제없이 처리할 수 있다. 하지만 보안상의 이유로 다른 도메인으로의 요청(크로스 도메인 요청)은 제한된다.
- 동일출처원칙 우회 방법
1. 웹서버의 프록시 파일
2. JSONP
3. Cross-Origin Resource Sharing: HTTP 헤더에 추가적으로 정보를 추가하여 브라우저와 서버가 서로 통신해야 한다는 사실을 알게하는 방법이다. Node.js 서버일 경우, CORS package를 사용하면 간단하게 구현할 수 있다.
const cors = require('cors')
app.use(cors())
REST API
: Representational State Transfer API
- 웹의 장점을 최대한 활용할 수 있는 아키텍쳐(설계도)가 REST이다. REST는 HTTP 프로토콜을 의도에 맞게 디자인 하도록 유도하고 있다. REST의 기본원칙을 성실히 지킨 서비스 디자인을 RESTful 이라고 표현한다.
- REST API 중심 규칙
1. URI는 정보의 자원을 표현해야 한다 => 명사사용, get등 행위 표현X (ex. GET /todos/1)
2. 자원에 대한 행위는 HTTP Method(GET, POST, PUT, DELETE 등)으로 표현한다.
- HTTP Method : 5가지의 메소드(GET, POST, PUT, PATCH, DELETE)를 사용하여 CRUD를 구현한다.
GET: 조회
POST: 생성
PUT: 전체 교체
PATCH: 일부 수정
DELETE: 삭제
- RESET API의 구성
1. 자원: HTTP URI
2. 자원에 대한 행위: HTTP Method(GET, ...)
3. 그 행위에 대한 내용: HTTP Message Pay Load
SPA & Routing
- Single Page Application & Routing
- SPA: 단일 페이지 애플리케이션, 모던 웹의 패러다임, 네이티브 앱과 유사한 사용자 경험,
SPA는 웹 애플리케이션에 필요한 모든 정적 리소스를 최초에 한번 다운로드 한다. 이후, 페이지 갱신에 필요한 데이터만을 전달 받아 페이지를 갱신한다.
- SPA의 구조적인 단점
1. 초기 구동 속도 느림
2. SEO(검색 엔진 최적화) 문제
- Routing : 경로를 결정하는 기능
* 애플리케이션의 상황을 고려햐여 적절한 방법을 선택하도록 해야함.
1. 전통적 링크방식: 링크 태그로 동작, 전체 페이지를 다시 랜더링하는 과정에서 새로고침 발생(사용성 안좋음)
2. AJAX 방식: 자바스크립트를 이용해서 비동기적으로 서버와 브라우저가 데이터를 교환하는 통신방식, 새로 랜더링X, 페이지 일부만 갱신, 히스토리 관리가 되지 않음
3. HASH 방식: URI의 fragment identifier(#service)의 고유기능인 앵커(anchor)를 사용한다. 서버에 어떤 요청도 하지 않음. 웹페이지 내부에서 이동을 위한것. 히스토리 관리에 아무런 문제가 없음. 하지만 과도기적 기술이다. (pushState는 일부의 브라우저에서만 지원이 가능하다. SEO 이슈도 있음)
4. PJAX 방식: hash방식의 단점 보완 위한 HTML5의 pushState와 popstate 이벤트를 사용한 PJAX 방식임. Ajax 방식은 주소창의 url을 변경시키지 않아 history 관리가 불가능한데, 이때 사용하는 것이 pushState 메서드임. pushState메서드는 주소창의 URL을 변경하고, URL을 history entry로 추가하지만 요청하지는 않는다. 서버랜더링 방식과 AJAX 방식이 혼재되어 있는 것이다.
'JAVASCRIPT' 카테고리의 다른 글
jQuery 정리 (0) | 2021.02.24 |
---|---|
ES6 정리 (0) | 2021.01.25 |