AngularJS 컨트롤러에서 'this'와 $ scope


1026

AngularJS 홈페이지"Create Components"섹션 에는 다음 예제가 있습니다.

controller: function($scope, $element) {
  var panes = $scope.panes = [];
  $scope.select = function(pane) {
    angular.forEach(panes, function(pane) {
      pane.selected = false;
    });
    pane.selected = true;
  }
  this.addPane = function(pane) {
    if (panes.length == 0) $scope.select(pane);
    panes.push(pane);
  }
}

어떻게 '공지 select방법에 추가됩니다 $scope,하지만 addPane방법이 추가됩니다 this. 로 변경 $scope.addPane하면 코드가 중단됩니다.

문서에는 실제로 차이점이 있지만 차이점이 무엇인지 언급하지 않았습니다.

이전 버전의 Angular (1.0 RC 이전) this에서는 $scope메소드 와 상호 교환 하여 사용할 수 있었지만 더 이상 그렇지 않습니다. 방법의 내부는 범위에 정의 this$scope상호 교환 (각 세트 있습니다 this에를 $scope) 있지만 그렇지 않으면 컨트롤러 생성자 내부.

어떻게 this$scopeAngularJS와 컨트롤러에서 사용할 수 있습니까?


나는 또한 혼란 스럽습니다. 뷰가 컨트롤러를 지정하면 (예 : ng-controller = '...') 뷰가 $ scope 속성에 액세스 할 수 있기 때문에 해당 컨트롤러와 관련된 $ scope가 함께 나타납니다. 그러나 지시어가 다른 컨트롤러를 '필요한 다음 연결 기능에 사용하면 다른 컨트롤러와 관련된 $ scope가 함께 제공되지 않습니까?
Mark Rajcok

"이전 버전 ..."에 대한 혼란스러운 인용문이 지금 제거 되었습니까? 그렇다면 업데이트가 있을까요?
Dmitri Zaitsev

단위 테스트의 경우 '$ scope'대신 'this'를 사용하면 조롱 된 범위로 컨트롤러를 주입 할 수 없으므로 단위 테스트를 수행 할 수 없습니다. 'this'를 사용하는 것이 좋은 습관이라고 생각하지 않습니다.
abentan

답변:


999

"어떻게 this$scopeAngularJS와 컨트롤러에서 사용할 수 있습니까?"

짧은 답변 :

  • this
    • 컨트롤러 생성자 함수가 호출되면 this컨트롤러입니다.
    • $scope객체 에 정의 된 this함수가 호출 될 때 "함수가 호출 될 때 적용되는 범위"입니다. 이것은 $scope함수가 정의 된 것일 수도 있습니다 . 따라서, 함수 내에서, this그리고 $scope없는 동일합니다.
  • $scope
    • 모든 컨트롤러에는 관련 $scope개체가 있습니다.
    • 컨트롤러 (생성자) 기능은 모델 속성 및 관련 기능 / 동작을 설정합니다 $scope.
    • $scope객체 에 정의 된 메소드 (및 프로토 타입 상속이 사용중인 경우 상위 범위 객체) 만 HTML / 뷰에서 액세스 할 수 있습니다. 예 : ng-click필터 등

긴 대답 :

컨트롤러 함수는 JavaScript 생성자 함수입니다. 생성자 함수가 실행될 때 (예를 들어, 뷰가로드 될 때), this즉 "함수 컨텍스트"는 컨트롤러 객체로 설정된다. addPane 함수가 생성 될 때 "탭"컨트롤러 생성자 함수에서

this.addPane = function(pane) { ... }

$ scope가 아닌 컨트롤러 객체에서 생성됩니다. 뷰는 addPane 함수를 볼 수 없습니다. $ scope에 정의 된 함수에만 액세스 할 수 있습니다. 즉, HTML에서는 작동하지 않습니다.

<a ng-click="addPane(newPane)">won't work</a>

"탭"컨트롤러 생성자 함수가 실행되면 다음과 같은 결과가 나타납니다.

탭 컨트롤러 생성자 함수 후

파선으로 표시된 검은 선은 프로토 타입 상속을 나타냅니다. 격리 범위는 프로토 타입으로 Scope 에서 상속됩니다 . (이 명령은 HTML에서 지시어가 발생한 범위에서 프로토 타입으로 상속되지 않습니다.)

