0%

201209_TIL(prototype, 빌트인 객체)

오늘 배운 것

프로토타입

for … in

1
2
3
4
5
6
7
8
9
10
11
12
13
const person = {
name: "Lee",
address: "Seoul",
__proto__: { age: 20 },
};

for (const key in person) {
// 객체 자신의 프로퍼티인지 확인한다.
if (!person.hasOwnProperty(key)) continue;
console.log(key + ": " + person[key]);
}
// name: Lee
// address: Seoul

상속받은 프로퍼티는 제외하고 객체 자신의 프로퍼티 만을 열거하려면 Object.prototype.hasOwnProperty 메서드를 사용하여 객체 자신의 프로퍼티인지 확인해야 한다.

Object.keys/values/entries 메서드

1
2
3
4
5
6
7
8
9
const person = {
name: "Lee",
address: "Seoul",
__proto__: { age: 20 },
};

console.log(Object.keys(person)); // ["name", "address"]
console.log(Object.values(person)); // ["Lee", "Seoul"]
console.log(Object.entries(person)); // [["name", "Lee"], ["address", "Seoul"]]

strict mode

프론트 엔드에서는 strick mode 보다는 ESlint를 사용하는 것이 좋다.

빌트인 객체

빌트인 전역 함수

parseInt() 는 문자열을 숫자로 변환한다. function parseInt(s: string, radix?: number): number 함수 설명이다. s: string은 문자열 필수 입력, radix?: number에서 ?:는 옵션이란 뜻이다. function 끝에 붙은 : number는 반환값이 number라는 뜻이다.

원시값과 래퍼 객체

1
2
3
const str = "hi";

console.log(str.length); // 2

내부적으로 . 이 있다면 문자열을 String 객체로 취급하여, 원시값으로 String 인스턴스를 생성하고 생성된 객체의 프로퍼티나 메서드에 접근한다.

문자열에 대해 마침표 표기법으로 접근하면 그 순간 래퍼 객체인 String 생성자 함수의 인스턴스가 생성되고 문자열은 래퍼 객체의 [[StringData]] 내부 슬롯에 할당된다. 래퍼 객체는 암묵적으로 변경한 객체를 원시값으로 다시 되돌리기 위해 사용된다.

String, Number, Boolean 원시값만 래퍼 객체를 갖는다.

This

일반 함수 호출

this의 사용에서 외부함수의 this와 내부함수의 this가 안 맞는 경우가 가장 힘든 경우이며, 그때는 that, bind(), 화살표 함수를 사용한다.

객체를 생성하지 않는 일반 함수에서 this는 의미가 없기 때문에, strict mode가 적용된 일반 함수 내부의 this에는 undefined가 바인딩된다.

1
2
3
4
5
6
7
8
9
10
function foo() {
"use strict";

console.log("foo's this: ", this); // undefined
function bar() {
console.log("bar's this: ", this); // undefined
}
bar();
}
foo();

일반 함수로 호출된 모든 함수(중첩 함수, 콜백 함수 포함) 내부의 this에는 전역 객체가 바인딩된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var value = 1;

const obj = {
value: 100,
foo() {
console.log("foo's this: ", this); // {value: 100, foo: ƒ}
// 콜백 함수 내부의 this에는 전역 객체가 바인딩된다.
setTimeout(function () {
console.log("callback's this: ", this); // window
console.log("callback's this.value: ", this.value); // 1 -> obj의 100을 원했지만 전역변수 value 값이 나왔다.
}, 100);
},
};

obj.foo();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var value = 1;

const obj = {
value: 100,
foo() {
const that = this; // foo의 this를 that에 넣어준다.

console.log("foo's this: ", this); // {value: 100, foo: ƒ}
// 콜백 함수 내부의 this에는 전역 객체가 바인딩된다.
setTimeout(function () {
console.log("callback's this: ", that); // obj
console.log("callback's this.value: ", that.value); // 100
}, 100);
},
};

