2011-06-10 9 views
1

다음 코드를 고려하십시오 Dog의 인스턴스에 this 포인터 점을 가정 "특권"canWalk() 방법과 그 코드에 버그가 있습니다"특권"메소드 호출 멤버 메소드 문제

function Dog() 
{ 
    this.foo = function() {}; 

    this.walk = function() 
    { 
     if(canWalk()) 
     { 
      alert('walking'); 
      return; 
     } 

     alert('I have no legs!'); 
    } 

    canWalk = function() 
    { 
     this.foo(); 
     return false; 
    } 
} 

var instance = new Dog(); 
instance.walk(); 

. 그것은 실제로 나를 혼란스럽게하는 전 지구 적 대상을 가리키고있는 것처럼 보입니다! 나는 클로저로 인해 생성자의 범위에서 this에 대한 참조를 가져올 수있다. 그런 다음 "권한있는"방법으로 참조를 사용하지만 해킹처럼 보인다.

다양한 컨텍스트에서 this 포인터의 동작을 간신히 파악합니다. 개체에 "부착 된"메서드는 첨부 된 개체를 가리키는 this을 받게된다는 것을 알고 있습니다. 예를 들어, foo.doStuff()foo 인스턴스를 가리키는 this입니다.

내가 문제가되는 것은 내가 영리하다고 생각하고 내 OBJECT에 "권한있는"방법을 만드는 것인데, 사실 내가 전역 범위에 함수를 덤핑하고있는 것처럼 보입니다! 아마도 다른 라이브러리 또는 파일에서 직접 생성 한 것이 아닌 init()이라는 전역 메서드가있었습니다 (가능한 경우). 그런 다음 init()이라는 "권한있는"메서드를 사용하여 작은 캡슐화 된 개체를 정의한 경우 다른 글로벌 init() 메서드를 대체합니다.

제 질문은, 그들이 속한 대상으로 범위가 지정된 "권한있는"방법 (및 해당 필드)을 만드는 가장 좋은 방법은 무엇입니까? 내 샘플 객체에 대한 다른 접근 방법으로는 사설 또는 권한있는 메소드를 제공하면서 적절한 범위를 지정할 수 있습니다. 요구 사항을 충족시키지 못하는 모호한 솔루션을 찾는 것이 아니라 최선의 방법을 찾는 것입니다.

+0

내 원래의 게시물을 편집하는 방법을 알아낼 수 없습니다,하지만 난 깨달았다 불행한 오류가 발생하여 올바른 예제 코드를 붙여 넣지 않았습니다. canWalk() 메서드에서 "foo"메서드 호출이 있었으므로 기본적으로 canWalk()가 this.foo()를 호출하고있었습니다. 혼란에 대한 죄송합니다. –

+0

아, 알겠습니다. 이 경우'this'는 아마'canWalk' 함수를 가리킬 것입니다. 내 예제에서'self.foo'를 사용했다면 괜찮을 것입니다. 어딘가에 아마도 편집 버튼이 있습니다 :) – Halcyon

+1

@ 스티브 (Steve) 텍스트의 왼쪽 하단에있는 파란색 태그 바로 아래에있는 "편집"을 클릭하여 자신의 글을 편집 할 수 있습니다. 내가 설명한 내용으로 코드를 업데이트하려고 시도했지만 약간 불명확했습니다. – ErikE

답변

4

this을 사용하지 마십시오. 도그 기능의 상단에 var self = this;을 넣고 self을 사용하십시오. 그런 식으로 개를 항상 '안전하게'참조 할 수 있습니다.

thisDog을 가리켜 야합니다. 내가 누락 된 것이 없으면 말입니다.

권한있는 방법에 대해서는 변수 정의를 잊어 버렸습니다. 추가 var canWalk;

다른 방법이 있습니다. 클로저입니다.

function create_dog() { 
    function canWalk() { 
     return false; 
    } 
    function walk() { 
     if (canWalk()) { 
      alert("walking"); 
      return; 
     } 
     alert("I have no hands!"); 
    } 
    return { 
     "walk": walk // points to the function walk() 
    }; // this the API of dog, like public functions (or properties) 
} 
var dog = create_dog(); 
dog.walk(); 

