0%

201125_TIL(객체, 함수)

오늘 한 것

타입 변환과 단축 평가

자열 타입으로 변환

1.toString() → 중의적 표현이라서 문맥에 따라 숫자 뒤의 .은 소수점으로 인식
(1).toString()으로 해야한다.

원시값과 객체의 비교

원시값

1
2
3
// y에는 x를 평가하여 x의 값을 참조하여 값을 전달한다. (값에 의한 전달)
var x = 10;
var y = x;

원시값은 변경 불가이다.
변수값 변경은 ‘재할당’이다. 변수값 변경과 원시값 변경은 다른 의미이다.

상수는 단 한 번만 할당이 허용되는 변수이므로 상수와 변경 불가능한 값을 동일시하는 것은 곤란하다. 상수는 재할당이 금지된 변수일 뿐이다.

값에 의한 전달

1
2
var score = 80;
var copy = score;

score의 80이 평가되어 score의 값 80을 복사한 후 메모리에 마련한 뒤 copy에 할당해 준다.

객체

객체는 프로퍼티의 개수가 정해져 있지 않으며, 동적으로 추가되고 삭제할 수 있다. 또한 프로퍼티의 값에도 제약이 없다. 따라서 객체는 원시값과 같이 확보해야 할 메모리 공간의 크기를 사전에 정해 둘 수 없다.

클래스 기반 객체 지향 언어는 객체에 할당된 메모리량을 정의한 클래스를 이용해 알 수 있다. 하지만 프로토타입 기반 객체 지향 언어는 객체의 할당 메모리량을 알 수 없다.
만약 객체가 원시값 처럼 동작한다면 메모리 소비가 매우 많다. → 변경 불가능한 값을 변경을 위해서는 복사한 값에 대한 새로운 메모리 공간이 필요하기 때문이다.

1
2
3
4
5
var person = {
name: "Kim",
};
// 프로퍼티 값 갱신
person.name = "Lee";
1
2
3
4
5
6
7
var person = {
name: "Kim",
};

person = {
name: "Lee",
};

위 두 상황은 같은 과정일까? → 물론 아니다. 전자는 프로퍼티 값만을 갱신해주는 행위지만, 후자는 person 식별자에 새로운 객체 생성해서 참조해주는 것이다.

1
2
3
4
5
6
7
8
9
10
var person1 = {
name: "Lee",
};

var person2 = {
name: "Lee",
};

console.log(person1 === person2); // false
console.log(person1.name === person2.name); // true

person1과 person2의 변수 값은 객체의 참조 주소이다. 물론 person1과 person2는 내용이 같을 뿐 다른 객체이기에 참조 주소도 다르다.
반면 person1.name과 person2.name은 모두 원시값 문자열 ‘Lee’의 표현식이기 때문에 같은 값으로 평가된다.

얕은 복사와 깊은 복사

1
2
3
4
5
6
7
8
9
10
11
12
13
// 얕은 복사 예
var person = {
name: "Lee",
};

// 참조에 의한 전달.
// 두 식별자가 하나의 객체를 공유한다.
var copy = person;

copy.name = "Kim";

console.log(person); // Kim
console.log(copy === person); // true

얕은 복사는 항상 조심해야한다.
깊은 복사를 해야 객체의 불변성을 얻을 수 있다. 하지만 깊은 복사는 퍼포먼스 측면에서 좋지 않기 때문에 대부분 얕은 복사를 기본으로 한다.
깊은 복사를 사용하고 싶다면 라이브러리를 사용해는 것이 좋다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const o = {
a: {
b: 2,
},
f() {},
};

// lodash의 cloneDeep을 사용한 깊은 복사
// "npm install lodash"로 lodash를 설치한 후, Node.js 환경에서 실행
const _ = require("lodash");

let c = _.cloneDeep(o);
console.log(o === c); // false
console.log(o.a === c.a); // false
console.log(c.f); // f

함수

1
2
3
4
// 변수에 함수 리터럴을 할당 (함수 표현식)
var f = function add(x, y) {
return x + y;
};
  • ;이 붙는 것은 표현식이라는 것이다. 값으로 평가되는 함수 리터럴이다. 함수 리터럴은 변수에 참조하기 직전에 생성한다.(함수 선언문은 runtime 전에 정의됨)
  • 함수 이름 add는 함수 몸체 내에서만 참조할 수 있는 식별자다.(함수 이름 생략 가능)
  • 함수가 객체라는 사실은 함수형 프로그래밍이 가능하다는 말이다. 함수가 객체가 아니라면 함수형 프로그래밍이 불가능하다.
1
2
3
4
5
6
7
8
9
10
11
// 함수 선언문(function declaration/function statement)
function add(x, y) {
return x + y;
}
// 함수 표현식(function expression)
var add = function (x, y) {
return x + y;
};

// 화살표 함수
var add = (x, y) => x + y;

선언문은 익명함수가 불가능하고 ; 가 붙지 않으며 표현식처럼 값으로 평가되지 않는다. 값으로 평가되는 문맥에서는 함수는 표현식이다.

함수 호이스팅

1
2
3
4
5
6
7
8
9
10
11
// 함수 호이스팅
foo();

// 함수 선언문은 runtime 이전에 정의되고 함수 이름으로 동일한 식별자를 생성함.
function foo() {
console.log("foo");
}

// 변수 호이스팅
console.log(x);
var x = 1;

가변인자 함수

1
2
3
4
5
6
7
8
function sum() {
var total = 0;
for (var i = 0; i < arguments.length; i++) total += arguments[i];
return total;
}

var result = sum(1, 2, 3, 4, 5);
console.log(result); // 15

argument는 유사배열로서 인자가 내부에 모두 저장되기 때문에 가능하다.

오늘 느낀 것

  • 슬슬 어렵다. 그래도 본격적으로 공부하니까 재밌다.

  • 배우는 것이 많다. 배움에서 끝내지 말고 학습하자.

Nyong’s GitHub