2010-12-10 10 views
3

자바 스크립트에서 객체를 생성하는 팩토리 패턴을 보여주는 자습서를 따르고 있습니다. 다음 코드는 왜 그것이 작동하는지에 관해서 난처하게했습니다.자바 스크립트 팩토리 패턴 변수 범위 지정

<html xmlns="http://www.w3.org/1999/xhtml"> 
<head> 
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
<title>6-2.htm</title> 
</head> 
<body> 
<script type="text/javascript"> 
function createAddress(street, city, state, zip) { 
    var obj = new Object(); 
    obj.street = street; 
    obj.city = city; 
    obj.state = state; 
    obj.zip = zip; 
    obj.showLabel = function() { 
    //alert(this.street + "\n" + this.city + ", " + this.state + " " + this.zip); 
    //var obj; 
    alert(obj.street + "\n" + obj.city + ", " + obj.state + " " + obj.zip); 
    }; 
    return obj; 
}; 

var JohnAddr = createAddress("12 A St.", "Johnson City", "TN", 37614); 
var JoeAddr = createAddress("10061 Bristol Park", "Pensacola", "FL", 32503); 

JohnAddr.showLabel(); 
JoeAddr.showLabel(); 
</script> 
</body> 
</html> 

첫 번째 주석 행합니다 (showLabel 함수에서 this 키워드를 사용) 나에게 적합한 것 같다. 그 자리에서 obj를 사용하는 것이 어떻게 작동하는지 모르겠습니다. obj는 전역 변수를 어딘가에서 참조해야 할 것입니다. 왜냐하면 그 함수 내에서 실행될 obj가 정의되지 않았기 때문입니다. 왜냐하면 나는 2 개의 객체를 만든다.이 경우 행운 만 뚜렷하게 표시되는 것이 아니라 obj의 내용에 대한 이전 값이 저장되고 참조된다. 하지만 어떻게? 내가 두 번째 주석의 주석을 없애면 깨지고 그 이유를 알게되어 현재 로컬 변수에 대해 이야기하고 있으며 아무 것도 없다는 것을 명시 적으로 알려줍니다.

답변

6

에 오신 것을 환영합니다. 당신은 당신이로 느끼는 것을 느낄 맞아 마치 글로벌이지만 꽤 글로벌하지 않은 것 같습니다. 이것이 클로저의 작동 방식입니다.

기본적으로 함수가 반환 될 때 모든 로컬 변수가 반드시 Java 또는 C처럼 가비지 수집/해제됩니다. 해당 변수에 대한 참조가 있으면 해당 변수는 정의 된 함수의 범위 내에서 유지됩니다.

기술적 인면에서는 기술이 다르며 어떤 사람들은 그렇게 설명하고 많은 사람들을 혼란스럽게 만듭니다. 나에게 클로저는 전역 변수와 마찬가지로 일종의 '개인적인'전역 변수이며, 전체 함수에서 공유되지만 전역 범위에서 선언되지는 않습니다.이 기능을 접할 때 느낌을 묘사하는 것과 같습니다.

여기에 내가 믿는 자바 스크립트 폐쇄에 관한 유래에 여기 내 다른 답변 중 일부는 가치가 읽고 있습니다

Hidden Features of JavaScript?

Please explain the use of JavaScript closures in loops

아니면 그냥 문구를 구글 수 있습니다 "자바 스크립트 폐쇄" 주제를 탐험 해보세요.


추가 답변. 반대로 코드에서 왜 this 작품의 설명에 관해서는

(에 * 기침 * ;-) *는 수정되지 않은 버전 * 기침에서 작동하지만 this도 작동 할 수 있도록 코드를 수정하려고 시도 :

자바 스크립트에 후기 바인딩이 있습니다. 아주 늦게, 아주 늦게. this은 컴파일하는 동안 바인딩되지 않을뿐만 아니라 런타임 중에 바인딩되지 않습니다. 실행 시간에 바인딩됩니다. 즉, 함수가 호출 될 때까지 실제로 이것이 가리키는 것을 알 수 없습니다. 호출자는 기본적으로 this이 사용되는 함수가 아닌 this의 값을 결정합니다.

일부 펑키 자바 스크립트 런타임에 바인딩 연습 : 작동 왜 코드에서

function foo() { 
    alert(this.bar); 
} 

var bar = "hello"; 
var obj = { 
    foo : foo, 
    bar : "hi" 
}; 
var second_obj = { 
    bar : "bye" 
}; 

foo(); // says hello, 'this' refers to the global object and this.bar 
     // refers to the global variable bar. 

