반응형

switch 조건문의 기본적인 형태

switch(비교할 값) {
    case '값' :
        내용
    break;

    case '값' :
        내용
    break;

    default :
        내용
    break;
}

break키워드 : break키워드는 switch조건문이나 반복문등을 빠져나가려고 사용하는 키워드입니다.

코드를 읽다가 break키워드를 만나게 되면 조건문이나 반복문등을 완전히 빠져 나가게 됩니다.

 

switch() : switch조건문의 괄호 안에는 비교할 값을 입력해줍니다. 이때 입력한 값을 기준으로 특정 코드를 실행해줍니다.

만약에 case키워드 옆에 표현식이 같으면 case키워드 바로 다음에 오는 내용을 실행하게 됩니다.

 

switch문 예

var contents = 'HelloWorld';

switch(contents) {
    case 'HelloWorld' :
        console.log('비교값과 같으면 실행될 부분'); // 실행
    break;

    case 'Hello' :
        console.log('비교값과 같으면 실행될 부분'); // 실행되지 않음
    break;

    default :
        console.log('위 내용들이 실행되지 않았을 때 실행될 부분'); // 실행되지 않음
    break;
}

 

switch 조건문

Switch 조건문

 

switch조건문은 대부분 특정 값의 조건을 비교할 때 사용됩니다.

 

반응형
반응형

if조건문 형태

// 불 표현식 | 내용
if(불 표현식) {
    내용
}

 

조건식

 

if 조건문

if(300 < 100) {
    alert('300 < 100 => true');
}

alert('종료');

300은 100보다 크기 때문에 내부 alert()은 작동하지 않는다.

 

시간을 사용한 조건 예

var date = new Date();
var hour = date.getHours();

if(hour < 12) {
    alert('오전입니다.');
}

if(hour >= 12) {
    alert('오후입니다.');
}

date.getHours()메서드로 현재 시각을 가져와서 오전인지 오후인지 알아보는 조건문

 

if else 조건문

if(불 표현식) {
    내용
} else {
    내용
}

if else 조건식

 

시간을 사용한 조건 예 ( if else 조건식으로 구현했을 때 )

var date = new Date();
var hour = date.getHours();

if(hour < 12) {
    alert('오전입니다.');
} else {
    alert('오후입니다.');
}

if else 조건문으로 구현하면 눈으로 볼때도 하나의 내용으로 보이고, 조건 하나를 처리하는 횟수가 줄어들기 때문에 성능향상에도 미약하지만 도움이 된다.

 

중첩 조건문

if(불 표현식) {
    if(불 표현식) {
        내용
    } else {
        내용
    }
} else {
    if(불 표현식) {
        내용
    } else {
        내용
    }
}

조건문 안에 조건문을 중첩해 사용하면 중첩 조건문이라고 한다.

 

중첩 조건문 예

var date = new Date();
var hour = date.getHours();

if(hour < 12) {
    alert('아침시간');
} else {
    if(hour < 18) {
        alert('점심시간');
    } else {
        alert('저녁시간');
    }
}

 

if else if 조건문

if(불 표현식) {
    내용
} else if(불 표현식) {
    내용
} else {
    내용
}

 

if else if 조건문 예

var date = new Date();
var hour = date.getHours();

if(hour < 12) {
    alert('아침시간');
} else if(hour < 18) {
    alert('점심시간');
} else {
    alert('저녁시간');
}

if else 조건식을 사용했을 때보다 간결해 진것을 알 수 있다.

 

반응형
반응형

모듈 패턴의 기본 패턴

(function(window) {
    var myLibrary = {
        helloWorld: function() {
            alert("Hello World");
        },
        hello: {
            World: function() {
                alert("Hello Module");
            }
        }
    };

    window.myLibrary = myLibrary;
}(window));

myLibrary.helloWorld(); // Hello World
myLibrary.hello.World(); // Hello Module

최초의 function은 즉시 호출 함수가 되어 내부적으로 바로 실행되며, 이 함수의 인자로 window를 넘겨준다. 이렇게 window를 넘기면 앞으로 이 모듈 안에서 window라는 변수값은 글로벌 변수로서 계속 사용할 수 있다.

 

