[Node.js_4기] Today_I_Learn : javascript (24/01/02)

2024. 1. 2. 21:47공부/내배캠 TIL

목차

 

1. 학습 내용

2. 내용 정리

3. 예제

4. 생각 정리

 

1. 학습 내용 

 

(1) 데이터 타입 심화 : 

 

(2) 실행컨텍스트 : 

 

(3) this : 

 

2. 내용 정리 

 

(1) 

불변성과 가변성

-> 원시타입으로 저장한 정보는 가변성을 가져 원본도 영향을 받아 변한다. 불변성의 필요.

undefined

1. 변수에 값이 지정되지 않은 경우

2. 해당 데이터가 존재하지 않는 경우

3. return 없거나 호출되지 않는 함수의 실행결과

 null

1. '없다'를 명시적으로 표현

2. typeof null이 object인건 js자체 버그. 조심하기.

동등 연산자(==)  -> console.log(n == undefined); // true

일치 연산자(===) -> console.log(n === undefined); // false

 

(2)

실행 컨텍스트 : 코드 실행을 위한 환경 정보 수집 객체

스택 : Last In/First Out, 큐 : First In/First Out

콜스택 : js코드의 순서를 보장한다.

VE와 LE :

 - 모두 레코더와 아우터를 포함.

 - VE는 스냅샷 유지/ LE는 실시간 변화 지속 반영

 - 실행 컨텍스트 생성 : 데이터를 VE에배치, 이를 복사해 LE를 생성

LexicalEnvironment : 

레코더는 식별자 저장. 

호이스팅 : 식별자, 정보를 수집은 끝났으나 코드 자체는 실행 전. 가상의 개념.

1. 매개변수/변수는 선언부를 호이스팅.

2. 함수 선언은 전체를 호이스팅

3. 함수 선언문, 함수 표현식

스코프 : 식별자에 대한 유효범위

스코프 체인 : 유혀범위를 안에서부터 밖으로 검색해 나가는 것

아우터 : 스코프 체인이 가능하도록 하는 외부 환경의 참조 정

 

(3)

1. 상황에따라 달라지는 this

tihs는 실행 컨텍스트가 생성될 때 결정됨.

- 메서드 에서 this는 메서드가 속한 객체를 가리킴. (.로 호출하든, []로 호출하든 똑같음)

- 함수에서 this는 명시적으로 지정되지 않으면 전역 객체로 기본 설정됨.

- 중첩 함수는 전역this를 보여주지만, 화살표 함수를 사용한 예외도 존재

- 콜백 함수에서의 this는 컨텍스트를 잃을 수 있다.(콜백 함수도 함수다.) 별도 지정 없으면 전역객체

- 명시적 this 바인딩 : this에 별도 값을 저장 call, apply

- bind메서드는 지정된 this값을 사용하여 새로운 함수 생성. 바인딩된 함수의 name 속성에는 bound 접두어 붙음.

- 화살표 함수는 this에 대한 동작을 LexicalScope에서 포착함.

 

 

3. 예제 

 

(1) 데이터 타입 심화

// 불변 객체의 필요성
var user = {
    name:'onejang',
    gender:'male'
};

// 1. 
var changeName = function(user,newName){
    var newUser = user;
    newUser.name = newName;
    return newUser;
};
// 특징 : 객체 속성에 접근해 이름 변경 -> 가변

// user도 함께 영향을 받아버림
var user2 = changeName(user,'twojang');

// 결국 아래 로직이 skip
if(user!==user2){
    console.log('유저 정보가 변경됨')
}
console.log(user.name, user2.name);
console.log(user===user2); // true
// 가변성의 문제점

// 2. 개선
var changeName = function(user,newName){
    return {
        name:newName,
        gender:user.gender
    } 
};
// 특징 : 진짜로 새로운 user 객체를 만들어 할당

// user는 영향을 받지 않는다.
var user2 = changeName(user,'twojang');

