본문으로 바로가기

4. 함수와 프로토타입 체이닝 (4)

category language/JavaScript 2019. 11. 22. 20:37

4.4 함수 호출과 this

4.4.1 arguments 객체

자바스크립트에서는 함수를 호출할 때 함수 형식에 맞춰 인자를 넘기지 않더라도 에러가 발생하지 않는다.


예제 4-21 함수 형식에 맞춰 인자를 넘기지 않더라도 함수 호출이 가능함을 나타내는 예제 코드

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

 

정의된 함수의 인자보다 적게 함수를 호출했을 경우, 넘겨지지 않은 인자에는 undefined 값이 할당됨. 정의된 인자 개수보다 많게 함수를 호출했을 경우에는 에러 x, 초과된 인수는 무시됨.

—> 런타임 시에 호출된 인자의 개수를 확인하고 이에 따라 동작을 다르게 해줘야 할 경우가 있다. 이를 가능하게 하는 것이 arguments 객체

자바스크립트에서는 함수를 호출할 때 인수들과 함께 암묵적으로 arguments 객체가 함수 내부로 전달된다. arguments 객체는 함수를 호출할 때 넘긴 인자들이 배열 형태로 저장된 객체를 의미. 이 객체는 실제 배열이 아닌 유사 배열 객체


예제 4-22 arguments 객체 예제 코드

// add() 함수
function add(a, b) {
    // arguments 객체 출력
    console.dir(arguments);
    return a+b;
}

console.log(add(1));    // (출력값) NaN
console.log(add(1, 2))  // (출력값) 3
console.log(add(1, 2, 3))   // (출력값) 3

 

arguments 객체는 다음과 같이 세 부분으로 구성됨 (__proto__ 프로퍼티는 제외)

  • 함수를 호출할 때 넘겨진 인자 (배열 형태) : 함수를 호출할 때 첫 번째 인자는 0번 인덱스, 두 번째 인자는 1번 인덱스, …
  • length 프로퍼티 : 호출할 때 넘겨진 인자의 개수
  • callee 프로퍼티 : 현재 실행 중인 함수의 참조값 (예제에서는 add() 함수)

arguments는 객체이지 배열이 아니다. 즉 length 프로퍼티가 있으므로 배열과 유사하게 동작하지만, 배열은 아니므로 배열 메서드를 사용할 경우 에러가 발생한다. (물론 유사 배열 객체에서 배열 메서드를 사용하는 방법이 있다.)


arguments 객체는 매개변수 개수가 정확하게 정해지지 않은 함수를 구현하거나, 전달된 인자의 개수에 따라 서로 다른 처리를 해줘야 하는 함수를 개발하는 데 유용하게 사용할 수 있다.


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

console.log(sum(1,2,3));        // (출력값) 6
console.log(sum(1,2,3,4,5,6,7,8,9));    // (출력값) 45

 

4.4.2 호출 패턴과 this 바인딩

자바스크립트에서는 함수를 호출할 때 기존 매개변수로 전달되는 인자값에 더해, 앞서 설명한 arguments 객체 및 this 인자가 함수 내부로 암묵적으로 전달된다.

특히, this 인자는 고급 자바스크립트 개발자로 거듭나려면 확실히 이해해야 하는 핵심 개념이다. this가 이해하기 어려운 이유는 자바스클비트의 여러 가지 함수가 호출되는 방식(호출 패턴)에 따라 this다른 객체를 참조하기 (this 바인딩) 때문이다.


4.4.2.1 객체의 메서드 호출할 때 this 바인딩

객체의 프로퍼티가 함수일 경우, 이 함수를 메서드라고 부른다. 이러한 메서드를 호출할 때, 메서드 내부 코드에서 사용된 this해당 메서드를 호출한 객체로 바인딩된다.


예제 4-23 메서드 호출 사용 시 this 바인딩

// myObject 객체 생성
var myObject =  {
    name: 'foo',
    sayName: function () {
        console.log(this.name);
    }
};

// otherObject 객체 생성
var otherObject = {
    name: 'bar'
};

// otherObject.sayName() 메서드
otherObject.sayName = myObject.sayName;

