JavaScript/기초

javascript 기초 1 - 함수(3)

고기고기물고기 2022. 5. 11. 18:03

○ 함수 호출과 this

 @ arguments 객체

   - C와 같은 엄격한 언어와 달리, 자바스크립트에서는 함수를 호출할 때 함수 형식에 맞춰 인자를 넘기지 않더라도 에       러가 발생하지 않는다.

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

 @ 호출 패턴과 this 바인딩

  - 함수를 호출할 때 arguments 객체 및 this 인자가 함수 내부로 암묵적으로 전달된다

  - this가 이해하기 어려운 이유는 자바스크립트의 여러 가지 함수가 호출되는 방식에 따라 this가 다른 객체를 참조하기 때문이다

 

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

     - 메서드 내부 코드에서 사용된 this는 해당 메서드를 호출한 객체로 바인딩된다.

var myObject = {
    name : 'foo',
    sayName: function () {
        console.log(this.name);
    }
};

var otherObject = {
    name : 'bar'
};

otherObject.sayName = myObject.sayName;

myObject.sayName(); //foo
otherObject.sayName(); //bar

  2. 함수를 호출할때 this 바인딩

     - 함수를 호출하면 함수 내부 코드에서 사용된 this는 전역객체에 바인딩 된다.

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

var number = "I'm foo";

console.log(number); // I'm foo
console.log(window.number); // I'm foo

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

var value = 100;

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();
        }
        func2();
    }
}
myObject.func1();

예상 출력결과 :

func1() called. this.value : 2
func2() called. this.value : 3
func3() called. this.value : 4

실제 출력결과 :

func1() called. this.value : 2
func2() called. this.value : 101
func3() called. this.value : 102

     - 이렇게 실행결과가 예측했던 것과 다르게 출력된 이유는 자바스크립트에서는 내부 함수 호출 패턴을 정의해 놓지         않기 때문이다.

 

var value = 100;

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

        // func2() 내부함수
        func2 = function () {
            that.value += 1;
            console.log('func2() called. this.value : ' + that.value);
            // func3() 내부함수
            func3 = function() {
                that.value +=1;
                console.log('func3() called. this.value : ' + that.value);
            }
            func3();
        }
        func2();
    }
}
myObject.func1();

     - func1의 that이라는 새로운 변수에 this를 대입해 놓고. that.value를 증가시켜주면 된다. 이는 내부함수의 스코프           체이닝을 이용한 방법이다.

 

 

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

    - 기존 함수에 new 연산자를 붙여서 호출하면 해당 함수는 생성자 함수로 작동한다.

    - 빈 객체 생성 및 this 바인딩

       생성자 함수를 호출하면 일단 빈 객체가 생성되고 this가 그 객체를 바인딩한다.

    - this를 통한 프로퍼티 생성

       바인딩 된 빈 객체에 동적으로 프로퍼티 또는 매서드를 생성한다.

    - 생성된 객체 리턴

       생성된 빈 객체를 리턴 하거나 지정된 리턴이 없더라도 this와 바인딩된 객체를 리턴한다.

 

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

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

var foo = new person('foo');
console.log(foo.name); //foo

 

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

//객체 리터럴 방식

var foo = {
    name : 'foo',
    age : '35',
    gender : 'man'
};

console.dir(foo);  // 프로토타입 객체가 object

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

//생성자 함수를 이용해 두 객체 생성

var bar = new Person('bar', 33, 'woman');
console.dir(bar.name); // 프로토타입 객체가 person

var baz = new Person('baz', 25, 'woman');
console.dir(baz.name); // 프로토타입 객체가 person

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

  - 객체 리터럴 방식과 생성자 함수를 통한 객체 생성 방식의 차이 예제를 이어서

var qus = person('qux', 20, 'man');
console.log(qux); // undefined

console.log(qux); // undefined
console.log(qux); // 20
console.log(qux); // man

  - person 함수는 리턴값이 특별히 없다 생성자 함수는 별도의 리턴값이 정해져 있지 않은경우에 새로 생성된 객체가 리턴되지만, 일반 함수를 호출할때는 undefined가 리턴된다. 따라서 undefined 값이 출력된 것이다.

 

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

 

ex) apply() 메서드를 이용한 명시적인 this 바인딩

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

var foo = {}; //빈 객체

Person.apply(foo, ['foo', 30, 'man']);
console.dir(foo);

  - this 객체를 foo 객체에 명시적으로 바인딩

 

ex) apply() 메서드를 활용한 argements 객체의 배열 표준 메서드 slice() 활용 코드


function myFunction() {
    console.log(arguments); //1

    var args = Array.prototype.slice.apply(arguments);
    console.dir(args);
}

myFunction(1, 2, 3);

    - apply() 메서드로 arguments 객체에서 마치 배열 메서드가 있는 것처럼 처리할 수 있다. 이를 가능하게 하는 것이 바로 다음 코드다.