Pregunta 'this' vs $ scope en controladores AngularJS


En el Sección "Crear componentes" de la página de inicio de AngularJS, hay un ejemplo:

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);
  }
}

Observe cómo el select método se agrega a $scope, pero el addPane método se agrega a this. Si lo cambio a $scope.addPane, el código se rompe.

La documentación dice que, de hecho, hay una diferencia, pero no menciona cuál es la diferencia:

Las versiones anteriores de Angular (pre 1.0 RC) le permitieron usar this indistintamente con el $scope método, pero este ya no es el caso. Dentro de los métodos definidos en el alcance this y $scope son intercambiables (conjuntos angulares) this a $scope), pero no dentro de su constructor de controlador.

Cómo this y $scope trabajar en controladores AngularJS?


965
2017-07-23 02:55


origen


Respuestas:


"Cómo this y $scope trabajar en controladores AngularJS? "

Respuesta corta:

  • this
    • Cuando se llama a la función del constructor del controlador, this es el controlador.
    • Cuando una función definida en un $scope se llama objeto, this es el "alcance en vigor cuando se llamó a la función". Esto puede (¡o no!) Ser el $scope que la función está definida en. Entonces, dentro de la función, this y $scope mayo no ser el mismo.
  • $scope
    • Cada controlador tiene un asociado $scope objeto.
    • Una función de controlador (constructor) es responsable de establecer propiedades de modelo y funciones / comportamiento en su asociado $scope.
    • Solo los métodos definidos en este $scope objeto (y objetos de ámbito principal, si la herencia prototípica está en juego) son accesibles desde el HTML / vista. Por ejemplo, de ng-click, filtros, etc.

Respuesta larga:

Una función de controlador es una función de constructor de JavaScript. Cuando la función constructor se ejecuta (por ejemplo, cuando se carga una vista), this (es decir, el "contexto de función") se establece en el objeto controlador. Entonces, en la función del constructor del controlador "pestañas", cuando se crea la función addPane

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

se crea en el objeto controlador, no en $ scope. Las vistas no pueden ver la función addPane, solo tienen acceso a las funciones definidas en $ scope. En otras palabras, en el HTML, esto no funcionará:

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

Después de que se ejecuta la función del constructor del controlador "pestañas", tenemos lo siguiente:

after tabs controller constructor function

La línea discontinua negra indica la herencia del prototipo: un alcance aislado prototípicamente hereda de Alcance. (No hereda de manera prototípica el alcance en vigor donde se encontró la directiva en el HTML).

Ahora, la función de enlace de la directiva pane necesita comunicarse con la directiva de pestañas (lo que realmente significa que necesita afectar las pestañas para aislar $ scope de alguna manera). Se podrían usar eventos, pero otro mecanismo es tener la directiva del panel require el controlador de pestañas. (Parece que no hay ningún mecanismo para la directiva del panel para require las pestañas $ scope.)

Por lo tanto, esto plantea la pregunta: si solo tenemos acceso al controlador de pestañas, ¿cómo accedemos a las pestañas para aislar $ scope (que es lo que realmente queremos)?

Bueno, la línea roja punteada es la respuesta. El "alcance" de la función addPane () (me refiero al alcance / cierres de funciones de JavaScript aquí) le da a la función acceso a las pestañas aislar $ scope. Es decir, addPane () tiene acceso a las "pestañas IsolateScope" en el diagrama anterior debido a un cierre que se creó cuando se definió addPane (). (Si en cambio definimos addPane () en el objeto $ scope de tabuladores, la directiva pane no tendría acceso a esta función, y por lo tanto no tendría forma de comunicarse con las pestañas $ scope.)

Para responder la otra parte de tu pregunta: how does $scope work in controllers?:

Dentro de las funciones definidas en $ scope, this está configurado a "$ scope en efecto donde / cuando se llamó a la función". Supongamos que tenemos el siguiente 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>

Y el ParentCtrl (Solo) tiene

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

Al hacer clic en el primer enlace, se mostrará que this y $scope son lo mismo, ya que "el alcance en vigor cuando se llamó a la función"es el alcance asociado con el ParentCtrl.