글로벌 변수에 모듈 패턴에 할당하는 형태

var myLibrary = (function(window) {
    var myLibrary = {
        helloWorld: function() {
            alert("Hello World");
        },
        hello: {
            World: function() {
                alert("Hello Module");
            }
        }
    };
    return myLibrary;
}(window));

myLibrary.helloWorld(); // Hello World
myLibrary.hello.World(); // Hello Module

 

글로벌 변수에 객체 표현식으로 모듈 패턴을 할당하는 형태

var myLibrary = (function(window) {
    return {
        helloWorld: function() {
            alert("Hello World");
        },
        hello: {
            World: function() {
                alert("Hello Module");
            }
        }
    };
}(window));

myLibrary.helloWorld(); // Hello World
myLibrary.hello.World(); // Hello Module

이렇게 다양하게 모듈을 생성하고 응용할 수 있다.

 

반응형
반응형

Object.create함수의 구현 방법을 살펴보면 Object.create와 별도로 객체를 초기화하고 있는 것을 볼 수 있다.

이러한 과정을 하나의 함수로 묶어서 객체별로 간단한 상속 함수를 만들 수도 있지만, 표준의 Object.create함수는 2번째 인자를 선택적으로 받아서 객체를 초기화하도록 되어 있다.

 

Object.create함수로 값을 초기화하는 예

function Person(name) {
    this.name = name;
}
Person.prototype = {
    yell: function() {
        alert("my name is " + this.name);
    }
};

var shiro = Object.create(Person.prototype, {
    name: {
        value: "Shrio"
    }
});
shiro.yell(); // Shiro

shiro.name = "Jun";
shiro.yell(); // Shiro

이렇게 Object.create함수를 통해서 값만 설정하면 읽기 전용 속성이 되어 값을 수정할 수 없게 된다. 따라서 값을 수정할 수 있게 하려면 해당 속성에 대하여 추가로 설정해주어야 한다.

 

Object.create함수로 수정 가능한 속성 초기화 예

function Person(name) {
    this.name = name;
}
Person.prototype = {
    yell: function() {
        alert("my name is " + this.name);
    }
};

var shiro = Object.create(Person.prototype, {
    name: {
        value: "Shrio",
        configurable: true,
        enumerable: true,
        writable: true
    }
});
shiro.yell(); // Shiro

shiro.name = "Jun";
shiro.yell(); // Jun

 

Object.defineProperty설정 파라미터

속성 내용 기본값
value 설정할 속성의 값 undefined
configurable 속성을 지우거나 value속성 이외의 설정 속성을 바꿀지 여부 false
enumerable for-in루프에서 해당 속성도 참조할지 여부 false
writable 속성의 값을 설정 가능 여부 false
get 속성을 참조하게 되면 참조용으로 호출할 함수 undefined
set 속성을 설정하게 되면 설정용으로 호출할 함수 undefined

 

접근자 활용 예

function Person(name) {
    this.name = name;
}
Person.prototype = {
    yell: function() {
        alert("my name is " + this.name);
    }
};

var shiro = Object.create(Person.prototype, {
    name: {
        value: "Shrio",
        configurable: true,
        enumerable: true,
        writable: true
    }
});
shiro.yell(); // Shiro

shiro.name = "Jun";
shiro.yell(); // Jun

Object.defineProperties(shiro, {
    firstName: {
        value: "Ko",
        writable: true
    },
    lastName: {
        value: "Shiro",
        writable: true
    },
    fullName: {
        get: function() {
            return this.firstName + " " + this.lastName;
        },
        set: function(value) {
            var res = value.split(" ");
            if(res.length > 1) {
                this.firstName = res[0];
                this.lastName = res[1];
            } else {
                alert("Wrong format");
            }
        }
    }
});

console.log(shiro.fullName); // Ko Shiro
shiro.fullName = "Hello World";
console.log(shiro.firstName); // Hello
console.log(shiro.lastName); // World

이렇게 다른 속성들을 조합하여 하나의 새로운 속성을 만들 때와 반대로 설정을 다른 속성으로 투영하고자 할 때 get과 set속성을 사용하면 편리하게 이용할 수 있다. 이처럼 객체를 생성할 때 Object.create를 사용하면 조금 더 다양하게 변수를 특징적으로 설정할 수 있고 속성 간의 관계도 편리하게 설계할 수 있다.