// sayName() 메서드 호출
myObject.sayName(); // foo
otherObject.sayName(); // bar

 

4.4.2.2 함수를 호출할 때 this 바인딩

자바스크립트에서는 함수를 호출하면 해당 함수 내부 코드에서 사용된 this는 전역 객체에 바인딩된다. 브라우저에서 자바스크립트를 실행하는 경우 전역 객체는 window 객체가 된다.


전역 객체란? (브라우저, Node.js)

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

Node.js와 같은 자바스크립트 언어를 통해 서버 프로그래밍을 할 수 있게끔 해 주는 자바스크립트 런타임 환경에서의 전역 객체는 global 객체. Node.js는 자바스크립트 개발자에게 브라우저 기반의 프로그래밍을 넘어 서버 기반 프로그래밍 영역까지 개발을 가능하게끔 해주는 플랫폼.


자바스크립트의 모든 전역 변수는 실제로는 이러한 전역 객체의 프로퍼티들이다.


예제 4-24 전역 객체와 전역 변수의 관계를 보여주는 예제 코드

var foo = "I'm foo";    // 전역 변수 선언

console.log(foo);   // (출력값) I'm foo
console.log(window.foo);    // (출력값) I'm foo

 

—> 전역 변수는 전역 객체 (window)의 프로퍼티로도 접근 가능


예제 4-24 함수를 호출할 때 this 바인딩을 보여주는 예제 코드

var test = 'This is test';
console.log(window.test);

// sayFoo() 함수
var sayFoo = function () {
    console.log(this.test); // sayFoo() 함수 호출 시 this는 전역 객체에 바인딩된다.
};

sayFoo();

 

이러한 함수 호출에서의 this 바인딩 특성은 내부 함수(inner function)를 호출했을 경우에도 그대로 적용되므로, 내부 함수에서 this를 이용할 때는 주의해야 한다.


예제 4-26 내부 함수의 this 바인딩 동작을 보여주는 예제 코드

// 전역 변수 value 정의
var value = 100;

// myObject 객체 생성
var myObject = {
    value: 1,
    func1: function () {
        this.value += 1;
        console.log('func1() called. this.value : ' + this.value);
        
        // func2() 내부 함수
        func2 = function () {
            this.value += 1;
            console.log('func2() called. this.value : ' + this.value);
            
            // func3() 내부 함수
            func3 = function () {
                this.value += 1;
                console.log('func3() called. this.value : ' + this.value);
            }
            
            func3();    // func3() 내부 함수 호출
        }
        
        func2();    // func2() 내부 함수 호출
    }
};
myObject.func1();   // func1() 메서드 호출

 

  • func1()myObject의 메서드. —> 메서드 코드 내에서 사용된 this는 자신을 호출한 객체 (myObject)
  • func2(), func3()this —> window

자바스크립트에서는 내부 함수 호출 패턴을 정의해 놓지 않는다.

—> 내부 함수도 결국 함수이므로 이를 호출할 때는 함수 호출로 취급된다.

—> 함수 호출 패턴 규칙에 따라 함수의 this는 전역 객체 (window)에 바인딩된다.


이를 극복하기 위해

부모 함수의 this를 내부 함수가 접근 가능한 다른 변수에 저장

하는 방법이 사용된다. 보통 관례상 this 값을 저장하는 변수의 이름을 that이라고 짓는다.


예제 4-27 내부 함수의 this 바인딩 문제를 해결한 예제 코드

// 내부 함수 this 바인딩

var vaule = 100;

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

myObject.func1();   // func1 메서드 호출

 

  • 내부 함수는 자신을 둘러싼 부모 함수인 func1()의 변수에 접근 가능 —> func2()func3()that변수를 통해 func1()this가 바인딩된 객체인 myObject에 접근 가능하게 된다.

자바스크립트에서는 이와 같은 this 바인딩의 한계를 극복하려고, this 바인딩을 명시적으로 할 수 있도록 callapply 메서드를 제공한다. (4.4.2.4절에서 자세히 설명) jQuery, underscore.js 등과 같은 자바스크립트 라이브러리들의 경우 bind라는 이름의 메서드를 통해, 사용자가 원하는 객체를 this에 바인딩할 수 있는 기능을 제곤. (7장에서 소개)


