Function.prototype.call(thisArg[,arg1[,arg2[, …]]])
var func = function(a,b,c){
console.log(this, a,b,c);
}
func(1,2,3); // Window{...} 1 2 3
func.call({x: 1}, 4,5,6); // {x: 1} 4 5 6
apply 메서드
Function.prototype.apply(thisArg[, argsArray])
var func = function(a,b,c){
console.log(this,a,b,c);
}
func.apply({x: 1}, [4,5,6]); // {x: 1} 4 5 6
객체에는 배열 메서드를 직접 적용할 수 없음
하지만 키가 0 또는 양의 정수인 프로퍼티가 존재하고, length 프로퍼티의 값이 0 또는 양의 정수인 객체, 즉 유사배열 객체
의 경우 call 또는 apply 메서드를 이용해 배열 메서드를 차용 가능
예제1)
var obj = {
0: 'a',
1: 'b',
2: 'c',
length: 3
}
// object에 push메서드를 쓰는 것은 원래는 안 되는데
// call을 쓰면 array의 push메서드를 object에 쓰는 것이 가능해진다.
Array.prototype.push.call(obj, 'd');
console.log(obj); // {0:'a', 1:'b', 2:'c', 3:'d', length: 4}
// slice에 인자가 없으면 얕은 복사를 하겠다라는 의미.
var arr = Array.prototype.slice.call(obj);
console.log(arr); // ['a','b','c','d']
예제2)
// 함수 내부에서 접근할 수 있는 arguments 객체도 유사배열객체임
function a(){
console.log(arguments);
var argv = Array.prototype.slice.call(arguments);
argv.forEach(function (arg){
console.log(arg);
}
}
a(1,2,3);
예제3)
document.body.innerHTML = '<div>a</div><div>b</div><div>c</div>'
var nodeList = document.querySelectorAll('div');
console.log(nodeList)
console.log(Array.isArray(nodeList)) // false 따라서 NodeList 도 유사배열 객체
var nodeArr = Array.prototype.slice.call(nodeList);
nodeArr.forEach(function(node){
console.log(node);
})
// nodeList.forEach(item=>console.log(item)); 은 될까 안될까?
정답
됨!!
⇒ 오잉 유사배열객체에는 배열의 메서드 쓰려면 call 메서드 써야하는 것 아니었남?
⇒ nodes는 프로토타입에 forEach가 있어서 된다.
=> 반면, document.getElementsById 와 같은 HTMLCollection은 call메서드를 써야한다.
function Person(name,gender){
this.name = name;
this.gender = gender;
this.sleep = function(){console.log(`${this.name}가 잠을 잔다`);}
}
function Student(name,gender,school){
Person.call(this, name, gender);
this.school = school;
}
const eunsu = new Student("eunsu", "female", "HUniversity");
eunsu.sleep() // eunsu가 잠을 잔다
// class의 상속과 비슷한 기능일까?
예제 Math.max()
var numbers = [10,20,30,40];
var max = Math.max.apply(null, numbers); // 여기서 null이 의미하는 것은 무엇일까?
var func = function(a,b,c,d){
console.log(this,a,b,c,d);
}
func(1,2,3,4); //
func.call({x:1}, 1,2,3,4})
var bindFunc1 = func.bind({x:1})
bindFunc1(5,6,7,8);
(bind메서드를 사용하여) 상위 컨텍스트의 this를 내부함수나 콜백함수에 전달하기
var obj = {
outer: function(){
console.log(this); // {outer: …}
var innerFunc = function(){
console.log(this); // Window {…}
}
innerFunc();
}
};
obj.outer();
var obj ={
outer: function(){
console.log(this);
var innerFunc = function(){
console.log(this); // {outer: …}
}.bind(this)
innerFunc();
}
}
obj.outer();
호출주체가 없을 때 자동으로 전역객체를 바인딩하지 않고, 호출 당시 주변환경의 this를 그대로 상속받아 사용할 수 있다면 좋겠다.(p.74) ⇒ 대표적인 방법 2가지(화살표함수, 변수활용)
forEach에 별도의 인자를 넣지 않은경우
- 콜백함수의 제어권을 갖는 forEach함수가 this를 무엇으로 할 지 결정하는데 지정안하면 this는 전역객체가 됨
var report = {
sum: 0,
count: 0,
add: function(){
var args = Array.prototype.slice.call(arguments);
args.forEach(function(entry){
this.sum += entry; // 여기서 this는? -> Window
++this.count;
});
}
}
report.add(60,85,95);
console.log(report.sum);
forEach의 두번째 인자에 this를 지정한 경우
var report = {
sum: 0,
count: 0,
add: function(){
var args = Array.prototype.slice.call(arguments);
args.forEach(function(entry){
this.sum += entry;
++this.count;
}, this);
}
}
report.add(60,85,95);
console.log(report.sum);
콜백함수와 함께 thisArg를 인자로 받는 메서드
Array.prototype.forEach(callback[, thisArg])
Array.prototype.map(callback[, thisArg])
Array.prototype.filter(callback[, thisArg])
Array.prototype.some(callback[, thisArg])
Array.prototype.every(callback[, thisArg])
...등