반응형
반응형

Object.create함수

자바스크립트 개발자들은 내부에서 생성자로 객체를 생성하면서 연결이 깨지는 것을 원하지 않았다. 그래서 만들어낸 것이 Object.create함수이다.

내부적인 구조의 불완전성 이외에도 new라는 키워드 자체가 '자바스크립트답지 않다'는 의견이 많이 반영되면서 객체를 상속하여 생성할 수 있는 함수를 별도로 제공하게 되었다.

 

더글라스 크락포드(Douglas Crockford)가 주장했던 Object.create함수의 형태

초기 Object.create함수

Object.create = function(o) {
    function F() {}
    F.prototype = o;
    return new F();
}

함수 안을 살펴보면 내부 함수 F는 아무런 초기화도 하지 않은 기본 함수이다. 그리고 F의 프로토타입만 인자로 받는 객체로 수정하여 새로운 F객체를 생성하여 반환한다.

여기서 주의점은 Object.create함수의 인자는 생성자인 함수가 아니라 프로토타입으로 설정할 객체 또는 인스턴스라는 점이다. 따라서 위의 함수를 토대로 앞서 나온 상속의 예를 간단하게 구현하면 아래와 같다.

 

Object.create함수를 이용한 상속 예

function Person(name) {
    this.name = name;
}
Person.prototype = {
    yell: function() {
        alert("my name is " + this.name);
    }
};

var shiro = Object.create(Person.prototype);
shiro.name = "Shrio";
shiro.yell(); // my name is Shrio

여기서 주의점은 Object.create함수의 인자로 넘겨준 것이 Person생성자가 아니라, 프로토타입이라는 점이다. 이렇게 함수가 아닌 객체를 넘겨주는 것은 Object.create의 내부적인 형태를 보면 쉽게 이해할 수 있다. Object.create함수 안에서는 인자로 넘어온 o를 이용해서 그대로 임의의 기본 함수 F의 프로토타입으로 설정해주고 있다.

 

그리고 new키워드와 생성자를 이용하여 객체를 생성하던 것과 비교해보면 shiro변수에 직접 shiro.name과 같이 속성을 부여하고 있는 것을 볼 수 있다. 이러한 것이 어떻게 보면 개발자 관점에서 작업을 별도로 해야 하는 불편함이 있을 수도 있지만, 전체적인 코드의 관점에서는 조금 더 직관적으로 보일 수 있기도 하다. 또한, 이러한 초기화 설정은 Object.create함수의 두 번째 인자를 통해 할 수 있도록 표준에서 정의하고 있기도 하다.

 

이렇게 Object.create함수를 통해서 객체를 생성하면, 개발자가 new키워드를 사용하지 않고 함수 호출로 객체가 생성되는 것을 확인할 수 있다. new키워드를 사용할 때와는 달리 전체적으로 코드에 생성자의 개념이 약해지고 객체의 인스턴스와 인스턴스 간의 상속을 강조하는 것이 Object.create함수의 특징이라고 볼 수 있다.

반응형
반응형

초창기 자바스크립트 상속 구현 방법

function Person() {
    this.name = 'shiro';
    this.job = 'none';

    this.hello = function() {
        alert('Hello, my name is ' + this.name);
    };
}

function Shiro() {
    var obj = new Person();
    obj.name = 'shiro';
    obj.job = 'Programmer';
    return obj;
}

var shiro = new Shiro();
shiro.hello();

이처럼 초창기 자바스크립트에서 ECMAScript표준의 처리 단계를 우회하여 기본적으로 반환되는 this대신 새로운 obj를 반환하는 방식으로 상속을 구현하였다. 이런 방법은 나름 직관적으로 보이긴 하지만, 치명적 단점이 있다. 바로 shiro변수가 Shiro의 인스턴스가 아닌 Person의 인스턴스로만 인식한다는 점이다.

 

상속 구현 후 객체 유형 인식문제

console.log(shiro instanceof Shiro); // false
console.log(shiro instanceof Person); // true

