''''vs AngularJS控制器中的$ scope

问题描述 投票:1024回答:7

"Create Components" section of AngularJS's homepage中,有此示例:

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$scope在AngularJS控制器中如何工作?

angularjs angularjs-scope this
7个回答
998
投票

this$scope在AngularJS控制器中如何工作?”

简短回答

  • this
    • 当调用控制器构造函数时,this是控制器。
    • 当调用在$scope对象上定义的函数时,this是“调用该函数时有效的作用域”。这可能(也可能不是!)是定义功能的$scope。因此,在函数内部,this$scope可能not相同。
  • $scope
    • 每个控制器都有一个关联的$scope对象。
    • 控制器(构造函数)负责在其关联的$scope上设置模型属性和功能/行为。
    • 只能在HTML /视图中访问此$scope对象(和父作用域对象,如果正在进行原型继承)中定义的方法。例如,来自ng-click,过滤器等

长答案

控制器函数是JavaScript构造函数。执行构造函数时(例如,加载视图时),会将this(即“函数上下文”)设置为控制器对象。因此,在“ tabs”控制器构造函数中,当创建addPane函数时]

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

它是在控制器对象上创建的,而不是在$ scope上创建的。视图无法看到addPane函数-它们只能访问$ scope上定义的函数。换句话说,在HTML中,这是行不通的:

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

执行“ tabs”控制器构造函数后,我们将具有以下内容:

“在选项卡控制器构造函数之后

黑色虚线表示原型继承-一个隔离范围原型继承自Scope。 (它并不是从HTML中遇到该指令的有效范围继承的原型。)

现在,窗格指令的链接功能希望与tabs指令通信(这实际上意味着它需要以某种方式影响选项卡隔离$ scope)。可以使用事件,但是另一种机制是使tabs控制器具有窗格指令require。 (对于窗格指令require选项卡$ scope,似乎没有机制。)

所以,这引出了一个问题:如果我们仅有权使用tabs控制器,那么我们如何获得对选项卡的隔离$ scope(这是我们真正想要的?)?

嗯,红色虚线是答案。 addPane()函数的“作用域”(我在这里指的是JavaScript的函数作用域/闭包)使函数可以访问选项卡隔离$ scope。也就是说,由于在定义addPane()时创建了一个闭包,因此addPane()可以访问上图中的“选项卡IsolateScope”。 (如果我们改为在选项卡的$ scope对象上定义addPane(),则panel指令将无法访问此功能,因此它将无法与选项卡的$ 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关联的作用域。

单击第二个链接将显示this$scope相同,因为[调用函数时有效的作用域

“是与ChildCtrl关联的作用域。因此,此处this设置为ChildCtrl$scope。在方法内部,$scope仍然是ParentCtrl的$ scope。Fiddle

我尽量不要在$ scope上定义的函数中使用this,因为这会影响哪个$ scope,特别是考虑到ng-repeat,ng-include,ng-switch和指令都可以创建时,这会造成混乱他们自己的子范围。

之所以将'addPane'分配给它是因为<pane>指令。

pane指令执行require: '^tabs',该操作将来自父指令的tabs控制器对象放入链接函数。

addPane被分配给this,以便pane链接功能可以看到它。然后,在pane链接函数中,addPane只是tabs控制器的属性,而只是tabsControllerObject.addPane。因此,窗格指令的链接功能可以访问tabs控制器对象,因此可以访问addPane方法。

我希望我的解释足够清楚。。这很难解释。

我刚刚阅读了关于两者之间区别的一个非常有趣的解释,并且越来越喜欢将模型附加到控制器,并对控制器进行别名以将模型绑定到视图。 http://toddmotto.com/digging-into-angulars-controller-as-syntax/是文章。他没有提到它,但是在定义指令时,如果您需要在多个指令之间共享某些内容并且不想要服务(在某些情况下,服务很麻烦),则将数据附加到父指令的控制器。

$scope服务提供了很多有用的东西,$watch是最显而易见的,但是如果您需要将数据绑定到视图,则在模板中使用普通控制器和'controller as'是很好的,并且可以说是更可取的。

我建议您阅读以下文章:AngularJS: "Controller as" or "$scope"?

很好地描述了使用“ Controller as”来公开变量而不是“ $ scope”的优点。

我知道您是专门询问方法而不是变量,但是我认为最好坚持一种技术并与之保持一致。

因此,我认为,由于帖子中讨论了变量问题,最好只使用“ Controller as”技术,并将其应用于方法。

在本课程(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>

以前的Angular版本(1.0 RC之前的版本允许您使用可与$ scope方法互换使用,但这不再是案件。在作用域和$ scope定义的方法内部可互换(将其设置为$ scope),但不能互换在您的控制器构造函数中。

要恢复这种行为(有人知道为什么更改了吗?),您可以添加:

return angular.extend($scope, this);

在控制器功能的末尾(假设$ scope已注入到此控制器功能中。)>

这具有很好的效果,即可以通过控制器对象访问父范围,而该对象可以用require: '^myParentDirective'进入子对象。>

$ scope具有与控制器“ this”不同的“ this”。因此,如果将console.log(this)放在控制器中,它将为您提供一个对象(控制器),并且this.addPane()将addPane方法添加到控制器宾语。但是$ 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>


55
投票
之所以将'addPane'分配给它是因为<pane>指令。

27
投票
我刚刚阅读了关于两者之间区别的一个非常有趣的解释,并且越来越喜欢将模型附加到控制器,并对控制器进行别名以将模型绑定到视图。 http://toddmotto.com/digging-into-angulars-controller-as-syntax/是文章。他没有提到它,但是在定义指令时,如果您需要在多个指令之间共享某些内容并且不想要服务(在某些情况下,服务很麻烦),则将数据附加到父指令的控制器。

20
投票
我建议您阅读以下文章:AngularJS: "Controller as" or "$scope"?

16
投票
在本课程(https://www.codeschool.com/courses/shaping-up-with-angular-js)中,他们解释了如何使用“ this”和许多其他内容。

3
投票
以前的Angular版本(1.0 RC之前的版本允许您使用可与$ scope方法互换使用,但这不再是案件。在作用域和$ scope定义的方法内部可互换(将其设置为$ scope),但不能互换在您的控制器构造函数中。

1
投票
$ scope具有与控制器“ this”不同的“ this”。因此,如果将console.log(this)放在控制器中,它将为您提供一个对象(控制器),并且this.addPane()将addPane方法添加到控制器宾语。但是$ scope具有不同的范围,并且其范围内的所有方法都必须由$ scope.methodName()访问。控制器内部的this.methodName()意味着在控制器对象内部添加方法。$scope.functionName()在HTML中和内部

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

将此代码粘贴到编辑器中,然后打开控制台以查看...
© www.soinside.com 2019 - 2024. All rights reserved.