// 아래 로직이 수행됨
if(user!==user2){
    console.log('유저 정보가 변경됨')
}
console.log(user.name, user2.name);
console.log(user===user2); // false
// 근데... 바꿀게 1억줄 있다면...?

// 3. 얕은 복사
var copyObject = function (target) {
    var result = {};
    // for~in 구문, 객체의 모든 프로퍼티에 접근
    // copyObject로 복사, 복사 후에 객체 프로퍼티 변경하면?
    for (var prop in target) {
        result[prop] = target[prop];
    }
    return result
}
var user = {
    name:'onejang',
    gender:'male',
    prop1:'1',
    prop2:'2',
    prop3:'3',
};
var user2 = copyObject(user); // 항상 user와 user2는 다르다
user2.name = 'twojang'
// 아래 로직이 수행됨
if(user!==user2){
    console.log('유저 정보가 변경됨')
}
console.log(user.name, user2.name);
console.log(user===user2);

// 4. 깊은 복사 : 
// 내부의 모든 값들을 하나하나 다 찾아서 모두 복사
// 결론 : 
// 객체의 프로퍼티 중, 기본형 데이터 : 그대로 복사
// + 참조형 데이터 : 다시 그 내부의 프로퍼티를 복사 
// ⇒ 재귀적 수행!
// 함수나 알고리즘이 자기 자신을 호출하여 반복적으로 실행
var copyObjectDeep = function(target) {
	var result = {};
	if (typeof target === 'object' && target !== null) {
		for (var prop in target) {
			result[prop] = copyObjectDeep(target[prop]);
		}
	} else {
		result = target;
	}
	return result;
}

//결과 확인
var obj = {
	a: 1,
	b: {
		c: null,
		d: [1, 2],
	}
};
var obj2 = copyObjectDeep(obj);

obj2.a = 3;
obj2.b.c = 4;
obj2.b.d[1] = 3;

console.log(obj);
console.log(obj2);

(3)

// (1). call
var func = function (a, b, c) {
	console.log(this, a, b, c);
};
// no binding
func(1, 2, 3); // Window{ ... } 1 2 3
// 명시적 binding
func.call({ x: 1 }, 4, 5, 6); // { x: 1 } 4 5 6

// (2). apply 메서드
// call과 완전 동일. 대신, this에 binding할 객체는 똑같이 넣어주고
// 나머지 부분만 배열 형태로 넘겨줌
var func = function (a, b, c) {
	console.log(this, a, b, c);
};
func.apply({ x: 1 }, [4, 5, 6]); // { x: 1 } 4 5 6

var obj = {
	a: 1,
	method: function (x, y) {
		console.log(this.a, x, y);
	}
};

obj.method.apply({ a: 4 }, [5, 6]); // 4 5 6

// (3). call/apply 메서드 활용
// 1. 유사배열객체에 배열의 메서드 적용
// 진짜 배열은 아니지만 배열처럼 사용 call/apply를 통해

//객체에는 배열 메서드를 직접 적용할 수 없어요.
//유사배열객체에는 call 또는 apply 메서드를 이용해 배열 메서드를 차용할 수 있어요.
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' ]


// (4). bind 메서드
// -> this를 binding하는 메서드
// call, apply랑은 좀 다르다 : 즉시 호출하지 않는다.
// [목적]
var func = function (a, b, c, d) {
    console.log(this, a, b, c, d);
};
func(1, 2, 3, 4);
// 1. 함수에 This 미리 적용
var bindFunc1 = func.bind({ x: 1 });
bindFunc1(5, 6, 7, 8);
// 2. 부분 적용 함수
var bindFunc2 = func.bind({ x: 1 }, 4, 5);
bindFunc2(6, 7);
console.log(func.name)
console.log(bindFunc1.name)
console.log(bindFunc2.name)
// name 프로퍼티
// 'bound(bind된)' 접두어

 

 

4. 생각 정리 

 

슬슬 처음보는 내용이 나오기 시작. 
특히 메모리 관련 설명이나 실행 컨텍스트 관련 내용은 한두번 봐서는 이해하기 힘들것 같다.

복습 또 복습.