일반적으로 자바스크립트에서 instanceof를 사용하는 것이 흔한 일은 아니라 불편함을 느끼지는 못할 수도 있지만, 객체지향을 구현하는 정석이 아닌 우회하는 느낌이 강하다. 왜냐하면 new Shiro()로 객체를 생성하였는데, Shiro의 인스턴스로 인식 못하는 것은 객체지향의 관점에서 매우 치명적인 단점이 될 수 있다.

 

따라서 이후 자바스크립트는 function에 기본으로 들어 있는 프로토타입 속성을 새로운 객체로 설정하여 상속하는 방법을 채택하였다. 이 방법은 앞에서 설명한 프로토타입을 새로운 객체로 선언하듯, 상속하고자 하는 객체를 하위 객체의 프로토타입 속성으로 설정하면 된다.

 

객체로 프로토타입을 수정한 자바스크립트 상속 구현

var person = {
    name: 'new',
    hello: function() {
        alert('hello, my name is ' + this.name);
    }
};

function Shiro() {
    this.name = 'Shiro';
}

Shiro.prototype = person;
var shiro = new Shiro();

shiro.hello(); // hello my name is Shiro
person.hello(); // hello my name is new
console.log(shiro instanceof Shiro); // true

코드를 보면 person변수를 객체 표혆식으로 정의하여 객체로 생성하고 있다. 그리고 Shiro()함수로 생성된 shiro객체가 person의 함수를 상속하고 있다.

 

하지만 이때 instanceof Shiro는 정상으로 true가 나오지만, shiro변수가 person변수를 상속했다는 것을 shiro instanceof person과 같은 코드로 확인 할 수 없다. 따라서 프로토타입을 설정할 때 new로 새로운 객체를 만들어서 Shiro.prototype으로 설정하는 방법으로 이러한 문제를 해결하고자 하였다.

 

프로토타입을 이용한 자바스크립트 상속 구현 방법

function Person() {
    this.name = 'new';
    this.hello = function() {
        alert('hello, my name is ' + this.name);
    };
}

function Shiro() {
    this.name = 'Shiro';
}

Shiro.prototype = new Person();

var shiro = new Shiro();

shiro.hello(); // hello, my name is Shiro

console.log(shiro instanceof Shiro); // true
console.log(shiro instanceof Person); // true

이처럼 Person이라는 새로운 생성자를 선언하여 Shiro.prototype에 new Person()으로 객체를 생성하여 선언하면, 일반적인 객체지향을 사용하듯이 shiro instanceof Shiro와 shiro instanceof Person모두 true가 된다. 이는 바로 앞의 상속 방법들과 비교하여 객체지향적인 개발 방법론을 선호하는 개발자들이 만족할만한 결과일 것이다. 

반응형
반응형

프로토타입 체인 ( Prototype Chain )

자바스크립트에서 모든 객체는 프로토타입이라는 다른 객체( or null )를 가리키는 내부링크를 가지고 있다.

한 객체의 프로토타입 또한 프로토타입을 가지고 있고, 이것이 반복되다 null을 프로토타입으로 가지는 객체에서 끝난다. 이와 같은 객체들의 연쇄를 '프로토타입 체인'이라고 부른다.

 

프로토타입 체인을 통한 속성 공유 예

function Car() {
    this.wheel = 4;
    this.beep = "BEEP!";
};

Car.prototype.go = function() {
    alert(this.beep);
};

function Truck() {
    this.wheel = 6;
    this.beep = "HONK!";
};

Truck.prototype = new Car();

function SUV() {
    this.beep = "WANK!";
};

SUV.prototype = new Car();

var truck = new Truck(), suv = new SUV();

console.log(truck.wheel); // 6
console.log(suv.wheel); // 4
console.log(truck.beep); // "HONK!
console.log(suv.beep); // WANK!
truck.go(); // HONK!
suv.go(); // WANK!

