(1) primitive(원시형) : number
, string
, boolean
, null
, undefined
...
(2) reference(참조형) : object
, Array
, Function
, Date
, RegExp
...
원시형은 값이 담긴 주소값을 바로 복제 & 불변성(immutability)
참조형은 값이 담긴 주솟값들로 이루어진 묶음을 가리키는 주소값을 복제
변수(variable)
는 '변할 수 있는 데이터 자체'이고, 식별자(identifier)
는 '어떤 데이터를 식별하는데 사용하는 이름(= 변수명)' 임불변값
, 참조형은 가변값
객체의 변수(프로퍼티) 영역
이 별도로 존재하는점var a = 10;
var b = a;
var obj1 = {c:10, d:'ddd'};
var obj2 = obj1;
b = 15
obj2.c = 20
(1) 기본형 데이터 복사의 경우
(2) 참조형 데이터 복사의 경우
...위와 동일
b = 15;
obj2= {c:20, d:'ddd'}
불변객체
의 필요성 발생얕은 복사 VS 깊은 복사
var copyObject = function(target){
var result ={};
for (var prop in target) {
result[prop] = target[prop];
}
return result;
var copyObjectDeep = functon(target){
var result = {};
if (typeof target === 'object' && target !== null) {
for (var prop in target) {
result[prop] = copyObjectDeep(target[prop]);
}
} else {
result = target;
}
return result;
};
깊은 복사를 간단하게 할 수 있는 방법
객체를 JSON 문법으로 표현된 문자열로 전환 후, 다시 JSON객체로 변경
var copyObjectViaJSON = function (target) { return JSON.parse(JSON.stringify(target)); };
실행할 코드에 제공할 환경 정보들을 모아놓은 객체
(javascript의 hoisting, this 속성과 관련)
흔히 실행 컨텍스트를 구성하는 방법은함수를 실행 하는 것
임
- 실행 컨텍스트에 담기는 정보s
VariableEnvironment
: 현재 컨텍스트 내의 식별자들에 대한 정보 + 외부환경 정보, 선언 시점의 LexicalEnvironment의 스냅샷으로, 변경사항은 반영XLexicalEnvironment
: 처음에는 VariableEnvironmnet와 같지만 변경 사항이 실시간으로 반영됨ThisBinding
: this 식별자가 바라봐야할 대상 객체
stack VS queue
stack
은 출입구가 하나인 깊은 우물같은 데이터 구조
queue
는 양쪽이 열려있는 파이프과 같은 데이터 구조
함수 선언문과 함수 표현식(익명, 기명)
: 함수를 새롭게 정의할때 쓰이는 방식 2가지
: 호이스팅하는 경우, 함수 선언문은 전체를 호이스팅 하지만, 함수 표현식의 경우에는 식별자(변수명) 부분만 호이스팅하고 실제 함수는 그자리에 둠실무에서, 여러사람이 작업하는 긴 코드 내에서 동일한 변수명이 포함되는 경우, 호이스팅 때문에 계속 override되어 마지막에 정의한 함수가 실행되는 오류 발생가능성 있음 => 따라서, 함수 표현식으로 함수를 정의하면 각각의 위치에서 함수가 다르게 작동가능하므로 상대적으로 함수 표현식이 안전
// 함수 선언문
function a () {}
//함수 표현식(익명)
var b = function (){}
//함수 표현식(기명)
var c = function d(){}
Scope란?
: 식별자에 대한 유효범위
Scope Chain이란?
: 식별자의 유효범위를 안에서부터 바깥으로 차례로 검색해 나가는 것
: 이를 가능케 하는 것이 LexicalEnvironmet의 outerEvironmentReference임
(1) 메서드로서 호출할 때 그 메서드 내부에서의 this
함수를 실행한는 2가지 방법
- 함수로서 호출하는 경우 : 그 자체로 독립적 기능 수행
- 메서드로 호출하는 경우 : 자신을 호출한 대상 객체에 대한 동작을 수행 (
obj.~
식으로 호출하는 경우)
(2) 함수로서 호출할때 그 함수 내부에서의 this
실행 컨택스트를 활성화 할 당시(함수가 호출되는 시점) this가 별도로 지정되지 않으면, this는 전역 객체를 가리킴
- 메서드 내부 함수에서 this를 우회하는 방법
메서드 내부 함수에서 this를 변수(ex>
var self = this
)에 담은 다음 호출하도록 하면, 동일하게 메서드 내부 함수를 함수로 호출하더라도 전역 객체가 아닌 해당 객체를 반환- this를 바인딩 하지 않는 함수 = "arrow function"
: ES6에서 도입한 arrow function을 사용하면, 위의 우회법 필요 xvar obj = { outer: function() { console.log(this); // {outer: f} var innerFunc = () =>{ console.log(this); // {outer: f} }; innerFunc() } }; obj.outer();
(3) 콜백함수 호출 시 그 함수 내부에서의 this
setTimeout
함수,forEach
와 같은 메서드는 내부 콜백함수를 호출시, 대상이 될 this를 지정하지 않아, 콜백함수 내부에서 this는 전역객체를 참조- but,
addEventListener
함수 내부의 콜백함수를 호출할때는 자신의 this를 상속하게 되어 있음
(4) 생성자 함수 내부에서의 this
new
명령어와 함께 함수를 호출하면 생성자로 동작하고, 리렇게 생성자로 호출된 경우 내부에서의 this는 곧 새로 만들 구체적인 인스턴스 자신을 가리킴
(1) call 메서드
Function.prototype.call(thisArg,[ arg1,[, arg2[,...]]])
- call 메서드는 호출 주체인 함수를 즉시 실행하도록 하는 함수
- 첫번째 인자를 this로 바인딩하고, 이후 인자들은 호출할 함수의 매개변수로 적용
var func = function(a, b, c) { console.log(this, a, b, c); }; func(1, 2, 3) // Window{...}, 1, 2, 3 func.call({x:1}, 4, 5, 6); // {x:1} 4, 5, 6
(2)apply 메서드
Function.prototype.apply(thisArg[, argsArray])
- call 메서드와 큰차이 없지만, 두번째 인자를 배열로 받는 다는 차이
(3) call/apply 메서드의 활용
1. 유사배열 객체에 배열 메서드 사용
- 원칙적으로 object에는 array method를 사용할 수 없지만, 유사배열객체 (키가 0또는 양의 정수인 프로퍼티가 존재하고, length 프로퍼티의 값이 0또는 양의 정수인 객체)는 call or apply method 이용하여 array method 적용가능
- 문자열도 가능하지만, 문자열의 경우 length property가 읽기 전용이기 때문에 원본 문자열에 변경을 가하는 method는 에러
- call/apply를 이용한 형변환은
this를 원하는 값으로 지정하여 호출한다
는 원래 의도에서 벗어난 활용법임
=> 이에, ES6에서는 유사배열 객체 또는 순환가능 모든 종류의 데이터 타입을배열
로 전환하는Array.from
메서드가 새로 도입됨var obj ={ 0: 'a', 1: 'b', 2: 'c', length: 3 }; Array.prototype.push.call(obj, 'd') console.log(obj) // {0: 'a', 1: 'b', 2:'c', 3:'d', length: 4} var arr = Array.prototype.slice.call(obj); console.log(arr); // ['a', 'b', 'c', 'd'] //얕은 복사 결과물로 array 반환
2. 생성자 내부에서 다른생성자를 호출
: 생성자 내부에 다른 생성자와 공통된 내용이 있는 경우, call or apply를 이용해 다른 생성자 호출하면 간단히 반복을 줄일 수 있음
3. 여러 인수를 묶어 하나의 배열로 전달하고 싶을 때 - apply
: (예시-아래) 최소 및 최대값 구하기
: 원래 Math.max(a, b, c, d..) 식으로 들어가야 함
: ES6의 spread syntax 활용하면 더 간단var numbers = [10,20,3,16,45] var max = Math.max.apply(null, numbers); var min = Math.min.apply(null, numbers); console.log(max, min); // 45, 3
(4) bind 메서드
Function.prototype.bind(thisArg[, arg1[, arg2[, ...]]])
bound
라는 접두어가 붙음 ('bound xxx'라면, xxx라는 원본 함수에 bind method 반환 함수라는 뜻)Arrow function
을 이용하면, 스코프체인상 가장 가까운 this에 접근하게 됨(5) 별도의 인자로 this를 받는 경우(콜백함수 내에서의 this)
forEach
this
값을 원하는 대로 변경할 수 있음Array.prototype.forEach(callback[, thisArg])
map, filter, some, every, find, findIndex, flatMap, from..
콜백함수는 다른 코드의 인자로 넘겨주는 함수
- '제어권'과 관련이 깊음
var obj = {
vals: [1, 2, 3],
logValues: function(v, i) {
console.log(this, v, i);
}
};
obj.logValues(1, 2); // { vals: [1 ,2, 3], logValues: f} 1 2
[4, 5, 6].forEach(obj.logValues); // Window {...} 4 0
// Window {...} 5 1
// Window {...} 6 2
Promise
, Generator
, ES2017의 async/await
로 해결가능
- A
closure
is the combination of a function and the lexical environment(outerEnvironmentReference
) within which that function was declared.- 어떤 함수에서 선언한 변수를 참조하는 내부 함수에서만 발생하는 현상 (= 외부함수의 LexicalEnvironment가 가비지 컬렉팅되지 않는 현상)
: 가비지 컬렉터는 어떤 값을 참조하는 변수가 하나라도 있다면 그 값은 수집대상에 포함시키지 않음- 클로저란, 어떤 함수 A에서 선언한 변수 a를 참조하는 내부함수 B를 외부로 전달할 경우 A의 실행 컨텍스트가 종료된 이후에도 변수 a가 사라지지 않는 현상
- 어떤 모듈의 내부 로직에 대해 외부로의 노출을 최소화해서 모듈 간의 결합도를 낮추고 유연성을 높이고자 하는 현대 프로그래밍 언어의 중요한 개념 중 하나.
- 흔히 접근 권한에는
public
(외부에서 접근 가능),private
(내부에서만 사용하고 외부노출 X),protected
의 세 종류가 있음- 외부에 제공하고자 하는 정보들을 모아서 return하고, 내부에서만 사용할 정보들은 return하지 않는 것으로 접근 권한 제어가 가능
부분 적용 함수
란 n개의 인자를 받는 함수에 미리 m개의 인자만 넘겨 기억시켰다가, 나중에 (n-m)개의 인자를 넘기면 비로소 원래 함수의 실행결과를 얻을 수 있도록 하는 함수
커링 함수
란 여러개의 인자를 받는 함수를 하나의 인자만 받는 함수로 나눠서 순차적으로 호출될 수 있게 체인 형태로 구성한 것
클래스 기반 언어에서 '상속'을 사용하듯, 프로토타입 기반 언어는 어떤 객체를 prototype으로 삼고 이를 복제(참조)함으로써 상속과 비슷한 효과를 얻음
- 어떤 constructor 함수를 new 연산자와 함께 호출하면 -> Constructor에서 정의된 내용을 바탕으로 새로운 인스턴스가 생성 -> 이때 instance에는
__proto__
라는 프로퍼티가 자동으로 부여되는데, 이 프로퍼티는 Constructor의 prototype이라는 프로퍼티를 참조__proto__
는 생략가능 (함수를 method로 호출하는 경우는 method 명 바로앞의 객체가 곧this
가 됨을 유의)
- 생성자 함수의 프로퍼티인 prototype 객체 내부와 이의 인스턴스 객체에는 constructor라는 프로퍼티가 있는데, 이는 인스턴스와의 관계에 있어서 필요한 정보임
- 읽기 전용 속성이 부여된 예외적인 경우(기본 리터럴 변수 - number, string, boolean)을 제외하고는 값을 바꿀 수 있음
어떤 데이터의
__proto__
프로퍼티 내부에 다시__proto__
프로퍼티가 연쇄적으로 이어진 것을 프로토타입 체인(prototype chain)이라고 하고 이 체인을 따라가며 검색하는 것을 프로토타입 체이닝(prototype chaining)이라고함
- 어떤 생성자 함수이든
prototype
은 반드시 객체이기 때문에,Object.prototype
이 언제나 프로토타입 체인의 최상단에 존재 -> 따라서, 객체에서만 사용할 메서드를 Object.prototype 내부에 정의하면 다른 데이터 타입도 해당 메서드를 사용할 수 있게 됨- 예외적으로 Object.create를 이용하면, Object.prototyp의 메서드에 접근할 수 없는 경우가 있음(Object.create(null)은
__proto__
가 없는 객체를 생성
클래스
가 아닌 프로토타입
기반의 언어클래스
문법이 추가(다만, 일정부분 프로토타입을 여전히 사용)클래스는 하위로 갈수록 상위 클래서의 속성을 상속하면서 더 구체적인 요건이 추가 또는 변경됨
인스턴스는 어떤 클래스의 속성을 지니는 실존하는 개체를 의미
static member
와 instance member
로 나뉨prototype method
라고 함)추상적 개념
이지만, 클래스 자체를 this로 접근해서 static method를 호출하는 경우는 그자체가 하나의 개체
로 취급