function fn(){
console.log(3)
}
setTimeout(fn, 3000);
위와 같인 코드
setTimeout(function() {
console.log(3)
}, 3000);
call, apply, bind: 함수 호출 방식과 관계없이 this를 지정할 수 있음
call 메서드는 모든 함수에서 사용할 수 있으며, this를 특정값으로 지정할 수 있다.
const jubby = {
name: "jubby",
};
const ohwa = {
name: "ohwa",
};
function showThisName() {
console.log(this.name); // 여기서 this = window
}
showThisName(); // 아무것도 뜨지 않는다.
showThisName.call(jubby); // jubby, this가 jubby가 된다.
function update(birthYear, occupation) {
this.birthYear = birthYear;
this.occupation = occupation;
}
update.call(jubby, 1998, 'dancer'); // jubby = this, 뒤부터는 매개변수 값.
console.log(jubby);
apply는 함수 매개변수를 처리하는 방법을 제외하면 call과 완전히 같다. call은 일반적인 함수와 마찬가지로 매개변수를 직접 받지만, apply는 매개변수를 배열로 받는다.
const jubby = {
name: "jubby",
};
const ohwa = {
name: "ohwa",
};
function showThisName() {
console.log(this.name); // 여기서 this = window
}
showThisName(); // 아무것도 뜨지 않는다.
showThisName.call(jubby); // jubby, this가 jubby가 된다.
function update(birthYear, occupation) {
this.birthYear = birthYear;
this.occupation = occupation;
}
update.apply(jubby, [1998, 'dancer']);
console.log(jubby);
const minNum = Math.min(3, 10, 1, 6, 4);
const maxNum = Math.max(3, 10, 1, 6, 4);
console.log(minNum); // 1
console.log(maxNum); // 10
// 배열에선 사용이 안된다.
const nums = [3, 10, 1, 6, 4];
const minNum = Math.min(nums);
const maxNum = Math.max(nums);
console.log(minNum); // NaN
console.log(maxNum); // NaN
// 나머지 매개변수 사용
const minNum = Math.min(...nums);
const maxNum = Math.max(...nums);
console.log(minNum); // 1
console.log(maxNum); // 10
// apply() 사용
const minNum = Math.min.apply(null, nums); // (null,[3,10,1,6,4])
const maxNum = Math.max.apply(null, nums);
console.log(minNum); // 1
console.log(maxNum); // 10
// call() 사용
const minNum = Math.min.call(null, ...nums); // (null,3,10,1,6,4)
const maxNum = Math.max.call(null, ...nums);
console.log(minNum); // 1
console.log(maxNum); // 10
bind는 함수의 this 값을 영구적으로 바꿀 수 있다.
const jubby = {
name: "jubby",
};
function update(birthYear, occupation) {
this.birthYear = birthYear;
this.occupation = occupation;
}
const updateJubby = update.bind(jubby); // 항상 jubby를 this로 갖는다.
updateJubby(1998, 'dancer');
console.log(jubby);
const user = {
name: "jubby",
showName: function() {
console.log(`hello, ${this.name}`);
},
};
user.showName(); // hello, jubby
let fn = user.showName;
fn(); // hello,
fn.call(user); // hello, jubby
fn.apply(user); // hello, jubby
let boundfn = fn.bind(user);
boundfn(); // hello, jubby
const user = {
name: "jubby"
}
user.name // jubby
// hasOwnProperty(): 자신이 프로퍼티를 가지고 있는지 확인할 수 있는 메소드
user.hasOwnProperty('name'); // true
user.hasOwnProperty('age'); // false
객체에서 프로퍼티를 읽으려고 하는 데 없으면 일단 __proto__
에서 찾는다.
만약, hasOwnProperty()
메소드가 객체 안에 있으면?
const user = {
name: "jubby",
hasOwnProperty: function() {
console.log('haha');
}
}
user.hasOwnProperty(); // haha
객체에 그 프로퍼티가 있으면 거기서 탐색을 멈춘다. 없을때만 __proto__
에서 프로퍼티를 찾는다.
const car = {
wheels: 4,
drive() {
console.log("drive..");
},
};
const bmw = {
color: "red",
navigation: 1,
};
const benz = {
color: "black",
};
const audi = {
color: "blue",
};
bmw.__proto__ = car; // car가 bmw의 proto가 된다.
benz.__proto__ = car; // benx는 car의 상속을 받는다.
audi.__proto__ = car;
const x5 = {
color: "white",
name: "x5",
};
// 상속은 계속 이어질 수 있다.
x5.__proto__ = bmw;
> bmw
{color: "red", navigation: 1}
> bmw.color
"red"
> bmw.wheels;
4
> x5.name
"x5"
> x5.navigation
1
> for(p in x5) {
console.log(p);
}
color
name
navigation
wheels
drive
> x5
{color: "white", name: "x5"}
> Object.keys(x5);
["color", "name"]
> Object.values(x5);
["white", "x5"]
> for(p in x5){
if(x5.hasOwnProperty(p)){
console.log('o', p);
} else {
console.log('x', p);
}
}
o color
o name
x navigation
x wheels
x drive
생성자 함수 사용하기
const car = {
wheels: 4,
drive() {
console.log("drive..");
},
};
const Bmw = function (color) {
this.color = color;
};
const x5 = new Bmw("red");
const z4 = new Bmw("blue");
x5.__proto__ = car;
z4.__proto__ = car;
위와 같은 코드
const Bmw = function (color) {
this.color = color;
};
// 생성자 함수가 생성하는 객체에 `__proto__`를 각각 설정한다는 의미이다.
Bmw.prototype.wheels = 4;
Bmw.prototype.drive = function () {
console.log("drive..");
};
Bmw.prototype.navigation = 1;
Bmw.prototype.stop = function () {
console.log("STOP!");
};
const x5 = new Bmw("red");
const z4 = new Bmw("blue");
>x5.stop();
STOP!
생성자 함수가 새로운 객체를 만들어 낼 때, 그 객체는 생성자의 인스턴스라고 불린다.
instanceof()를 이용해서 객체와 생성자를 구분할 수 있다. 이는 해당 객체가 그 생성자로부터 생성된 것인지를 판단해서 true 혹은 false를 반환한다.
// Bmw를 이용해서 z4를 만들었다, z4는 Bmw의 인스턴스 이다.
> z4 instanceof Bmw
true
생성자(Bmw)를 통해서 만들어진 인스턴스 객체(z4)는 constructor 프로퍼티를 가진다.
// z4의 생성자는 Bmw 이다.
> z4.constructor === Bmw;
true
위 코드를 좀 더 깔끔하게 작성해본다.
const Bmw = function (color) {
this.color = color;
};
Bmw.prototype = {
wheels: 4,
drive() {
console.log("drive..");
},
navigation: 1,
stop() {
console.log("STOP!");
},
}
const x5 = new Bmw("red");
const z4 = new Bmw("blue");
하지만 이렇게 되면 constructor가 사라진다.
> z4.constructor === Bmw;
false
그렇게 때문에 각각 명시해 주거나 아래와 같이 작성하면 된다.
Bmw.prototype = {
constructor: Bmw,
wheels: 4,
drive() {
console.log("drive..");
},
navigation: 1,
stop() {
console.log("STOP!");
},
}
const Bmw = function (color) {
this.color = color;
};
const x5 = new Bmw("red");
> x5
{color: "red"}
> x5.color = "black";
> x5.color
"black"
위와 같이 color 값이 변경되지 않게 하려면 아래와 같이 작성한다.
const Bmw = function (color) {
const c = color;
this.getColor = function () {
console.log(c);
};
};
const x5 = new Bmw("red");
값을 얻을 수 있는 방법만 있고, 바꿀 수 있는 방법은 없다.
> x5.getColor();
red
ES6에 추가된 스펙이다.
const User = function (name, age) {
this.name = name;
this.age = age;
this.showName = function() {
console.log(this.name);
};
};
/* showName() Prototype으로 바꾸기 */
User.prototype.showName = function() {
console.log(this.name);
};
/* class 사용 */
Class User2 {
// constructor(): 객체를 만들어주는 생성자 메서드
constructor(name, age) {
this.name = name;
this.age = age;
}
showName() { // prototype에 저장된다.
console.log(this.name);
}
}
const jubby = new User('jubby', 25);
const ohwa = new User2('ohwa', 28); // new를 통해 호출하면 constructor가 자동으로 실행된다.
new를 사용하지 않으면?
const jubby = User('jubby', 25);
const ohwa = User2('ohwa', 28); // error가 발생한다.
for..in문은 prototype이 포함된 프로퍼티들을 다 보여주고, 객체가 가지고 있는 프로터피만 판별하기 위해서는 hasOwnProperty()를 사용해야 한다. 하지만 class의 메서드는 for..in 문에서 제외된다.
const User = function (name, age) {
this.name = name;
this.age = age;
this.showName = function() {
console.log(this.name);
};
};
/* class 사용 */
Class User2 {
// constructor(): 객체를 만들어주는 생성자 메서드
constructor(name, age) {
this.name = name;
this.age = age;
}
showName() { // prototype에 저장된다.
console.log(this.name);
}
}
const jubby = new User('jubby', 25);
const ohwa = new User2('ohwa', 28);
for(const p in jubby) {
console.log(jubby); // name age showName
}
for(const p in ohwa) {
console.log(ohwa); // name age
}
extends 키워드를 사용한다.
class Car {
constructor(color) {
this.color = color;
this.wheels = 4;
}
drive() {
console.log("drive..");
}
stop() {
console.log("STOP!");
}
};
class Bmw extends Car() {
park() {
console.log("PARK");
}
};
const z4 = new Bmw("blue");
class Car {
constructor(color) {
this.color = color;
this.wheels = 4;
}
drive() {
console.log("drive..");
}
stop() {
console.log("STOP!");
}
};
class Bmw extends Car() {
park() {
console.log("PARK");
}
stop() { // overriding
console.log("OFF");
}
};
const z4 = new Bmw("blue");
z4.stop(); // 'OFF' 출력
부모 메서드를 그대로 사용하면서 확장하고 싶다면, super().method명
사용.
class Bmw extends Car() {
park() {
console.log("PARK");
}
stop() { // overriding
super.stop();
console.log("OFF");
}
};
const z4 = new Bmw("blue");
z4.stop();
// STOP!
// OFF
constructor overriding, 자식 생성자에서 this를 사용하기 전에 부모 생성자를 반드시 먼저 호출해야 한다.
class Bmw extends Car() {
// 부모 생성자의 인수와 동일한 인수를 넣어줘야 한다.
constructor(color) {
super(color); // 항상 부모 생성자를 먼저 실행해주어야 한다.
this.navigation = 1;
}
park() {
console.log("PARK");
}
};
const z4 = new Bmw("blue");