기초부터 완성까지, 프런트엔드 책 4장 [자바스크립트 기초 - 타입 변환과 함수] 파트
toString()
→ 결과 값 ‘[Object object]’ → 결과가 원시 타입이면 결과를 문자열로 변환하여 반환하고, 그렇지 않다면 valueOf()
호출 → 결과 값이 원시 타입이면 결과를 문자열로 변환하여 반환하고, 그렇지 않다면 TypeError 발생console.log(String({})); // '[Object object]'
valueOf()
→ 결과 값으로 객체를 그대로 반환 → 결과가 원시 타입이면 결과를 문자열로 변환하여 반환, 그렇지 않다면 toString()
메소드 호출 → 결과 값이 원시 타입이면 결과를 문자열로 변환하여 반환하고, 그렇지 않다면 TypeError 발생function setDefault(a){ return a || 'default string';}
const a = 'javascript';
function doSome(){ // ...\ }
a && doSome();
const a ='';
// a가 null, undefined 인 경우에만 'default' 문자열이 b의 값으로 할당
const b = a ?? 'default';
함수 선언문
function myFunction(a, b) { return a * b; }
함수 표현식
const myFunction = function(a, b) { return a * b; }
console.log(myFunction(2, 3); // 6
←이런식으로const myFunction = function doSome(a, b){ return a * b; }
console.log(myFunction(2,3)); // 6
console.log(doSome(2, 3)); // Uncaught ReferenceError: doSome is not defined
const factorial = function doSome(n){ return n<=1 ? 1 : n*doSome(n-1); }
console.log(factorial(5)); // 120
argument
, 매개변수는 parameter
function greeting(name = 'Shin'){ return `Hello ${name}`; }
function sum(x, y, z) {
console.log(arguments[0]);
console.log(arguments[1]);
console.log(arguments[2]);
return x+y+z;
} sum(1,2) // 1\2\undefined
arguments는 유사 배열 객체이므로 인덱스로 프로퍼티에 접근할 수 있다.
length 프로퍼티도 가짐
ES6부터 나머지 매개변수
('…')로 대체할 수 있다. 나머지 매개변수는 유사 배열 객체가 아니라 진짜 배열이기에 인자들을 배열로 다룰 수 있다.
function sum(...args){ // args는 배열이라 forEach() 사용가능
args.ForEach(function (arg)){ // ... } );
}
sum(1, 2);
바인딩?
일반적으로 변수와 변수에 관련된 프로퍼티를 연관시키고 값을 설정하는 것을 바인딩이라고 한다. JS에서는 함수 호출 시 값이 결정되는 arguments 객체나 this에 바인딩된다는 표현을 자주 사용한다.
// 화살표 함수의 나머지 매개변수 사용
const func = (...args) => args[0];
func(1); // 1
일반 함수
(함수 선언문 또는 함수 표현식으로 정의한 함수)console.log(this === window);
function func() {
'use strict';
console.log(this === window); // false
console.log(this === undefined); // true
} func();
생성자 함수
(new 키워드 사용)function Vehicle(type) { this.type = type; }
const car = new Vehicle('Car');
생성자 함수 내의 코드를 실행하기 전에 객체를 만들어 this에 바인딩한다. 생성된 객체는 생성자 함수의 prototype 프로퍼티에 해당하는 객체를 프로토타입으로 설정한다.
this에 바인딩한 객체에 프로퍼티를 생성한다. (this.type = type;
부분)
생성된 객체, this에 바인딩한 객체를 반환한다. 반환 값을 따로 명시하지 않아도 this에 바인딩된 객체가 반환되지만, this가 아닌 다른 반환 값을 명시적으로 지정할 수 있다.
function Vehicle(type) {
this.type = type;
return this; // 이 부분을 생략하여도 this에 바인딩한 객체(type)가 반환된다.
}
const obj = {
lnag: 'javascript',
greeting() { // obj 객체의 프로퍼티인 함수 greeting() -> 메소드
// this가 obj 객체로 바인딩된다.
console.log(this);
return `hello ${this.lang}`;
}
}
console.log(obj.greeting()); // 'hello javascript'
const obj = {
lnag: 'javascript',
greeting() {
console.log(this);
return `hello ${this.lang}`;
}
}
const greeting = obj.greeting;
console.log(greeting()); // 'hello undefined'
call(), apply(), bind()
)call(), apply()
어떤 함수를 다른 객체의 메소드처럼 호출할 수 있게 한다.
this를 특정 객체에 바인딩하여 함수를 호출하는 역할을 한다.
// call()
const obj = { name: 'javascript' };
function greeting() {
return `Hello ${this.name}`;
}
console.log(greeting.call(obj)); // 'Hello javascript'
// call() 메소드의 첫 인자 이후 모든 인자는 **호출하는 함수**로 전달된다.
const obj = { name: 'Shin' };
function getUserInfo(age, country) {
return `name: ${this.name}, age: ${age}, country: ${country}`;
}
console.log(getUserinfo.call(obj, 20, 'Korea'));
// 'name: Shin, age: 20, country: Korea'
apply()는 call()과 같은 기능을 하지만, 호출되는 함수에 전달할 인자를 배열로 전달해야 한다는 차이점이 있다.
// apply()
const obj = { name: 'Shin' };
function getUserInfo(age, country) {
return `name: ${this.name}, age: ${age}, country: ${country}`;
}
console.log(getUserinfo.call(obj, [20, 'Korea']));
// 'name: Shin, age: 20, country: Korea'
bind()
**// bind()**
const obj1 = { name: 'Lee' };
const obj2 = { name: 'Shin' };
function getUserInfo(age, country) {
return `name: ${this.name}, age: ${age}, contry: ${country}`;
}
const bound = getUserInfo.bind(obj1);
console.log(bound(20, 'Korea')); // 'name: Lee, age: 20, country: Korea'
console.log(bound.apply(obj2, [20, 'Korea'])); // 위와 동일!
**//** **함수에 전달시킬 인자를 고정할 수도 있다.**
const fixedBound = getUserInfo.bind(obj1, 20);
console.log(fixedBound('Korea')); // 'name: Lee, age: 20, country: Korea'
**렉시컬 this**
란?> 렉시컬 스코프는 자바스크립트 엔진이 변수를 찾는 검색 방식에 대한 규칙이며, 함수를 어디에 선언했는지에 따라 결정된다.
>
```jsx
const obj = {
lang: 'javascript',
greeting: () -> {
return `hello ${this.lang}`;
}
}
console.log(obj.greeting()); // **'hello undefined'**
```
- 화살표 함수의 렉시컬 this가 obj가 아닌 obj를 둘러싸고 있는 전역 컨텍스트에서 값을 받아오기 때문에 위와 같은 결과가 나온다. 전역 객체를 this로 가리키고 있다.
// setTimeout 사용 예제
const obj = {
lang: 'javascript',
greeting() {
setTimeout((function timer() {
console.log(this.name);
}).bind(this), 1000);
}
}
// 화살표 함수로 setTimeout 함수 사용
const obj = {
lang: 'javascript',
greeting() {
setTimeout(() => {
console.log(this.name);
}, 1000);
}
} // 더욱 간결하게 변경할 수 있다.
block.addEventListener('click', function() {
// this는 block 객체에 바인딩된다.
console.log(this.id);
});
block.addEventListener('click', () => {
// this는 전역 객체에 바인딩된다.
console.log(this.id);
});
this 바인딩은 함수 호출에 따른 컨텍스트에 따라 달라지며 call(), apply(), bind()와 같은 메소드를 사용하여 변경할 수 있다. 하지만 ES6부터 등장한 화살표 함수는 렉시컬 this를 가지기에 생성자 함수로 사용할 수 없으며, this 바인딩을 변경할 수 없다.