4.4.2.3 생성자 함수를 호출할 때 this 바인딩

자바스크립트 객체를 생성하는 방식은 크게 객체 리터럴 방식이나 생성자 함수를 이용하는 두 가지 방법 존재. 이번 절에서는 생성자 함수를 이용한 객체 생성 방법을 알아봄.


자바스크립트의 생성자 함수는 말 그대로 자바스크립트의 객체를 생성하는 역할.

하지만 C++이나 자바와 같은 객체지향 언어에서의 생성자 함수의 형식과는 다르게 그 형식이 정해져 있는 것이 아니라, 기존 함수에 new 연산자를 붙여서 호출하면 해당 함수는 생성자 함수로 동작 반대로 일반 함수에 new를 붙여 호출하면 원치 않는 생성자 함수처럼 동작할 수 있으니 주의. 따라서 대부분의 자바스크립트 스타일 가이드에서는 특정 함수가 생성자 함수로 정의되어 있음을 알리기 위해 함수 이름의 첫 문자를 대문자로 쓰기를 권하고 있다.


자바스크립트는 이러한 생성자 함수를 호출할 때, 생성자 함수 코드 내부에서 this는 앞서 알아본 메서드와 함수 호출 방식에서의 this 바인딩과는 다르게 동작.


생성자 함수가 동작하는 방식

new 연산자로 자바스크립트 함수를 생성자로 호출하면

  1. 빈 객체 생성 및 this 바인딩

: 생성자 함수 코드가 실행되기 전 빈 객체가 생성된다. 이 객체는 생성자 함수가 새로 생성하는 객체이며, 이 객체는 this로 바인딩된다. —> 이후 생성자 함수의 코드 내부에서 사용된

this는 이 빈 객체

를 가리킴.

하지만 여기서 생성된 객체는 엄밀히 말하면 빈 객체는 아니다. 자바스크립트의 모든 객체는 자신의 부모인 프로토타입 객체와 연결되어 있으며, 이를 통해 부모 객체의 프로퍼티나 메서드를 마치 자신의 것처럼 사용할 수 있기 때문이다. 이렇게 생성자 함수가 생성한 객체는 자신을 생성한 생성자 함수의 prototype 프로퍼티가 가리키는 객체를 자신의 프로토타입 객체로 설정한다. (자바스크립트의 규칙)

  1. this를 통한 프로퍼티 생성

: 함수 코드 내부에서 this를 사용하여 앞에서 생성된 빈 객체에 동적으로 프로퍼티나 메서드를 생성

  1. 생성된 객체 리턴

: 리턴문이 동작하는 방식은 경우에 따라 다르므로 주의! 가장 일반적인 경우로 특별한 리턴문이 없을 경우, this로 바인딩된 새로 생성한 객체가 리턴된다. 명시적으로 this를 리턴해도 결과는 같다. (주의 : 생성자 함수가 아닌 일반 함수를 호출할 때 리턴값이 명시되어 있지 않으면 undefined가 리턴됨) 하지만 리턴값이 새로 생성한 객체(this)가 아닌 다른 객체를 반환하는 경우는 생성자 함수를 호출했다고 하더라도 this가 아닌 해당 객체가 리턴됨.


예제 4-28 생성자 함수의 동작 방식

// Person() 생성자 함수
var Person = function (name) {
    // 함수 코드 실행 전
    this.name = name;
    // 함수 리턴
};

// foo 객체 생성
var foo = new Person('foo');
console.log(foo.name);  // (출력값) foo

 

  1. Person() 함수가 생성자로 호출되면, 함수 코드가 실행되기 전에 빈 객체가 생성된다. 여기서 생성된 빈 객체는 Person() 생성자 함수의 prototype 프로퍼티가 가리키는 객체(Person.prototype 객체)를 [[Prototype]] 링크로 연결해서 자신의 프로토타입으로 설정한다. 그리고 이렇게 생성된 객체는 생성자 함수 코드에서 사용되는 this로 바인딩된다.
  2. this가 가리키는 빈 객체에 name이라는 동적 프로퍼티를 생성했다.
  3. 리턴값이 특별히 없으므로 this로 바인딩한 객체가 생성자 함수의 리턴값으로 반환돼서, foo 변수에 저장된다.