Truck()rhk SUV()함수의 각 프로토타입을 new Car()로 새로운 객체들을 생성하여 설정한 뒤, truck.go()로 go속성 함수를 참조하면 다음과 같은 순서로 탐색한다.

  1. truck객체에 go속성이 있는지 검사.
  2. Truck.prototype에 go속성이 있는지 검사. ( new Car() )
  3. new Car()에 go 속성이 없으면, new Car()로 생성된 객체의 프로토타입인 Car.prototype에 go속성이 있는지 검사.
  4. Car.prototype.go속성을 참조.

즉, 객체의 속성에 접근할 때 객체와 프로토타입을 재귀로 검사하는 단계를 거쳐 속성을 참조한다. 

 


 

위처럼 속성이 프로토타입을 따라서 참조하게 되면 다시 재조명해야 할 함수가 'hasOwnProperty()함수'이다

이 함수를 사용하면 접근하려는 속성이 현재 객체에 포함된 것인지 아닌지 구분할 수 있다.

외부에서는 같더라도 해당 속성이 객체 자체의 속성인지 프로토타입 체인에 있는 속성인지 구분할 수 있다.

 

자바스크립트에서 hasWonProperty()함수를 유용하게 사용할 수 있는 상황은 속성 전체를 탐색하며 루프를 도는 for-in을 사용하는 예이다.

 

객체의 모든 속성을 출력하는 예

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

Person.prototype.getName = function() {
    return this.name;
};
Person.prototype.getBlog = function() {
    return this.blog;
};

var shiro = new Person("shiro", "shiro21.tistory.com"), prop;

for(prop in shiro) {
    console.log(`shiro[${prop}] =  ${shiro[prop]}`);
}

위 코드는 Person()함수의 프로토타입에 2가지 함수를 추가해 shiro라는 객체를 생성한다. 그리고 shiro안에 있는 shiro.name과 shiro.blog속성을 출력하고자 for-in으로 shiro에 있는 속성들의 키와 값을 출력하고 있다.

결과 값

의도는 for-in을 사용하여 shiro의 속성들만 출력하고자 했다.그런데 shiro의 속성들인 shiro.name과 shiro.blog만 출력하는 것이 아니라 프로토타입에 있는 getName과 getBlog까지 모두 출력되었다.

 

이런 현상을 방지하기 위해 객체 자체의 속성인지 구분하는 hasOwnProperty()함수를 사용하면 프로토타입에서 가져오는 속성들은 걸러낼 수 있다.

 

객체의 직속 속성만 출력하는 예

for(prop in shiro) {
    if(shiro.hasOwnProperty(prop)) {
        console.log(`shiro[${prop}] =  ${shiro[prop]}`);
    }
}

결과 값

결과를 보면 의도대로 shiro객체 자체의 속성들만 출력되는 것을 확인할 수 있다.

이처럼 특정 객체의 속성에만 접근하고 싶을 때 hasOwnProperty()함수를 이용하면 좋다.

 

JSLint에서도 for-in을 사용할 때 이처럼 hasOwnProperty()함수로 객체의 속성인지를 점검해 줄것을 권장하고 있다.

 

반응형
반응형
stranger.gender = "female";
console.log(stranger.gender); // female
console.log(shiro.gender); // male
console.log(Person.prototype.gender) // male

이전 'prototype에 정의된 변수를 수정하는 예'에서 구조를 보면 prototype에서 참조하던 gender값이 바뀌는게 아니라, stranger객체에 gender속성이 추가되어 저장되는 것이다. 따라서 stranger에서 gender를 조회하면 'female'을 출력한다. 그리고 'Person.prototype.gender'에 gender값은 그대로 'male'값을 그대로 유지하므로 shiro에서는 그대로 prototype에 있는 gender를 참조하여 'male'을 출력한다.

 

만약 모든 Person객체에 있는 gender를 공통으로 static변수인 것처럼 바꾸고 싶다면 prototype에 있는 gender를 바꿔주면 된다.

function Person1() {};
Person1.prototype.gender = "male";

var shiro1 = new Person1(),
    stranger1 = new Person1();

console.log(shiro1.gender); // male
console.log(stranger1.gender); // male

Person1.prototype.gender = "female";

console.log(shiro1.gender); // female
console.log(stranger1.gender); // female

 

반응형
반응형

프로토타입을 사용하는 예

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