Al hacer clic en el segundo enlace se revelará this y $scope son no lo mismo, ya que "el alcance en vigor cuando se llamó a la función"es el alcance asociado con el ChildCtrl. Entonces aquí, this se establece en ChildCtrles $scope. Dentro del método, $scope sigue siendo el ParentCtrl$ $ scope

Violín

Intento no usar this dentro de una función definida en $ scope, ya que se vuelve confuso qué $ scope se ve afectado, especialmente si se considera que ng-repeat, ng-include, ng-switch y directivas pueden crear sus propios ámbitos secundarios.


949
2018-01-05 04:48



La razón por la cual se le asigna 'addPane' es debido a la <pane> directiva.

los pane directiva no require: '^tabs', que coloca el objeto del controlador de pestañas de una directiva principal en la función de enlace.

addPane está asignado a this de manera que la pane la función de enlace puede verlo. Entonces en el pane función de enlace addPane es solo una propiedad de tabs controlador, y solo es tabsControllerObject.addPane. Por lo tanto, la función de vinculación de la directiva del panel puede acceder al objeto del controlador de pestañas y, por lo tanto, acceder al método addPane.

Espero que mi explicación sea lo suficientemente clara ... es algo difícil de explicar.


50
2017-07-23 15:20



Acabo de leer una explicación bastante interesante sobre la diferencia entre los dos, y una creciente preferencia para adjuntar modelos al controlador y alias del controlador para vincular los modelos a la vista. http://toddmotto.com/digging-into-angulars-controller-as-syntax/ es el articulo No lo menciona, pero al definir las directivas, si necesita compartir algo entre varias directivas y no desea un servicio (hay casos legítimos en que los servicios son una molestia), adjunte los datos al controlador de la directiva principal. El servicio $ scope proporciona muchas cosas útiles, $ watch es el más obvio, pero si todo lo que necesita para enlazar datos a la vista, usar el controlador simple y el 'controlador como' en la plantilla está bien, y podría decirse que es preferible.


26
2017-08-28 21:25



En este curso(https://www.codeschool.com/courses/shaping-up-with-angular-js) explican cómo usar "esto" y muchas otras cosas.

Si agrega un método al controlador mediante este método, debe llamarlo a la vista con el nombre del controlador "dot" su propiedad o método.

Por ejemplo, usando su controlador en la vista puede tener un código como este:

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

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

    </div>

15
2017-09-24 07:29



Te recomiendo que leas la siguiente publicación: http://codetunnel.io/angularjs-controller-as-or-scope/

describe muy bien las ventajas de usar "Controlador como" para exponer variables sobre "$ scope".

Sé que preguntaste específicamente sobre métodos y no sobre variables, pero creo que es mejor seguir una técnica y ser consecuente con ella.

Por lo tanto, para mi opinión, debido al problema de variables discutido en la publicación, es mejor usar la técnica "Controlador como" y también aplicarla a los métodos.


15
2017-11-03 10:31



Las versiones anteriores de Angular (pre 1.0 RC) le permitieron usar esto   de manera intercambiable con el método $ scope, pero este ya no es el   caso. Dentro de los métodos definidos en el alcance this y $ scope son   intercambiable (angular establece esto en $ scope), pero no de otra manera   dentro de tu constructor de controlador

Para devolver este comportamiento (¿alguien sabe por qué se cambió?) Puede agregar:

return angular.extend($scope, this);

al final de su función de controlador (siempre que $ scope se haya inyectado a esta función del controlador).

Esto tiene un buen efecto de tener acceso al ámbito principal a través del objeto controlador que puede obtener en el niño con require: '^myParentDirective'


3
2018-06-20 08:46



$ scope tiene un 'this' diferente, luego el controlador 'this'. Por lo tanto, si coloca console.log (this) dentro del controlador, le da un objeto (controlador) y this.addPane () agrega addPane Method al controlador Object. Pero el $ scope tiene un alcance diferente y todos los métodos en su alcance necesitan ser accedidos por $ scope.methodName (). this.methodName() dentro del controlador significa agregar methos dentro del objeto controlador.$scope.functionName() está en HTML y adentro

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

Pegue este código en su editor y abra la consola para ver ...

 <!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>

0
2018-02-07 09:06