지금 당신이 this 또는 new 필요가 없습니다 내가 예를 제공 할 것입니다. 또한 당신이 할 수 있습니다 :
function create_dog() { 
    function canWalk() { 
     return false; 
    } 
    function walk() { 
     if (canWalk()) { 
      alert("walking"); 
      return; 
     } 
     alert("I have no hands!"); 
    } 
    var dog = { 
     "walk": walk 
    }; 
    return dog; 
} 
var dog = create_dog(); 
dog.walk(); 

그래서 당신은 당신의 priveledges 기능의 dog에 대한 참조를 가질 수 있습니다. 프로토 타이핑을 사용하지 않을 경우 클로저 방식을 권장합니다.

그건 그렇고.

function my_func() {} 

var my_func = function() {}; 

은 동일합니다 혼동을 피하기합니다. 후자는 두 함수 사이에 순환 참조가 있고 사용 전 정의를 시행하려는 경우 유용 할 수 있습니다.

+0

+1 완전히 다른 두 가지 방법으로 똑같은 일을하는 훌륭한 대답. –

+0

왜 '새 개'에서 벗어나 객체를 만드시겠습니까? – ErikE

+0

프로토 타이핑을 사용하지 않는다면'new' 사용에 이점이 없습니다. 클로저 접근법을 사용할 수 있으며, 상속을 시도하지 마십시오. – Halcyon

1

먼저 canWalk 앞에 var이 필요합니다. 그런 식으로 canWalk 함수는 암시 적 전역이 아닌 dog()의 범위로 제한됩니다.

this은 함수의 "소유자"를 가리 킵니다. new 연산자를 사용할 때이 함수는 자체 범위를 만듭니다. 따라서 dog()의 본문 내에서 this은 dog 인스턴스 객체를 참조합니다. walk 함수 내에서 은 walk 함수를 dog (this.walk = function() { ... })의 인스턴스로 설정했기 때문에 dog 인스턴스를 참조합니다. 그러나 canWalk에는 소유자가 없으므로 this은 전역 개체를 가리 킵니다. window.

var obj = { 
    'f': function() { 
     // this === obj, because obj "owns" this function 
     // In other words, this function is callable by obj.f() 
    }, 
    'o': { 
     'f': function() { 
      // this === obj.o, because obj.o "owns" this function 
      // In other words, this function is callable by obj.o.f() 
     } 
    } 
}; 

// The new operator essentially sets "this" within the 
// function to an empty object and returns that object 
var instance = new Dog(); 

function Dog() { 
    // this === instance, because of the "new" operator 

    // For demonstration 
    var self = this; 

    this.walk = function() { 
     // this === instance === self, because self/instance "owns" this function 
     // In other words, this function is callable by self.walk() 
    }; 

    var canWalk = function() { 
     // What's the owner of this object? Nothing, 
     // so it defaults to the global object, window 
     // this === window 

     // Instead, we can access the Dog instance by 
     // using the "self" variable we set earlier. 
     // self === instance 
    }; 
} 

희망 물건을 지 웁니다

가 내 설명이 혼동 될 수 있음을 인식, 그래서 여기 내 설명의 코드 주석 버전입니다.

+0

이것은 상황의 두 요소 모두에 대한 좋은 설명입니다. 나는 canwalk의 암시 적 글로벌 범위만을 다루고 있었기 때문에 나는 나의 대답을 삭제했다. +1 –

+0

또 다른 좋은 설명과 사물의 발표. 나는 내가 'var'를 앞에 사용하지 않았다는 사실을 놓친 것이 조금 당혹 스럽다. –

1

수집 한 것처럼 canWalk를 똑바로 호출하면 'this'키워드가 해당 함수 호출의 전역 객체로 설정된다는 것을 의미합니다. 현재 개의 컨텍스트에서 호출을 실행하려면

명시 적으로 다음과 같이 수행 할 수 있습니다 :

canWalk.call(this)

+0

나는 call() 솔루션을 찾았지만 정확하지 않았기 때문에 그것을 사용하지 않기로 결정했다. 대신 냄새가있어서 디자인 변경을 찾아야한다고 생각했다. 그러나 call() 옵션을 기억하는 것이 좋습니다. –