객체 리터럴 방식과 생성자 함수를 통한 객체 생성 방식의 차이


예제 4-29 객체 생성 두 가지 방법(객체 리터럴 vs 생성자 함수)

// 객체 리터럴 방식으로 foo 객체 생성
var foo = {
    name: 'foo',
    age: 35,
    gender: 'man'
};
console.dir(foo);

// 생성자 함수
function Person(name, age, gender, position) {
    this.name = name;
    this.age = age;
    this.gender = gender;
}

// Person 생성자 함수를 이용해 bar 객체, baz 객체 생성
var bar = new Person('bar', 33, 'woman');
console.dir(bar);

var baz = new Person('baz', 25, 'woman');
console.dir(baz);

 

foo 객체와 같이 객체 리터럴 방식으로 생성된 객체는 같은 형태의 객체를 재생성할 수 없지만, Person() 생성자 함수를 사용해서 객체를 생성하면 생성자 함수를 호출할 때 다른 인자를 넘김으로써 같은 형태의 서로 다른 객체를 생성할 수 있다.


객체 리터럴 방식의 경우는 자신의 프로토타입 객체가 Object(Object.prototype)이고, 생성자 함수 방식의 경우는 Person(Person.prototype)으로 서로 다르다.

<— 자바스크립트 객체 생성 규칙 때문에 차이가 발생 : 자바스크립트 객체는 자신을 생성한 생성자 함수의 prototype 프로퍼티가 가리키는 객체를 자신의 프로토타입 객체로 설정한다. 객체 리터럴 방식에서는 객체 생성자 함수는 Object()이며, 생성자 함수 방식의 경우는 생성자 함수 자체, 예제에서는 Perton()이므로 두 가지 방식이 다른 프로토타입 객체가 있는 것. (더 자세한 내용은 4.5 프로토타입 체이닝에서)


생성자 함수를 new를 붙이지 않고 호출할 경우

자바스크립트에서는 일반 함수와 생성자 함수가 별도의 차이가 없다. new를 붙여서 함수를 호출하면 생성자 함수로 동작하는 것. —> 객체 생성을 목적으로 작성한 생성자 함수를 new 없이 호출하거나 일반 함수를 new를 붙여서 호출할 경우 코드에서 오류가 발생할 수 있다. 일반 함수 호출과 생성자 함수를 호출할 때 this 바인딩 방식이 다르기 때문! 일반 함수 호출의 경우는 thiswindow 전역 객체에 바인딩되는 반면, 생성자 함수 호출의 경우 this는 새로 생성되는 빈 객체에 바인딩된다.


예제 4-30 new를 붙이지 않고 생성자 함수 호출 시의 오류

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

var qux = Person('qux', 20, 'man');
console.log(qux);   // (출력값) undefined

console.log(window.name);   // (출력값) qux
console.log(window.age);    // (출력값) 20
console.log(window.gender); // (출력값) man

 

  • Person() 함수는 리턴값이 특별히 없다. 생성자 함수는 별도의 리턴값이 정해지 않은 경우에 새로 생성된 객체가 리턴되지만, 일반 함수를 호출할 때는 undefined가 리턴된다.
  • Person()new 없이 일반 함수 형태로 호출할 경우, this는 함수 호출이므로 전역 객체인 window 객체로 바인딩된다. —> 이 코드는 Person 객체를 생성해서 이를 qux 변수에 저장하려는 원래 의도와는 다르게 this가 바인딩된 window 객체에 동적으로 name, age, gender 프로퍼티가 생성된다.

강제로 인스턴스 생성하기

앞에서 설명한 위험성을 피하려고 널리 사용되는 패턴

function A(arg) {
    if (!(this instanceof A))
        return new A(arg);
    this.value = arg ? arg : 0;
}

var a = new A(100);
var b = A(10);

console.log(a.value);       // (출력값) 100
console.log(b.value);       // (출력값) 10
console.log(global.value);  // (출력값) undefined

 