이제 pane 지시문의 링크 함수는 tabs 지시문과 통신하려고합니다 (실제로 어떤 식 으로든 탭이 $ scope를 분리하는 데 영향을 주어야 함). 이벤트를 사용할 수 있지만 또 다른 메커니즘은 창 지시문 require에 탭 컨트롤러 를 두는 것 입니다. ( require$ scope 탭 에 대한 pane 지시문에 대한 메커니즘이없는 것 같습니다 .)

따라서 이것은 질문을 제기합니다 : 탭 컨트롤러에만 액세스 할 수 있다면 탭에 어떻게 액세스하여 $ scope를 분리합니까 (실제로 원하는 것입니까)?

빨간색 점선이 그 답입니다. addPane () 함수의 "scope"(여기서는 JavaScript의 함수 범위 / 클로저를 참조하고 있습니다)는 탭 격리 $ scope에 대한 액세스 권한을 제공합니다. 즉, addPane ()은 addPane ()이 정의 될 때 생성 된 클로저로 인해 위의 다이어그램에서 "탭 IsolateScope"에 액세스 할 수 있습니다. (대신에 $ scope 객체 탭에서 addPane ()을 정의하면 pane 지시문이이 함수에 액세스 할 수 없으므로 $ scope 탭과 통신 할 방법이 없습니다.)

질문의 다른 부분에 대답하려면 how does $scope work in controllers?:

$ scope에 정의 된 함수 내 this에서 "함수가 호출 된 시점 및 시점에 적용되는 $ scope"로 설정됩니다. 다음 HTML이 있다고 가정하십시오.

<div ng-controller="ParentCtrl">
   <a ng-click="logThisAndScope()">log "this" and $scope</a> - parent scope
   <div ng-controller="ChildCtrl">
      <a ng-click="logThisAndScope()">log "this" and $scope</a> - child scope
   </div>
</div>

그리고 ParentCtrl(Solely)는

$scope.logThisAndScope = function() {
    console.log(this, $scope)
}

첫 번째 링크를 클릭하면 그 표시됩니다 this$scope"이후, 동일 함수가 호출 유효한 범위 의"와 연관된 범위이다 ParentCtrl.

제 2 링크를 클릭하면 계시 this하고 $scope있는 없다 "때문에, 동일한 함수가 호출 유효한 범위 의"와 연관된 범위이다 ChildCtrl. 그래서 여기 this로 설정 ChildCtrl의 ' $scope. 메소드 안에는 $scope여전히 ParentCtrl$ 범위입니다.

깡깡이

thisng-repeat, ng-include, ng-switch 및 지시문이 모두 자체 자식 범위를 만들 수 있다는 점을 고려하여 $ scope에 정의 된 함수 내부를 사용하지 마십시오 .


6
@ tamakisquare, 나는 당신이 인용 한 굵은 글씨가 컨트롤러 생성자 함수가 호출 될 때, 즉 컨트롤러가 생성 될 때 = $ scope와 관련이 있다고 생각합니다. 임의의 JavaScript 코드가 $ scope 객체에 정의 된 메서드를 호출 할 때는 나중에 적용되지 않습니다.
Mark Rajcok

79
컨트롤러의 이름을 "MyController as myctrl"으로 지정한 다음 myctrl.addPane ()을 지정하여 템플리트에서 직접 addPane () 함수를 호출 할 수 있습니다. docs.angularjs.org/guide/concepts#controller
Christophe Augier를

81
고유 한 복잡성이 너무 많습니다.
Inanc Gumus

11
이것은 매우 유익한 답변이지만 실용적인 문제 ( 'this'사용하여 정의 된 컨트롤러 메서드에서 $ scope. $ apply ()를 호출하는 방법)로 돌아 왔을 때 해결할 수 없었습니다. 이것이 여전히 유용한 답변이지만, "내재 된 복잡성"당황 스럽습니다.
dumbledad

11
자바 스크립트-많은 밧줄 [자신을 교수형].
AlikElzin-kilaka

55

'addPane'이 할당 된 이유는 <pane>지시문 때문입니다 .

pane지시자 않는 require: '^tabs'링크 기능으로, 부모 지시자로부터 탭 제어기 오브젝트를 두는.

addPane에 할당 this있도록 pane링크 기능이 그것을 볼 수 있습니다. 그런 다음 pane링크 함수 addPane에서 tabs컨트롤러 의 속성이며 tabsControllerObject.addPane입니다. 따라서 pane 지시문의 연결 기능은 탭 컨트롤러 객체에 액세스하여 addPane 메서드에 액세스 할 수 있습니다.