Person.prototype.getName = function() {
    return this.name;
};
Person.prototype.getBlog = function() {
    return this.blog;
};

var shiro = new Person("shiro", "shiro21.tistory.com");
var stranger = new Person("stranger", "google.com");

console.log(shiro.getName()); // shiro
console.log(shiro.getBlog()); // shiro21.tistory.com
console.log(stranger.getName()); // stranger
console.log(stranger.getBlog()); // google.com

Person.prototype 코드부분은 constructor.prototype코드로 접근할 수 있다.

Person이라는 생성자의 prototype속성을 설정하고 있는 것이다.

이후 새로 생성된 shiro와 stranger객체는 내부적으로 이 prototype객체를 참고하여 prototype객체가 가지고 있는 getName()과 getBlog()함수를 사용할 수 있다.

이는 '생성자를 통해서 생성한 객체들이 prototype을 공유한다'라고 생각하면 된다.

 

객체 생성 후 prototype의 수정 예

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

Person.prototype.getName = function() {
    return this.name;
};
Person.prototype.getBlog = function() {
    return this.blog;
};

var shiro = new Person("shiro", "shiro21.tistory.com");
var stranger = new Person("stranger", "google.com");


Person.prototype.introduce = function() {
    console.log("Hi!, my name is " + this.name + ", plase visit my blog " + this.blog);
};

shiro.introduce(); // Hi!, my name is shiro, plase visit my blog shiro21.tistory.com

이렇게 이미 생성자를 통해 생성된 객체라도 나중에 생성자의 프로토타입에 새로운 속성을 추가할 수 있고, 이렇게 추가된 속성 또한 모든 객체가 공유한다. 

 

이미 정의된 prototype의 속성 수정 예

Person.prototype.introduce = function() {
    console.log("Hello, " + this.name + " ! ! !");
};
shiro.introduce(); // Hello, shiro ! ! !

기존에 선언해 두었던 속성을 다시 수정할 수 있다.

 

prototype에 변수 추가 예

Person.prototype.gender = "male";

console.log(shiro.gender); // male
console.log(stranger.gender); // male

프로토타입에 함수가 아닌 변수도 추가하여 공유가 가능하다.

 

prototype에 정의된 변수를 수정하는 예

stranger.gender = "female";
console.log(stranger.gender); // female
console.log(shiro.gender); // male
console.log(Person.prototype.gender) // male

위 코드를 실행하면 stranger객체의 gender값은 female로 바뀌었지만, shiro객체의 gender값은 여전히 male을 출력한다. 그런데 특이한 점은 stranger.gender였던 Person.prototype.gender값이 female로 바뀌지 않고 여전히 male로 유지되고 있다는 점이다.

 

반응형
반응형

Prototype이란 ?

프로토타입은 사전적 의미로 '원형'이다. 이 말을 그대로 자바스크립트에 투영해서 무엇의 원형을 나타내는지 생각하면 된다.

 

Javascript에서의 객체 생성

자바스크립트가 채택하고 있는 자바의 몇 가지 문법 중 대표적인 것은 new키워드이다. new키워드는 ECMAScript6 이전에 class키워드가 없었던 자바스크립트 문법에는 적합하지 않아서, 자바와 조금 다른 방식으로 채택하고있다. 자바에서는 class를 정의하지만, 자바스크립트에서는 function을 정의한다. 

 

Function을 통한 new키워드 활용

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

var shiro = new Person("shiro21", "shiro21.tistory.com");
alert(shiro.name);

 

위 코드를 객체지향 관점에서 봤을때, 자바스크립트에서 function은 자바의 class와 생성자를 합쳐놓은 개념이다.

객체를 생성할 때 function을 사용하는 방식은 다른 언어와 많은 차이가 있다. 따라서 ECMAScript6에서는 다른 언어와의 이질감을 줄이고, 객체지향을 조금이라도 더 지원하기 위해 class키워드를 새로 만들기도 했다.

 

class를 이용한 new키워드 활용

class Person {
    constructor(name, blog) {
        this.name = name;
        this.blog = blog;
    }
}

var shiro = new Person("shiro21", "shiro21.tistory.com");
alert(shiro.name);