함수 A가 호출될 때 this가 A의 인스턴스인지를 확인하는 분기문을 추가.

this가 A의 인스턴스가 아니라면, new로 호출된 것이 아님을 의미 —> 이 경우 new로 A를 호출하여 반환하도록

함. 이렇게 하면 var b = A(10);와 같이 사용자가 사용했다고 하더라도, 전역 객체에 접근하지 않고, 새 인스턴스가 생성되어 b에 반환됨.


cf) 어떤 코드에서는 앞과 같이 함수의 이름을 그대로 쓰지 않고 다음과 같이 표현식을 쓰곤 한다.

if (!(this instanceof arguments.callee))

 

arguments.callee가 곧 호출된 함수를 가리킨다. —> 특정 함수 이름과 상관없이 이 패턴을 공통으로 사용하는 모듈을 작성할 수 있게 된다!


이 패턴을 사용함으로써

  1. 함수 사용자가 함수 작성자의 의도와는 다르게 함수를 호출할 때에도 문제가 발생하지 않게 한다.
  2. 함수 작성자 역시 사용자가 new로 반환된 인스턴스를 사용하게 될 것을 확신하고 코드를 작성할 수 있다.

4.4.2.4 call과 apply 메서드를 이용한 명시적인 this 바인딩

자바스크립트는 내부적인 this 바인딩 이외에도 this를 특정 객체에 명시적으로 바인딩시키는 방법도 제공한다. apply()call() 메서드를 통해 가능! 이들은 모든 함수의 부모 객체인 Funciton.prototype 객체의 메서드 —> 모든 함수는 다음과 같은 형식으로 apply() 메서드를 호출하는 것이 가능.


function.apply(thisArg, argArray)

 

call() 메서드는 apply() 메서드와는 기능이 같고 단지 넘겨받는 인자의 형식만 다르다.


apply() 메서드를 호출하는 주체는 함수이고, apply() 메서드도 this를 특정 객체에 바인딩할 뿐 결국 본질적인 기능은 함수 호출이다.

예를 들어, Person()이라는 함수가 있고, Person.apply() 이렇게 호출한다면 이것의 기본적인 기능은 Person() 함수를 호출하는 것!


  • apply() 메서드의 첫 번째 인자 thisArg : apply() 메서드를 호출한 함수 내부에서 사용한 this에 바인딩할 객체를 가리킨다. 즉, 첫 번째 인자로 넘긴 객체가 this로 명시적으로 바인딩되는 것.
  • apply() 메서드의 두 번째 인자 argArray : 함수를 호출할 때 넘길 인자들의 배열. apply() 메서드의 기능도 결국 함수를 호출하는 것이기 때문에, 함수에 넘길 인자를 argArray 배열로 넘긴다.

—> apply() 메서드는 두 번째 인자인 argArray 배열을 자신을 호출한 함수의 인자로 사용하되, 이 함수 내부에서 사용된 this는 첫 번재 인자인 thisArg 객체로 바인딩해서 함수를 호출하는 기능.


예제 4-31 apply() 메서드를 이용한 명시적인 this 바인딩

// 생성자 함수
function Person(name, age, gender) {
    this.name = name;
    this.age = age;
    this.gender = gender;
}

// foo 빈 객체 생성
var foo = {};

// apply() 메서드 호출
Person.apply(foo, ['foo', 30, 'man']);
console.dir(foo);

 

call() 메서드는 apply()와 기능은 같지만, apply()의 두 번째 인자에서 배열 형태로 넘긴 것을 각각 하나의 인자로 넘긴다.


Person.call(foo, 'foo', 30, 'man');

 

이러한 apply()call() 메서드는 this를 원하는 값으로 명시적으로 매핑해서 특정 함수나 메서드를 호출할 수 있다는 장점. 이들의 대표적인 용도가 arguments 객체와 같은 유사 배열 객체에서 배열 메서드를 사용하는 경우.


예제 4-32 apply() 메서드를 활용한 arguments 객체의 배열 표준 메서드 slice() 활용 코드

function myFunction() {
    console.dir(arguments);

    // arguments.shift();  에러 발생

    // arguments 객체를 배열로 변환
    var args = Array.prototype.slice.apply(arguments);
    console.dir(args);
}