obj.foo();

bind를 사용하는 경우

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var value = 1;

const obj = {
value: 100,
foo() {
// 콜백 함수에 명시적으로 this를 바인딩한다.
setTimeout(
function () {
console.log("callback's this: ", this); // obj
console.log("callback's this.value: ", this.value); // 100
}.bind(this),
100
);
},
};

obj.foo();

bind()는 함수 호출문, bind의 this는 인수이며 이는 외부에서 오는 것이다.(상위 스코프인 foo의 this이다.)

외부의 this를 함수 내부의 this와 묶는 것이 bind()이다.

call/apply/bind는 외부의 this를 내부로 밀어넣는 간접호출이다.

화살표 함수

1
2
3
4
5
6
7
8
9
10
11
var value = 1;

const obj = {
value: 100,
foo() {
// 화살표 함수 내부의 this는 상위 스코프의 this를 가리킨다. -> 상위 스코프는 foo이다.
setTimeout(() => console.log(this.value), 100); // 100
},
};

obj.foo();

메서드 호출

메서드를 호출할 때 메서드를 호출한 객체가 this 이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function Person(name) {
this.name = name;
}

Person.prototype.getName = function () {
return this.name;
};

const me = new Person("Lee");

// getName 메서드를 호출한 객체는 me다.
console.log(me.getName()); // ① Lee

Person.prototype.name = "Kim";

// getName 메서드를 호출한 객체는 Person.prototype이다.
console.log(Person.prototype.getName()); // ② Kim

①의 경우, getName 메서드를 호출한 객체는 me다. 따라서 getName 메서드 내부의 this는 me를 가리키며 this.name은 ‘Lee’이다.

②의 경우, getName 메서드를 호출한 객체는 Person.prototype이다. Person.prototype도 객체이므로 직접 메서드를 호출할 수 있다. 따라서 getName 메서드 내부의 this는 Person.prototype을 가리키며 this.name은 ‘Kim’이다.

메서드로서 호출하였을 때는 메서드의 마침표 연산자 앞에 있는 객체가 this다.

정렬

정렬 확인

주어진 배열(array)이 정렬되어 있다면 true, 그렇지 않다면 false를 반환하는 함수를 구현하라. 단, 어떠한 빌트인 함수도 사용하지 않고 for 문을 사용하여 구현하여야 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function isSorted(array) {
for (let i = 0; i < array.length - 1; i++) {
if (array[i] <= array[i + 1]) continue;
else {
for (let j = 0; j < array.length - 1; j++) {
if (array[j] >= array[j + 1]) continue;
else return false;
}
}
}
return true;
}

console.log(isSorted([1, 2, 3, 4, 5])); // true
console.log(isSorted([2, 3, 4, 1, 5])); // false

심심해서 내림차순일 경우도 정렬로 인정되게 해봤다.

버블 정렬

  • 버블 정렬(buble sort)은 순차적으로 배열을 순회하면서 인접한 두 요소를 비교하여 작은 요소를 왼쪽으로, 큰 요소를 오른쪽으로 교환한다.
  • 버블 정렬은 가장 간단하지만 가장 느린 정렬 알고리즘이다.
  • 시간 복잡도: O(n2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
function bubbleSort(array) {
for (let i = 0; i < array.length - 1; i++) {
for (let j = 0; j < array.length - i; j++) {
if (array[j + 1] < array[j]) {
[array[j + 1], array[j]] = [array[j], array[j + 1]];
}
}
}
return array;
}

console.log(bubbleSort([2, 4, 5, 1, 3])); // [1, 2, 3, 4, 5]
console.log(bubbleSort([5, 2, 1, 3, 4, 6])); // [1, 2, 3, 4, 5, 6]
console.log(bubbleSort([3, 1, 0, -1, 4, 2])); // [-1, 0, 1, 2, 3, 4]

Nyong’s GitHub