obj.foo(); // says hi, 'this' refers to the first thing before the last dot 
      // ie, the object foo belongs to 

// now this is where it gets weird, an object can borrow/steal methods of 
// another object and have its 'this' re-bound to it 

obj.foo.call(second_obj); // says bye because call and apply allows 'this' 
          // to be re-bound to a foreign object. In this case 
          // this refers to second_obj 

this 편리하게 당신이 분명히 하지있는 가정 를 사용하더라도 자사의 방법으로 함수를 호출하는 객체를 참조 올바른 생성자 구문

+0

우연히 이것은 유감스럽게 생각하는 것에 매우 반대입니다 (그러나 그럼에도 불구하고 흥미 롭습니다). 정말 당신의 의견을 주셔서 감사합니다! 내가 가장 도움이되었다고 생각하는 것은 내가 (변수를 전달하면) 괄호를 보면 예상대로 동작하지만 괄호를 보지 않으면 자세히 살펴 봐야한다는 것입니다. – Ankur

2

obj 함수가 showLabel 함수 내부에서 작동하는 이유는 obj가 지역 변수이기 때문입니다. 이 함수는 create address가 호출 될 때마다 선언됩니다. 자바 스크립트에서는 이것을 클로저 (closure)라고 부릅니다.

일반적으로 프로토 타입 개체 생성이이 팩터 리 패턴보다 선호됩니다. 당신이 기대하는 것처럼 코드가 정확히 작동합니다

// create new address 
var address = new Address('1', '2', '3', '4'); 
address.showLabel(); // alert 

: 나는 새 키워드로 새 주소를 만들 때 이제

var Address = function(street, city, state, zip){ 
    this.street = street; 
    this.city = city; 
    this.state = state; 
    this.zip= zip; 
}; 

Address.prototype.showLabel = function(){ 
    alert(this.street + "\n" + this.city + ", " + this.state + " " + this.zip); 
} 

:

지금이 프로토 타입의 예를 보라. 그러나 생성자 안에 새 키워드 this을 사용하지 않으면 실제로는 window 개체입니다.

// create new address 
var address = Address('1', '2', '3', '4'); // address == undefined 
window.showLabel(); // address was added to window 

이 내용이 약간 비워지기를 바랍니다.

+0

프로토 타입 패턴이 더 우아합니다. 나는 학문적 인 POV에서 왔고 나는 왜 공장 패턴이 효과가 있었는지 배우고 싶었다. 감사! – Ankur

0

이것은 js의 기이함 중 하나입니다. showLabel은 클로저이며 obj에 대한 액세스 권한을 가지고 있습니다. 이는 createAddress가 호출 될 때마다 새로운 클로저가 만들어집니다.

var에 foo는 = 새로운 createAddress (...

그리고 멤버 변수를 할당 할 수 :

는 '이'는 식으로 당신은 당신이 그렇게 new 연산자를 사용할 필요가 거라고 기대하고 사용하려면 '이'에. 사용하지 않는 새로운이 경우

'이'글로벌 개체입니다. 폐쇄의 세계에

+0

그래, 내가 받아 들일 수 있지만 그때 왜 첫 번째 주석 라인 작업을 사용합니까? (다른 2 개의 선 없음으로 나는 의미한다). this.street가 실제로 window.street를 할당하면 showLabel에 대한 두 번째 호출이 다른 값을 반환하고 덮어 쓰기로 인해 이전 값을 잃지 않는 이유는 무엇입니까? – Ankur

+0

나는 다음과 같이 말하면서 내 질문에 답하는 것이 맞다. 'this'는 특별한 변수이고, 클로저에도 불구하고 여전히 함수가 멤버 인 객체를 참조 할 것이다. 또는 나는 이것을 완전히 얻지 못합니까? – Ankur

+0

@ 안 쿠르 : 제 대답을보십시오. 짧게 당신이 말하는 것은 옳습니다. – slebetman

1
function Address(street, city, state, zip) { 

    this.street = street; 
    this.city = city; 
    this.state = state; 
    this.zip = zip; 
    this.showLabel = function() { 
    //alert(this.street + "\n" + this.city + ", " + this.state + " " + this.zip); 
    //var obj; 
    alert(this.street + "\n" + this.city + ", " + this.state + " " + this.zip); 
    }; 
}; 

var JohnAddr = new Address(...); 
JohnAddr.showLabel(); 
+0

+1은 스코프에 대한 그의 질문에 대답하지 않지만 멋진 우아한 솔루션입니다. – Zevan