myFunction(1,2,3);

 

  • 배열에서는 shift() 메서드를 사용해 첫 번째 원소를 쉽게 삭제할 수 있지만, arguments 객체는 length 프로퍼티만을 가진 유사 객체 배열 —> 앞 코드에서 주석을 제거하고 arguments.shift()와 같이 표준 배열 메스드를 호출하면 에러가 발생하며 프로그램 종료
  • apply() 메서드로 arguments 객체에서 마치 배열 메서드가 있는 것처럼 처리 가능.
Array.prototype.slice.apply(arguments)
—> ‘Array.prototype.slice() 메서드를 호출해라. 이때 this는 arguments 객체로 바인딩해라.’ 즉, arguments 객체가 Array.prototype.slice() 메서드를 마치 자신의 메서드인 양 arguments.slice()와 같은 형태로 메서드 호출하라는 것.
  • slice() 메서드는 이 메서드를 호출한 배열의 start 인덱스에서 end-1 인덱스까지 복사한 배열을 리턴. end 인자를 지정하지 않을 경우 기본값은 배열의 length 값. slice() 메서드에 아무 인자도 넘기지 않을 경우 전체 배열이 copy된다.

예제 4-23 slice() 메서드 사용 예제

var arrA = [1, 2, 3];
var arrB = arrA.slice(0)    // [1, 2, 3]
var arrC = arrA.slice();    // [1, 2, 3]
var arrD = arrA.slice(1);   // [2, 3]
var arrE = arrA.slice(1, 2);    //[2]

 

  • argumentsargs__proto__ 프로퍼티는 다르다. 즉, arguments는 객체이므로 프로토타입이 Object.prototype인 반면, args는 배열이므로 Array.prototype이 프로토타입이다.

4.4.3 함수 리턴

자바스크립트 함수는 항상 리턴값을 반환

특히, return 문을 사용하지 않았더라도 다음의 규칙으로 항상 리턴값을 전달


4.4.3.1 규칙 1) 일반 함수나 메서드는 리턴값을 지정하지 않을 경우, undefined 값이 리턴된다


예제 4-34 ruturn 문 없는 일반 함수의 리턴값 확인

// noReturnFunc() 함수
var noReturnFunc = function () {
    console.log('This function has no return statement.');
};

var result = noReturnFunc();
console.log(result);

 

4.4.3.2 규칙 2) 생성자 함수에서 리턴값을 지정하지 않을 경우 생성된 객체가 리턴된다

생성자 함수에서 별도의 리턴값을 지정하지 않을 경우 this로 바인딩된 새로 생성된 객체가 리턴된다. —> 생성자 함수에서는 일반적으로 리턴값을 지정하지 않는다.


생성자 함수의 경우에는 리턴값을 처리하는 몇 가지 예외 상황이 있다.


  • 생성자 함수에서 this로 바인딩되는 생성된 객체가 아닌 다른 객체를 리턴한다면?

예제 4-35 생성자 함수에서 명시적으로 객체를 리턴했을 경우

// Persion() 생성자 함수
function Person(name, age, gender) {
    this.name = name;
    this.age = age;
    this.gender = gender;

    // 명시적으로 다른 객체 반환
    return {name:'bar', age:20, gender:'woman'};
}

var foo = new Person('foo', 30, 'man');
console.dir(foo);
—> 생성자 함수의 리턴값을 새로 생성한 객체가 아니라, 객체 리터럴 방식을 특정 객체로 지정한 경우 new 연산자로 Person() 생성자 함수를 호출해서 새로운 객체를 생성하더라도, 리턴값에서 명시적으로 넘긴 객체나 배열이 리턴된다.
  • 생성자 함수의 리턴값으로 넘긴 값이 객체가 아닌 불린, 숫자, 문자열의 경우는 이러한 리턴값을 무시하고 this로 바인딩된 객체가 리턴된다.

예제 4-36 생성자 함수에서 명시적으로 기본 타입(불린, 숫자, 문자열) 값을 리턴했을 경우

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

var foo = new Person('foo', 30, 'man');
console.log(foo);

 

#책/인사이드자바스크립트