‘this’ vs $ scope en controladores AngularJS

En la sección “Crear componentes” de la página principal 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 se agrega el método de select a $scope , pero se addPane método addPane 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 permitían usar this indistintamente con el método $scope , pero este ya no es el caso. Dentro de los métodos definidos en el scope this y $scope son intercambiables (angular establece this en $scope ), pero no dentro de su constructor de controlador.

¿Cómo funcionan this y $scope en los controladores AngularJS?

“¿Cómo funciona this y $scope en los controladores AngularJS?”

Respuesta corta :

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

Larga respuesta :

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 la función”) se establece en el objeto controlador. Entonces, en la función del constructor del controlador “tabs”, 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á:

 won't work 

Después de que se ejecuta la función del constructor del controlador “tabs”, tenemos lo siguiente:

después de la función del constructor del controlador de pestañas

La línea negra discontinua indica la herencia prototípica: un scope aislado prototípicamente hereda de Scope . (No hereda de manera prototípica el scope 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 tabs (lo que realmente significa que necesita afectar las tabs para aislar $ scope de alguna manera). Se podrían usar eventos, pero otro mecanismo es hacer que la directiva pane require el controlador de tabs. (Parece que no hay ningún mecanismo para que la directiva pane require las tabs $ scope).

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

Bueno, la línea roja punteada es la respuesta. El “scope” de la función addPane () (me refiero al scope / cierres de funciones de JavaScript aquí) le da a la función acceso a las tabs aislar $ scope. Es decir, addPane () tiene acceso a las “tabs IsolateScope” en el diagtwig 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 tabs $ scope.)

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

Dentro de las funciones definidas en $ scope, this se establece en “$ scope en efecto donde / cuando se llamó a la función”. Supongamos que tenemos el siguiente HTML:

 
log "this" and $scope - parent scope
log "this" and $scope - child scope

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 los mismos, ya que ” el scope en vigor cuando se llamó a la función ” es el scope asociado con el ParentCtrl .

Hacer clic en el segundo enlace revelará this y $scope no son lo mismo, ya que ” el scope en vigor cuando se llamó a la función ” es el scope asociado con el ChildCtrl . Así que aquí, this está configurado en el $scope ChildCtrl . Dentro del método, $scope sigue siendo el $ $ de ParentCtrl .

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 scopes secundarios .

La razón por la cual se le asigna ‘addPane’ se debe a la directiva .

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

addPane se asigna a this para que la función de enlace del pane pueda verlo. Luego, en la función de enlace de pane , addPane es solo una propiedad del controlador de tabs , 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 tabs y, por lo tanto, acceder al método addPane.

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

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 artículo. 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.

Te recomiendo que leas la siguiente publicación: 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.

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:

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

Las versiones anteriores de Angular (pre 1.0 RC) le permitían usar esto indistintamente con el método $ scope, pero este ya no es el caso. Dentro de los métodos definidos en el scope this y $ scope son intercambiables (angular establece esto en $ scope), pero no dentro de su 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 efecto agradable de tener acceso al ámbito principal a través del objeto controlador que puede obtener en el niño con require: '^myParentDirective'

$ 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 scope diferente y todos los métodos en su scope necesitan ser accedidos por $ scope.methodName (). this.methodName() dentro del controlador significa agregar methos dentro del objeto controlador. $scope.functionName() está en HTML y dentro

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

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

        this $sope vs controller     
Comming From $SCOPE :{{firstName}}

Comming from $SCOPE:{{lastName}}

Should Come From Controller:{{nickName}}

Blank nickName is because nickName is attached to 'this' of controller.





{{message}}