유블로그

자바스크립트 함수 호출과 this 본문

JavaScript & jQuery

자바스크립트 함수 호출과 this

yujeong kang 2021. 6. 18. 23:25

arguments 객체

function func(arg1, arg2) {
	console.log(arg1, arg2);
};

func();			// undefined undefined
func(1);		// 1 undefined
func(1,2);		// 1 2
func(1,2,3);		// 1 2

함수를 호출할 때 같이 넘긴 인자들이 arguments 라는 유사 배열 객체에 담겨 전달된다.

이 객체의 구성은

  • 함수 호출 시 넘겨진 인자들 : 유사배열 형태로, 첫번째 인자는 0번 인덱스, 두번째 인자는 1번 인덱스.. 에 저장됨. 배열은 아니므로 배열 함수 사용 불가
  • length 프로퍼티 : 전달된 인자 개수
  • callee 프로퍼티 : 현재 실행중인 함수의 참조값

가 있다.

 

arguments 객체는 매개변수 개수가 정확하게 정해져있지않거나, 전달된 인자 개수마다 다른 처리를 해줘야할 때 유용하다.

function sum() {
	var result = 0;
    for(var i = 0; i < arguments.length; i++) {
    	result += arguments[i];
    }
    return result;
};

console.log(sum(1));		// 1
console.log(sum(1,2,3));	// 6

이렇게 sum() 안에 인자 개수를 정확히 적지 않아도 arguments 객체를 이용하여 인자에 접근할 수 있다.


호출 패턴과 this 바인딩

(1) 객체 메서드 호출 시 this 바인딩

var obj1 = {
	name: '이름1',
    sayName: function () {
    	console.log(this.name);
    }
};

var obj2 = {
	name: '이름2'
};

obj2.sayName = obj1.sayName;

obj1.sayName();	// 이름1
obj2.sayName();	// 이름2

obj2의 sayName은 obj1의 sayName과 같은 함수를 참조하지만

this는 호출한 객체에 바인딩 하기 때문에

obj1 과 obj2 의 sayName() 결과가 다르다.


(2) 함수 호출 시 this 바인딩

함수 호출 시 함수 내부 코드에서 사용된 this는 전역 객체에 바인딩된다 !

브라우저에서 자바스크립트를 실행하는 경우에 전역 객체는 window 이다.

var test = 'hello';
console.log(test);			// hello
console.log(window.test);	// hello

var sayTest = function() {
	console.log(this.test);
};

sayTest();	// hello

자바스크립트의 전역 변수는 전역 객체인 window의 프로퍼티다.

 

내부 함수에서도 this 가 전역 객체에 바인딩된다 !

var val = 100;

var obj = {
	value: 1,
    func1: function () {
    	this.value += 1;
        console.log(this.value);
        
        func2 = function () {
          this.value += 1;
          console.log(this.value);
          
          func3 = function () {
            this.value += 1;
            console.log(this.value);
          }
          
          func3();
        }
        
        func2();
    }
};

obj.func1();

위 코드의 출력은

2

101

102

이다.

 

이 상태!

 

그렇다면 내부함수에서 부모 함수가 가리키는 this (obj) 에 접근하려면 ?

that 이라는 변수를 사용한다.

var val = 100;

var obj = {
	value: 1,
    func1: function () {
    	this.value += 1;
        console.log(this.value);
        
        func2 = function () {
          that.value += 1;
          console.log(that.value);
          
          func3 = function () {
            that.value += 1;
            console.log(that.value);
          }
          
          func3();
        }
        
        func2();
    }
};

obj.func1();

출력 결과

2

3

4

이렇게 바꿀 수 있다 !


(3) 생성자 호출 시 this 바인딩

var Person = function (name) {
	this.name = name;
};

var yj = new Person('yj');
console.log(yj.name);	// yj

만약 생성자 함수를 호출할 때 new 키워드를 붙이지 않거나, 일반 함수에 new를 붙이면 this가 원하지 않는 곳에 바인딩된다.

var Person = function (name, age) {
	this.name = name;
    this.age = age;
};

var yj = Person('yj', 10);

console.log(yj);		// undefined
console.log(window.name);	// yj
console.log(window.age);	// 10

위처럼 Person 함수에 작성된 this는 window 객체에 바인딩되어 yj 객체를 출력하면 undefined 가 나온다.

일반 함수에서 return 값이 없으면 undefined 가 나오기 때문이다.

 

자바스크립트에서 일반 함수와 생성자 함수 구분이 없으므로

생성자 함수는 앞글자를 대문자로 쓰자 !

 

그래도 new 를 사용하지 않아 발생하는 에러를 막기 위해 다음과 같은 코드를 쓰기도 한다고 한다.

var Person = function (arg) {
	if(!(this instanceof Person)) {
    	return new Person(arg);
    }
    this.value = arg ? arg : 0;
};
if(!(this instanceof arguments.callee))

arguments의 callee 는 호출한 함수를 가리키기 때문에 이렇게 쓰기도 한다.


(4) call과 apply 메서드를 이용한 this 바인딩

this 를 특정 객체에 바인딩 시키기 위한 방법이다.

apply(), call() 은 Function.prototype 객체의 메서드이다.

apply(함수 내부에서 사용한 this에 바인딩할 객체, 함수를 호출할 때 넘길 인자들의 배열)

function Person (name, age) {
	this.name = name;
    this.age = age;
};

var yj = {};
Person.apply(yj, ['yj', 10]);	// this에 바인딩할 객체를 yj 로 지정
console.log(dir);

// 출력결과
// age: 10
// name: "yj"

이렇게 명시적으로 바인딩할 객체를 지정할 수 있다.

 

call은 apply의 두번째 인자를 배열 형태 대신 각각 인자로 넘긴다.

Person.apply(yj, ['yj', 10]);
Person.call(yj, 'yj', 10);

위 두 줄은 동일하다.  

 

function func () {
	console.dir(arguments);
    
    arguments.shift();	// 에러! arguments 는 유사배열이기 때문에 배열 메서드 사용불가
    
    var args = Array.prototype.slice.apply(arguments);
    console.log(args);
}

func(1,2,3);

Array.prototype.slice.apply(arguments); 를 사용하면

Array.prototype.slice() 를 호출하는데, this를 arguments 에 바인딩함으로써

arguments.slice() 형태로 사용할 수 있다.

이 때 args 의 prototype은 Array.prototype 이다.

 

 

 

 


출처: 송형주, 고현준, 인사이트 자바스크립트, 한빛미디어(2020)