(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)
forEachthis 값을 원하는 대로 변경할 수 있음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
closureis 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를 호출하는 경우는 그자체가 하나의 개체로 취급