내 설명이 충분히 명확하길 바랍니다. 설명하기가 어렵습니다.


3
설명 주셔서 감사합니다. 문서는 컨트롤러가 범위를 설정하는 기능 인 것처럼 보입니다. 모든 동작이 범위에서 발생하는 경우 컨트롤러가 개체처럼 취급되는 이유는 무엇입니까? 왜 부모 범위를 연결 함수에 전달하지 않습니까? 편집 :이 질문을 더 잘 표현하기 위해 컨트롤러 메소드와 범위 메소드가 모두 동일한 데이터 구조 (범위)에서 작동하는 경우 모두 한곳에 두지 않겠습니까?
Alexei Boronine

"재사용 가능한 구성 요소를 지원하려는 의도로 인해 상위 범위가 lnk 기능으로 전달되지 않는 것 같습니다.이 구성 요소는 실수로 상위 범위의 데이터를 읽거나 수정해서는 안됩니다." 그러나 지시어가 실제로 'pane'지시어와 같이 상위 범위의 일부 특정 데이터를 읽거나 수정하려는 경우 약간의 노력이 필요합니다. 원하는 상위 범위가있는 컨트롤러를 '필요'한 다음 특정 데이터에 액세스하려면 해당 컨트롤러의 메소드 ($ scope가 아닌 'this'사용). 원하는 부모 범위가 lnk 기능에 주입되지 않기 때문에 이것이 유일한 방법이라고 생각합니다.
Mark Rajcok

1
이봐, 지시문의 범위를 수정하는 것이 실제로 더 쉽습니다. 링크 기능 jsfiddle.net/TuNyj
Andrew Joslin을

3
바이올린에 대한 @ 앤디 감사합니다. 바이올린에서 지시어가 새로운 범위를 생성하지 않으므로 링크 기능이 컨트롤러의 범위에 직접 액세스하는 방법을 볼 수 있습니다 (범위가 하나뿐이므로). 탭 및 창 지시문은 격리 범위를 사용합니다 (즉, 부모 범위에서 프로토 타입으로 상속되지 않는 새 자식 범위가 생성됨). 분리 범위의 경우, 컨트롤러에서 메소드를 정의 ( 'this'사용)하면 다른 지시문이 다른 (분리 된) 범위에 (간접) 액세스 할 수있는 유일한 방법 인 것 같습니다.
Mark Rajcok

27

방금 두 가지의 차이점에 대한 흥미로운 흥미로운 설명을 읽었으며 모델을 컨트롤러에 연결하고 컨트롤러의 별칭을 지정하여 모델을 뷰에 바인딩하는 선호도가 높아지고 있습니다. 기사는 http://toddmotto.com/digging-into-angulars-controller-as-syntax/ 입니다.
그는 언급하지 않지만 지시문을 정의 할 때 여러 지시문 사이에 무언가를 공유해야하고 서비스를 원하지 않는 경우 (서비스가 번거로운 합당한 경우가 있음) 부모 지시문의 컨트롤러에 데이터를 첨부하십시오.

$scope서비스는 $watch가장 유용한 유용한 기능을 많이 제공 하지만 데이터에 뷰를 바인딩해야하는 경우 템플릿의 일반 컨트롤러 및 '컨트롤러'를 사용하는 것이 좋습니다.


20

다음 게시물을 읽는 것이 좋습니다 : AngularJS : "Controller as"또는 "$ scope"?

"$ scope"보다 변수를 노출하기 위해 "Controller as"를 사용하는 이점을 잘 설명합니다.

변수가 아닌 메서드에 대해 구체적으로 묻는 것을 알고 있지만 한 가지 기술을 고수하고 일관성을 유지하는 것이 좋습니다.

내 의견으로는 게시물에서 논의 된 변수 문제로 인해 "Controller as"기술을 사용하고 메소드에 적용하는 것이 좋습니다.


16

