AngularJS控制器中的'this'与$范围

AngularJS主页的“创建组件”部分中,有这样一个例子:

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控制器中工作?

306936 次浏览

将“addPane”分配给它的原因是因为<pane>指令。

pane指令执行require: '^tabs',它将父指令中的tab控制器对象放入link函数中。

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

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

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

简短的回答

  • this
    • 当调用控制器构造函数时,this是控制器。
    • 当调用$scope对象上定义的函数时,this是“调用函数时有效的范围”。这可能(也可能不是!)是定义函数的$scope。因此,在函数内部,this$scope可能没有相同。
  • $scope
    • 每个控制器都有一个关联的$scope对象。
    • 控制器(构造函数)函数负责在其关联的$scope上设置模型属性和函数/行为。
    • 只有在这个$scope对象上定义的方法(以及父作用域对象,如果使用原型继承)才能从超文本标记语言/视图访问。例如,从ng-click,过滤器等。

冗长的回答

控制器函数是JavaScript构造函数。当构造函数执行时(例如,当视图加载时),this(即“函数上下文”)被设置为控制器对象。所以在“选项卡”控制器构造函数中,当创建addPane函数时

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

它是在控制器对象上创建的,而不是在$scope上创建的。视图看不到addPane函数——它们只能访问$scope上定义的函数。换句话说,在超文本标记语言中,这是行不通的:

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

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

制表符控制器构造函数之后

虚线黑线表示原型继承——隔离范围原型继承自范围。(它不原型继承自超文本标记语言中遇到指令的有效范围。)

现在,pane指令的link函数想要与tabs指令进行通信(这实际上意味着它需要以某种方式影响选项卡隔离$范围)。可以使用事件,但另一种机制是让pane指令require成为选项卡控制器。(窗格指令似乎没有将tabs$范围require的机制。)

所以,这就引出了一个问题:如果我们只能访问选项卡控制器,我们如何访问选项卡隔离$范围(这是我们真正想要的)?

好吧,红色虚线就是答案。addPane()函数的“作用域”(我在这里指的是JavaScript的函数作用域/闭包)允许函数访问制表符隔离$作用域。即,addPane()可以访问上图中的“制表符隔离作用域”,因为在定义addPane()时创建了一个闭包。(如果我们在tabs$作用域对象上定义addPane(),则窗格指令将无法访问此函数,因此它将无法与制表符$作用域通信。)

回答你问题的另一部分:how does $scope work in controllers?

在$ope上定义的函数中,this被设置为“调用函数时/调用函数时生效的$ope”。假设我们有以下超文本标记语言:

<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(唯一)

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

单击第一个链接将显示this$scope是相同的,因为“调用函数时有效的范围”是与ParentCtrl关联的范围。

单击第二个链接将显示this$scope没有相同,因为“调用函数时有效的范围”是与ChildCtrl关联的范围。所以在这里,this被设置为ChildCtrl$scope。在方法内部,$scope仍然是ParentCtrl的$范围。

小提琴

我尽量不使用this在一个函数中定义的范围,因为它会混淆哪个范围正在受到影响,特别是考虑到ng-重复,ng-包括,ng-开关,和指令都可以创建自己的子范围。

以前版本的Angular(1.0 RC之前)允许您使用此可以与$scope方法互换,但这不再是case。在作用域this和$scope上定义的方法内部是可互换的(角设置这个$范围),但不是其他在控制器构造函数中。

要恢复这种行为(有人知道为什么它被改变了吗?)你可以添加:

return angular.extend($scope, this);

在控制器函数的末尾(前提是$scope被注入到这个控制器函数中)。

这有一个很好的效果,可以通过控制器对象访问父范围,您可以使用require: '^myParentDirective'在子对象中获得

我刚刚读了一篇关于两者之间区别的非常有趣的解释,以及越来越倾向于将模型附加到控制器并为控制器别名以将模型绑定到视图。http://toddmotto.com/digging-into-angulars-controller-as-syntax/是文章。

注:原始链接仍然存在,但格式更改使其难以阅读。查看在原始更容易。

他没有提到这一点,但在定义指令时,如果您需要在多个指令之间共享某些内容并且不需要服务(在某些情况下,服务是一个麻烦),那么将数据附加到父指令的控制器。

$scope服务提供了很多有用的东西,$watch是最明显的,但是如果你只需要将数据绑定到视图,那么在模板中使用普通控制器和“控制器为”是很好的,可以说是更可取的。

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

如果您通过“this”方法向控制器添加方法,您必须在视图中以控制器的名称“点”调用它您的属性或方法。

例如,在视图中使用你的控制器,你可能有这样的代码:

    <div data-ng-controller="YourController as aliasOfYourController">
Your first pane is \{\{aliasOfYourController.panes[0]}}
</div>

我建议你阅读以下文章:AngularJS:“控制器为”或“$范围”?

它非常好地描述了使用“Controller as”在“$作用域”上公开变量的优点。

我知道你特别问的是方法而不是变量,但我认为最好坚持一种技术并与之保持一致。

因此,在我看来,由于本文中讨论的变量问题,最好只使用“Controller as”技术并将其应用于方法。

$作用域有一个不同的'this',然后控制器有一个'this'。因此,如果你把一个console.log(this)放在控制器内,它会给你一个对象(控制器)this.addPane()将addPane方法添加到控制器对象。但是$作用域有不同的作用域,其作用域中的所有方法都需要由$scope.methodName()访问。this.methodName()内部控制器意味着在控制器对象中添加方法。$scope.functionName()是超文本标记语言,在

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