🌖 실무를 시작한지 어느덧 1년... ⏰
이제 구글신님과 경험을 통해 기능 구현은 잘할수 있다! 라는 자신감이 생겼지만
정작 마음속에 남아있는근데 왜이렇게 돌아가지 하는 의문점들은 해소하지 못하고 있었다.
그러던 중 자바스크립트님을 깊게 공부해보지 못한 것이 아닌가 하는 생각이 들었고..
(취준시절은 이해되는것에 한계가 있었던 것 같다.넘나 어렵..😑)
그러던 중 인강도 있고책도 두껍지도 않으면서 깔꼼하고 컬러풀한 책을 찾았다.
다 읽고 나니 겉모습만 훌륭한것이 아니라 결론적으로
자바스크립트를 이해하는데 너무 도움이 되었던 책이었다
재미도 있고 정리도 잘되어있어서 2일만에 술술 다 보았던 것 같다
❗️ 강추 👍
기본형 | 참조형 |
---|---|
number, string, boolean, null, undefined, symbol | 그 외 |
값이 담긴 주솟값을 바로 복제 | 값이 담긴 주솟값들로 이루어진 묶음을 가리키는 주솟값 복제 |
불변성을 띔 | 가변값인 경우가 많지만 변경불가능한 경우도 있고 불변값으로 활용도 가능 |
1) 데이터 변환을 자유롭게 할 수 있게 함
2) 메모리를 더욱 효율적으로 관리할수 있기 때문
3) 중복된 데이터에 대한 처리 효율도 높아짐
값을 직접 저장 | 값의 주소를 저장 |
---|---|
데이터 할당시에는 빠름 | 데이터 할당시에는 느림 |
비교에 비용이 많이 듦 | 비교에 비용이 들지 않음 |
메모리 낭비 심함 | 메모리 낭비 최소화 |
어떤 데이터 타입이던 변수에 할당하기 위해서는 주솟값을 복사해야하기 때문.
기본형은 주솟값을 복사하는 과정이 한 번만 이뤄지고 참조형은 한 단계를 더 거침
원본 객체는 변하지 않아야 하는 경우 불변 객체가 필요
얕은 복사와 깊은 복사
얕은 복사 | 깊은 복사 |
---|---|
바로 아래 단계의 값만 복사 | 내부의 모든 값들을 찾아 전부 복사 (재귀적으로 구현) |
순수한 정보를 다룰때 JSON 문자열로 전환했다가 다시 JSON객체로 바꿔 구현하는 방법도 있음
undefined와 | null |
---|---|
어떤 변수에 값이 존재하지 않을 경우 | 사용자가 명시적으로 '없음'을 표현하기 위해 대입 |
< undefined가 반환되는 경우 >
1) 값을 대입하지 않은 변수, 주소를 지정하지 않은 식별자에 접근할 때
2) 객체 내부의 존재하지 않는 프로퍼티에 접근할 때
3) return 문이 없거나 호출되지 않는 함수의 실행결과
->>> 직접 undefined를 할당하지 않는것을 권장, 비어있음을 나타내고 싶을때 null을 사용
< let, const >
let, const는 할당하지 않은채로 초기화를 마쳐
TDZ에 들어간것처럼 보이고 호이스팅 되지않는다고 여겨짐
< 자바스크립트의 버그 >
typeof null === object
실행할 코드에 제공할 환경 정보들을 모아놓은 객체
하나의 실행컨텍스트를 구성하는 방법은 함수를 실행하는 것
블록스코프는 독립된 공간의 역할은 하지만 별개의 실행컨텍스트는 생성하지않음
실행컨텍스트가 활성화되는 시점에 선언된 변수를 끌어올리고 외부 환경정보를 구성한다.
해당 컨텍스트에 관련된 코드들을 실행하는데 필요한 환경 정보들을 수집하여 실행컨텍스트 객체에 저장
컨텍스트내의 식별자 정보 + 외부환경정보
VariableEnvironment | LexicalEnvironment |
---|---|
선언시점의 스냅샷으로 변경사항이 반영되지 않음 | 처음에는 VariableEnvironment와 같지만 변경사항이 반영 |
식별자 정보 수집 | 식별자 데이터 추적 |
environmentRecord | outerEnvironmentReference |
---|---|
매개변수명, 식별자, 함수명 등을 수집 | 직전 컨텍스트의 LexicalEnvironment 저장 |
순서대로 수집하여 식별자 정보들이 저장, 변수명을 코드 실행전에 알게 됨 | 자신이 선언된 시점의 LexicalEnvironment 참조 |
호이스팅 현상 발생 | 식별자의 유효범위를 안에서부터 검색해내가는 스코프 체인과 관련 |
가장 가까운 자신부터 점점 멀리 있는 스코프로 식별자를 찾아나가는 것
무조건 스코프 체인 상에서 가장 먼저 발견된 식별자에만 접근 가능 (변수 은닉화)
현재 어떤 함수가 동작중인지 다음엔 어떤 함수가 호출될 예정인지 등을 제어
기본적으로 실행 컨텍스트가 생성될 때 결정, 즉 함수를 호출할 때 결정
1) 전역공간에서 this는 전역객체(window)를 참조
2) 메서드로서 호출한경우 (~~~.func()
, ~~~[]()
- 앞에 객체가 명시 되어 있는 경우)
메서드 호출 주체를 참조(~~~)
3) 함수로서 호출한 경우 전역객체를 참조 메서드 내부함수에서도 동일
4) 콜백함수 내부에서의 this는 제어권을 넘겨받은 함수가 정의한 바에 따르며 그렇지 않은경우 전역객체 참조
5) 생성자 함수에서의 this는 생성될 인스턴스 참조
함수 | 메서드 |
---|---|
자체로 독립적인 기능을 수행 | 자신을 호출한 대상 객체에 관한 동작을 수행 |
call
, apply
메서드는 this를 명시적으로 지정하면서 함수또는 메서드를 호출
function Product(name, price) {
this.name = name;
this.price = price;
}
function Food(name, price) {
Product.call(this, name, price);
/* 기능적으로 call과 완전동일, 두번째 인자를 배열로 받음 */
// Product.apply(this, [name, price]);
this.category = 'food';
}
console.log(new Food('cheese', 5).name);
// expected output: "cheese"
bind
메서드는 this및 함수에 넘길 인수를 일부 지정하여 새로운 함수를 만듦
call과 비슷하지만 즉시 호출하지 않고 새로운 함수를 반환
즉, 함수에 this를 미리 적용
bind 메서드를 적용한 함수는 name프로퍼티에 자동으로 bound
라는 접두어가 붙음
const module = {
x: 42,
getX: function() {
return this.x;
}
};
const unboundGetX = module.getX;
console.log(unboundGetX()); // The function gets invoked at the global scope
// expected output: undefined
const boundGetX = unboundGetX.bind(module);
console.log(boundGetX());
// expected output: 42
자바스크립트의 모든 변수는 실은 특정 객체의 프로퍼티로 동작
전역변수 선언시 이를 전역객체의 프로퍼티로 할당
const outer = {
const inner1 = function () {
console.log(this); // Window { ... }
};
const self = this;
const inner2 = function () {
console.log(self); // { outer: f }
};
}
화살표 함수는 실행 컨텍스트를 생성할 때 상위 스코프 this를 그대로 활용할 수 있음
실행 컨텍스트 생성 시 this바인딩하는 과정이 제외,
접근하고자 하면 스코프체인상 가장 가까운 this에 접근
const outer = {
const inner3 = () => {
console.log(this); // { outer: f }
}
}
다른 코드의 인자로 넘겨주는 함수로 제어권도 함께 위임
콜백함수를 넘겨받은 코드는 콜백함수를 필요에 따라 적절한 시점에 실행
1) 콜백함수를 호출하는 시점을 스스로 판단하여 실행
2) 인자로 넘겨줄 값들 및 순서가 정해져 있음 (파라미터가 정해져있음)
3) this가 무엇을 바라보도록 할지 정해져 있는 경우가 있음 (ex- addEventListener)
-> 정해지지 않은 경우 전역객체를 바라봄. 임의로 this를 바꾸고 싶은 경우 bind
를 활용
setInterval
, setTimeout
, addEventListener
등이 있음const callbackFunc = () => {
console.log('callback!')
};
let timer = setInterval(callbackFunc, 200); // timer의 변수에는 setInterval의 ID값이 담김
콜백 함수로 어떤 어떤 객체의 메서드를 전달하더라도 메서드는 메서드가 아닌 함수로서 호출
-> this가 다름 (해당객체를 this로 바라볼 수 없음)
콜백지옥과 비동기 제어
동기적 코드 | 비동기적 코드 |
---|---|
즉시 처리가 가능한 대부분의 코드 | 별도의 요청, 실행 대기, 보류 등과 관련된 코드 |
여러 함수형 프로그래밍 언어에서 등장하는 보편적인 특성으로
이미 생명 주기가 끝난 외부 함수의 변수를 참조하는 함수
외부에서 선언한 변수를 참조하는 내부함수에서만 발생하는 현상
-> 외부함수의 LexicalEnvironment가 가비지 컬렉팅 되지 않는 현상
함수와 그 함수가 선언될 당시의 lexical environment(outerEnvironmentReference)의 상호관계에 따른 현상
유효범위가 사라진 후에도 호출할수 있는 함수
let outer = function () {
let a = 1; // 외부 변수
let inner = function () {
return ++a;
}
return inner; // inner 자체를 return 하여 이를 참조하는 a가 살아있음
};
let outer2 = outer();
가비지 컬렉터는 어떤 값을 참조하는 변수가 하나라도 있다면 그 값은 수집대상에 포함시키지 않는다.
즉, 좀비처럼 살아있게 되는 것!
필요성이 사라진 시점에 더는 메모리를 소모하지 않도록
식별자에 기본형데이터(보통 null / undefined)를 할당하여 참조카운트를 0으로 만듦
1) 콜백함수 내부에서 외부 데이터를 사용하고자 할 때
let buildFunc = function (param) { // 외부 데이터 : param
return function() {
console.log('param is ', param);
}
}
$el.addEventListener('click', buildFunc(param));
2) 접근 권한 제어(정보 은닉)
어떤 모듈의 내부로직에 대해 외부로의 노출을 최소화하여
모듈간의 결합도를 낮추고 유연성을 높이고자 하는 개념
클로저를 활용하여 외부 스코프에서 함수 내부의 변수들 중 선택적으로 일부의 변수에 대한 접근 권한 부여 가능 (public한 값과 private한 값을 구분가능)
let outer = function () {
let a = 1; // 공개 변수 (public)
let b = 2; // 지역 변수 (private)
let inner = function () {
return ++a;
}
return inner;
};
let outer2 = outer();
3) 커링 함수
여러 개의 인자를 받는 함수를 하나의 인자만 받는 함수로 나눠 순차적으로 호출될 수 있게 체인 형태로 구성한 것
마지막 인자가 넘어갈 때까지 함수 실행을 미루는 셈-> 지연실행
원하는 시점까지 지연시켰다가 실행하는 것이 요긴한 상황에서 적합
const curry = func => a => b => c => d => func(a, b, c, d);
1) return
으로 전달
2) 콜백
으로 전달
Symbol.for
메서드는전역 심볼공간에 인자로 넘어온 문자열이 이미 있으면 해당 값을 참조하고
선언되어 있지 않으면 새로 만드는 방식으로
어디서든 접근 가능하며 유일무이한 상수를 만들고자 할때 사용
자바스크립트는 프로토타입 기반언어
클래스 기반언어 | 프로토타입 기반언어 |
---|---|
상속 사용 | 어떤 객체를 원형으로 삼고 이를 복제(참조)함으로써 상속과 비슷한 효과를 얻음 |
prototype 객체 내부에는 인스턴스가 사용할 메서드를 저장.
인스턴스에서도 숨겨진 프로퍼티인 __proto__
([[Prototype]])
를 통해 이 메서드들에 접근할 수 있게됨
__proto__
를 통해 직접 접근하기보다 getPrototypeOf()
를 이용하는 것을 권장
__proto__
는 생략가능한 프로퍼티이기 때문에 바로 접근가능
1) 자바스크립트는 함수에 자동으로 객체인 prototype 프로퍼티를 생성
2) 해당 함수를 생성자 함수로 사용할 경우 (new와 함께 호출) 생성자 함수의 prototype 프로퍼티를 참조하여 인스턴스에 숨겨진 프로퍼티 __proto__
생성
3) __proto__
는 생략가능하기 때문에 인스턴스도 마치 자신의 것처럼 해당 메서드나 프로퍼티에 접근할 수 있음
콘솔에서 확인
짙은색은 열거가능한 프러퍼티, 옅은색은 열거할 수 없는 프로퍼티로
for in등으로 프로퍼티에 접근하고자 할 때 접근가능 여부를 색상으로 구분
인스턴스는 해당 생성자 함수의 이름을 표기함으로써 해당 함수의 인스턴스임을 표기
prototype에 있는 constructor 프로퍼티는 인스턴스가 자신의 생성자 함수가 무엇인지 알고자할 때 사용
프로토타입 체인 & 프로토타입 체이닝
프로토타입 체인
어떤 데이터의__proto__
프로퍼티 내부에 다시__proto__
프로퍼티가 연쇄적으로 이어진것
프로토타입 체이닝
프로토타입 체인을 따라가며 검색하는 것
let array = [1, 2]
/* .toString()은 object prototype */
array.toString() // object prototype속성을 체이닝을통해 사용할 수 있음
// '1,2'
어떤 생성자 함수이든 prototype은 객체이기 때문에 Object.prototype이 언제나 프로토타입 체인의 최상단에 존재하게 됨
객체만을 대상으로 동작하는 객체 전용 메서드들은 부득이 Object에 스태틱메서드로 부여할 수 밖에 없음
메서드가 오버라이드된 경우에는 자신으로부터 가장 가까운 메서드에만 접근 가능
클래스 | 인스턴스 |
---|---|
특성을지닌 집단, 추상적인 개념 | 클래스의 속성을 지니는 실존하는 개체 |
인스턴스에서 직접 접근할 수 없는 메서드
ES6 클래스 문법으로 이전보다 간단하게 구현 가능
ES5까지는 프로토타입 체이닝을 잘 연결하여 상속을 구현