이 과정 ( https://www.codeschool.com/courses/shaping-up-with-angular-js )에서 "this"와 다른 많은 것들을 사용하는 방법을 설명합니다.

"this"메소드를 통해 컨트롤러에 메소드를 추가하는 경우 컨트롤러 이름이 "dot"인 뷰에서 메소드 또는 메소드를 호출해야합니다.

예를 들어보기에서 컨트롤러를 사용하면 다음과 같은 코드가있을 수 있습니다.

    <div data-ng-controller="YourController as aliasOfYourController">

       Your first pane is {{aliasOfYourController.panes[0]}}

    </div>

6
과정을 마친 후에는을 사용하는 코드로 $scope인해 즉시 혼란 스러웠 으므로 언급 해 주셔서 감사합니다.
Matt Montag

16
그 과정은 그들은 단지 사용 모두에서 $ 범위를 언급하지 않습니다 asthis어떻게 차이를 설명 할 수 있도록?
dumbledad

10
Angular와의 첫 번째 접촉은 언급 한 과정에서 왔으며 $scope결코 언급되지 않았으므로 this컨트롤러 에서만 사용하는 법을 배웠습니다 . 문제는 컨트롤러에서 약속을 다루기 시작할 때 많은 참조 문제가 this있으며 약속 반환 함수 내에서 var me = this모델을 참조하는 것과 같은 일을 시작해야한다는 것 this입니다. 그 때문에 그래서, 나는 여전히 어떤 방법이 나에게 사용한다에 대해 혼동하고있어 $scopethis.
Bruno Finger

@BrunoFinger 불행히도, 약속 또는 다른 클로즈가 많은 작업을 수행 할 때 var me = this또는 .bind(this)필요할 때마다 필요합니다 . Angular와는 아무런 관련이 없습니다.
Dzmitry Lazerka

1
중요한 것은 컨트롤러 자체 ng-controller="MyCtrl as MC"에 넣는 것과 같다는 $scope.MC = this것입니다. – 템플릿을 사용하기 위해 범위에 MyCtrl 인스턴스 (이것)를 정의합니다{{ MC.foo }}
William B

3

이전 버전의 Angular (1.0 RC 이전)에서는이를 $ scope 메소드와 호환하여 사용할 수 있었지만 더 이상 그렇지 않습니다. 스코프에 정의 된 메소드 내에서 this와 $ scope는 교환 가능하지만 (앵글은 이것을 $ scope로 설정) 컨트롤러 생성자 내부에서는 그렇지 않습니다.

이 동작을 되돌리려면 (누군가 왜 변경되었는지 알고 있습니까?) 다음을 추가 할 수 있습니다.

return angular.extend($scope, this);

컨트롤러 기능이 끝날 때 (이 컨트롤러 기능에 $ scope가 주입 된 경우).

이것은 자식 개체를 가질 수있는 컨트롤러 개체를 통해 부모 범위에 액세스 할 수있는 좋은 효과가 있습니다. require: '^myParentDirective'


7
이 기사 는 왜 이것과 $ scope가 다른지에 대한 좋은 설명을 제공합니다.
Robert Martin

1

$ scope는 'this'와 컨트롤러 'this'가 다릅니다. 따라서 console.log (this)를 컨트롤러에 넣으면 객체 (controller)를 제공하고 this.addPane ()은 addPane 메서드를 컨트롤러 Object에 추가합니다. 그러나 $ scope의 범위는 다르며 해당 범위의 모든 메서드는 $ scope.methodName ()에 의해 액세스되어야합니다. this.methodName()컨트롤러 내부는 컨트롤러 객체 내부에 메 토스를 추가하는 것을 의미합니다. $scope.functionName()HTML 안에 있고

$scope.functionName(){
    this.name="Name";
    //or
    $scope.myname="myname"//are same}

이 코드를 편집기에 붙여 넣고 콘솔을 열어서 ...

 <!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>this $sope vs controller</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.7/angular.min.js"></script>
    <script>
        var app=angular.module("myApp",[]);
app.controller("ctrlExample",function($scope){
          console.log("ctrl 'this'",this);
          //this(object) of controller different then $scope
          $scope.firstName="Andy";
          $scope.lastName="Bot";
          this.nickName="ABot";
          this.controllerMethod=function(){

            console.log("controllerMethod ",this);
          }
          $scope.show=function(){
              console.log("$scope 'this",this);
              //this of $scope
              $scope.message="Welcome User";
          }

        });
</script>
</head>
<body ng-app="myApp" >
<div ng-controller="ctrlExample">
       Comming From $SCOPE :{{firstName}}
       <br><br>
       Comming from $SCOPE:{{lastName}}
       <br><br>
       Should Come From Controller:{{nickName}}
       <p>
            Blank nickName is because nickName is attached to 
           'this' of controller.
       </p>

       <br><br>
       <button ng-click="controllerMethod()">Controller Method</button>

       <br><br>
       <button ng-click="show()">Show</button>
       <p>{{message}}</p>

   </div>

</body>
</html>
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.