var name = `Kim`; // 전역변수로 선언 ⇒ 전역객체(window)의 프로퍼티로 할당됨
function foo() {
console.log(this); // window
console.log(this.name); // window.name이므로 Kim
}
foo();
var age = 100;
function foo() {
var age = 99;
bar(age); // 함수의 내부 함수
callback(age); // 콜백 함수
}
function bar() {
console.log(this.age); // window.age이므로 100
}
function callback() {
setTimeout(function() {
console.log(this); // window
console.log(this.age); // window.age이므로 100
}, 100);
}
foo();
ES6문법 const / let은 window 전역객체의 프로퍼티로 할당되지 않는다.
// Dot Notation
var age = 100;
// 리터럴 방식으로 객체 생성
var ken = {
age: 35,
foo: function() {
console.log(this.age); // ken.age이므로 35
}
}
ken.foo();
var fn = ken.foo;
fn(); // 일반함수 호출 => window.age이므로 100
// 프로토타입 객체의 경우에도 해당 함수를 호출한 객체에 바인딩된다.
function Person(name) {
this.name = name;
}
Person.prototype.getName = function() {
return this.name;
}
var foo = new Person(`Lee`);
console.log(foo.getName()); // foo에 바인딩되므로 Lee
Person.prototype.name = `Kim`;
console.log(Person.prototype.getName()); // prototype Object에 바인딩되므로 Kim
* 생성자 함수 동작 방식 *
function Person(paramName) {
this.name = paramName;
}
var person1 = new Person('kim'); // { name:kim }
// 1) 빈 객체(Empty Object) 생성 후 생성자 함수 내의 this를 이 객체에 바인딩
// => {}가 생성되고 this에 바인딩 되었다!
// 2) this를 통한 프로퍼티 생성
// => this.name = paramName 구문에 의해 { name:kim } 프로퍼티가 생성되었다!
// 3) 위에서 암묵적으로 생성된 객체 반환
// 3-1) return 이 없으면 this에 바인딩된 객체 반환
// => this에 바인딩된 { name:kim } 객체가 반환되어 person1에 할당되었다!
// 3-2) return 으로 다른 객체를 반환할 수도 있음. (아래 예시)
function Stranger(strangeName) {
this.name = strangeName;
return { name: 'strange' };
}
var stranger = new Stranger('park'); // { name: strange }
// 이 경우 this가 생성자 함수에서의 역할을 수행하지 못한다. ⇒ 보통 return 명시하지 않음
function Person(name) {
this.name = name;
}
var kim = new Person(`Kim`);
console.log(kim.name); // kim.name 이므로 Kim
// 일반 함수로 호출 -> 암묵적으로 객체를 생성하여 반환하지 않는다.
// 일반 함수의 this는 전역객체에 바인딩된다.
var lee = Person(`Lee`);
console.log(lee.name); // undefined.name 이므로 TypeError
function.prototype.apply
/ function.prototype.call
/ function.prototype.bind
사용/*
* 1) func.apply(thisArg, [argsArray])
* thisArg: 함수 내부의 this에 바인딩할 객체
* argArray: 함수에 전달할 argument의 배열
*/
function Person(name) {
this.name = name;
}
var foo = {};
// apply 는 생성자 함수 Person을 호출하고,
// 이때 this에 객체 foo를 바인딩한다.
Person.apply(foo, [`Foo`]);
console.log(foo); // { name: `Foo` }
/*
* 2) func.call(thisArg[, arg1[, arg2 …]])
* thisArg: 함수 내부의 this에 바인딩할 객체
* arg: 함수에 전달할 argument
*/
Person.call(foo, `Foo`);
/*
* 3) func.bind(thisArg)()
* func에 인자로 전달한 thisArg가 this에 바인딩된 새로운 함수를 반환
* apply나 call처럼 함수를 실행하지 않으므로 별도로 호출해줘야 한다.
*/
Person.bind(foo)(`Foo`);
1) 일반함수 호출방식 관련 : Strict mode 에서 일반 함수 실행
⇒ this가 window객체와 의도치 않게 바인딩되어 발생하는 문제를 예방할 수 있다.
/*
* strict mode 사용 방법: 스크립트 코드 최상단에 ‘use strict’ 구문 추가
*/
‘use strict’;
var name = `Kim`;
function foo() {
console.log(this.name); // error
}
foo();
2) 생성자 함수 관련 : Scope-Safe Constructor Pattern
⇒ 휴먼에러 (ex. new 키워드 누락) 으로 인해 this 가 생성자 함수 실행으로 반환된 객체와 바인딩되지 않은 문제를 예방할 수 있다.
/*
* Scope-Safe Constructor Pattern
*/
function A(arg) {
// 생성자 함수가 new 연산자와 함께 호출되면 빈객체를 생성하고 this에 바인딩한다.
if (!(this instanceof arguments.callee)) {
return new arguments.callee(arg);
}
/*
* arguments.callee = 호출된 함수의 이름
* this가 호출된 함수(arguments.callee, 여기서는 A)의 인스턴스가 아니면
* new 연산자를 사용하지 않은 것이므로
* new와 함께 생성자 함수를 호출하여 인스턴스를 반환한다.
*/
// 프로퍼티 생성과 값의 할당
this.value = arg ? arg : 0;
}
var a = new A(100);
var b = A(10);
console.log(a.value); // 100
console.log(b.value); // 10
유익한 글이었습니다.