class키워드를 이용하면 자바 등의 다른 객체지향 언어와 유사하게 클래스를 정의할 수 있다. 그런데 class키워드를 사용하면 내부적으로 특수한 function으로 정의한다는 점이다. 

아래를보면 class Person의 내부 정의를 function Person정의와 다르게 하고 있는 것을 확인할 수 있다.

class키워드가 function과 다른 점은 함수처럼 바로 실행하면 에러가 발생한다는 점이다. 그리고 함수 정의와는 다르게 현재 스코프에 진입했을 때 바로 사용할 수 있는 것이 아니라, 해당 class키워드로 클래스를 선언하는 소스가 실행되고 난 이후에 객체를 생성할 수 있다.

 

this에 대하여

앞 코드에서 function을 이용한 new키워드를 보면 생성자 함수 안에 this를 통해 객체를 초기화하고 있는 것을 확인할 수 있다. 일반적인 객체지향 프로그래밍 언어의 관점에서 보면 당연한 표현이지만, 자바스크립트에서의 this는 조금 다르게 동작하는 경우가 많다.

 

함수를 호출하는 방법

  1. 일반 함수로의 호출
  2. 멤버함수로의 호출
  3. call()함수를 이용한 호출
  4. apply()함수를 이용한 호출

 

일반적인 함수 호출 예

function say(something) {
    alert(something);
}

say("Hello World");

 

멤버함수 호출 예 :: 객체의 속성으로 함수를 호출 ( 함수가 객체의 멤버변수로 설정되었을때 호출하는 방법 )

    var shiro = {
        say: function(member) {
            alert(member);
        }
    };

    shiro.say("shiro");

 

call()과 apply()를 이용한 함수 호출 예 :: function객체의 기본 함수이므로 앞의 일반 함수를 호출 할 때 동일하게 호출

function say(something) {
    alert(something);
}

say.call(undefined, "Hello World");
say.apply(undefined, ["Hello World !!"]);

call()과 apply()함수의 차이는 함수로 넘겨줄 인자를 따로따로 넘겨주느냐, 배열로 넘겨주느냐의 차이만 있고 나머지는 크게 다르지 않다.

 

함수 호출 방법에 따른 this의 변화

    function whatsThis() {
        return this.toString();
    }

    var shiro = {
        what: whatsThis,
        toString: function() {
            return "[object shiro]";
        }
    };

    console.log(whatsThis());
    console.log(shiro.what());
    console.log(whatsThis.call());
    console.log(whatsThis.apply(shiro));

    console.log(shiro.what.call(undefined));
    console.log(shiro.what.call(shiro));

 

아래는 각 호출 방법에 따른 결과이다.

 

  1. 일반함수: this = window
  2. 멤버함수: this = shiro
  3. call, 인자없음: this = window
  4. apply, 첫번째 인자 shiro: this = shiro
  5. 멤버함수 call, 인자없음: this = window
  6. 멤버함수 call, 첫번째 인자 shiro: this = shiro

결과를 보면 1번은 일반적으로 함수가 호출될 때 내부적으로 call()함수로 변형되어서 처리되는데, 이때 call()함수의 첫번째 인자를 undefined로 넘겨주어 this의 기본값으로 window가 들어가게 된다.

따라서 call()이나 apply()함수를 이용한 함수 호출에서는 첫 번째 인자로 설정한 객체가 this로 설정되며, 인자가 넘어가지 않을 때는 일반 함수 호출과 같이 글로벌 객체인 window가 this로 설정된다.

 

2번은 같은 멤버함수 호출인 경우에는 내부적으로 call()함수를 호출할 때 첫번째 인자로 멤버함수를 보유한 객체를 넘겨준다. 2번 예에서는 첫번째 인자로 shiro가 넘어가기 때문에 this는 shiro가 된다.

하지만 같은 함수라도 멤버함수가 호출되는 방법이 다르면 this는 또 변경된다.

 

멤버함수를 다른 방법으로 호출하는 예

var newWhat = shiro.what;

console.log(newWhat()); // [object window]

이렇게 this는 함수나 스코프 기반으로 결정되는 것이 아닌 호출방법에 따라 변경된다.

반응형

+ Recent posts