AngularJS控制器中的'this'与$ scope

本文翻译自:'this' vs $scope in AngularJS controllers

In the "Create Components" section of AngularJS's homepage , there is this example: 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);
  }
}

Notice how the select method is added to $scope , but the addPane method is added to this . 请注意如何将select方法添加到$scope ,但是将addPane方法添加到this If I change it to $scope.addPane , the code breaks. 如果我将其更改为$scope.addPane ,代码将中断。

The documentation says that there in fact is a difference, but it doesn't mention what the difference is: 该文档说实际上存在区别,但是没有提到区别是什么:

Previous versions of Angular (pre 1.0 RC) allowed you to use this interchangeably with the $scope method, but this is no longer the case. 以前的Angular版本(1.0 RC之前的版本)允许您与$scope方法互换使用this方法,但情况不再如此。 Inside of methods defined on the scope this and $scope are interchangeable (angular sets this to $scope ), but not otherwise inside your controller constructor. 对范围定义的方法里面this$scope是可以互换(角套this$scope ),而不是其他你的控制器构造函数中。

How does this and $scope work in AngularJS controllers? this$scope在AngularJS控制器中如何工作?


#1楼

参考:https://stackoom.com/question/mhED/AngularJS控制器中的-this-与-scope


#2楼

The reason 'addPane' is assigned to this is because of the <pane> directive. 之所以将'addPane'分配给它,是因为<pane>指令。

The pane directive does require: '^tabs' , which puts the tabs controller object from a parent directive, into the link function. pane指令确实require: '^tabs' ,它将来自父指令的tabs控制器对象放入链接函数。

addPane is assigned to this so that the pane link function can see it. addPane分配给this以便pane链接功能可以看到它。 Then in the pane link function, addPane is just a property of the tabs controller, and it's just tabsControllerObject.addPane. 然后,在pane链接函数中, addPane只是tabs控制器的属性,而只是tabsControllerObject.addPane。 So the pane directive's linking function can access the tabs controller object and therefore access the addPane method. 因此,窗格指令的链接功能可以访问tabs控制器对象,因此可以访问addPane方法。

I hope my explanation is clear enough.. it's kind of hard to explain. 我希望我的解释很清楚..这很难解释。


#3楼

"How does this and $scope work in AngularJS controllers?" this$scope在AngularJS控制器中如何工作?”

Short answer : 简短答案

  • this
    • When the controller constructor function is called, this is the controller. 当控制器构造函数被调用, this是控制器。
    • When a function defined on a $scope object is called, this is the "scope in effect when the function was called". 调用在$scope对象上定义的函数时, this是“调用该函数时生效的作用域”。 This may (or may not!) be the $scope that the function is defined on. 这可能是(也可能不是!)是在其上定义函数的$scope So, inside the function, this and $scope may not be the same. 因此,在函数内部, this$scope可能相同。
  • $scope
    • Every controller has an associated $scope object. 每个控制器都有一个关联的$scope对象。
    • A controller (constructor) function is responsible for setting model properties and functions/behaviour on its associated $scope . 控制器(构造函数)负责在其关联的$scope上设置模型属性和功能/行为。
    • Only methods defined on this $scope object (and parent scope objects, if prototypical inheritance is in play) are accessible from the HTML/view. 从HTML /视图只能访问在$scope对象(和父作用域对象,如果正在进行原型继承)上定义的方法。 Eg, from ng-click , filters, etc. 例如,通过ng-click ,过滤器等

Long answer : 长答案

A controller function is a JavaScript constructor function. 控制器函数是JavaScript构造函数。 When the constructor function executes (eg, when a view loads), this (ie, the "function context") is set to the controller object. 当构造函数执行时(例如,加载视图时), this函数(即“函数上下文”)被设置为控制器对象。 So in the "tabs" controller constructor function, when the addPane function is created 因此,在“ tabs”控制器构造函数中,创建addPane函数时

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

it is created on the controller object, not on $scope. 它是在控制器对象上创建的,而不是在$ scope上创建的。 Views cannot see the addPane function -- they only have access to functions defined on $scope. 视图无法看到addPane函数-它们只能访问$ scope上定义的函数。 In other words, in the HTML, this won't work: 换句话说,在HTML中,这是行不通的:

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

After the "tabs" controller constructor function executes, we have the following: 执行“ tabs”控制器构造函数后,我们将具有以下内容:

Tabs控制器构造函数之后

The dashed black line indicates prototypal inheritance -- an isolate scope prototypically inherits from Scope . 黑色虚线表示原型继承-一个隔离范围原型从Scope继承。 (It does not prototypically inherit from the scope in effect where the directive was encountered in the HTML.) (它并不是从HTML中遇到该指令的有效范围继承的原型。)

Now, the pane directive's link function wants to communicate with the tabs directive (which really means it needs to affect the tabs isolate $scope in some way). 现在,pane指令的链接函数希望与tabs指令进行通信(这实际上意味着它需要以某种方式影响选项卡隔离$ scope)。 Events could be used, but another mechanism is to have the pane directive require the tabs controller. 可以使用事件,但是另一种机制是使pane指令require tabs控制器。 (There appears to be no mechanism for the pane directive to require the tabs $scope.) (pane指令似乎没有机制require使用选项卡$ scope。)

So, this begs the question: if we only have access to the tabs controller, how do we get access to the tabs isolate $scope (which is what we really want)? 因此,这就引出了一个问题:如果我们只能访问tabs控制器,我们如何才能访问这些选项卡将$ scope隔离(这是我们真正想要的)?

Well, the red dotted line is the answer. 好吧,红色虚线就是答案。 The addPane() function's "scope" (I'm referring to JavaScript's function scope/closures here) gives the function access to the tabs isolate $scope. addPane()函数的“作用域”(我在这里指的是JavaScript的函数作用域/闭包)使函数可以访问选项卡隔离$ scope。 Ie, addPane() has access to the "tabs IsolateScope" in the diagram above because of a closure that was created when addPane() was defined. 即,由于定义了addPane()时创建的闭包,addPane()可以访问上图中的“选项卡IsolateScope”。 (If we instead defined addPane() on the tabs $scope object, the pane directive would not have access to this function, and hence it would have no way to communicate with the tabs $scope.) (如果改为在选项卡的$ scope对象上定义addPane(),则panel指令将无法访问此函数,因此它将无法与选项卡的$ scope通信。)

To answer the other part of your question: how does $scope work in controllers? 回答问题的另一部分: how does $scope work in controllers? :

Within functions defined on $scope, this is set to "the $scope in effect where/when the function was called". 在$ scope定义的函数中, this其设置为“在调用函数的位置/时间生效的$ scope”。 Suppose we have the following HTML: 假设我们有以下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>

And the ParentCtrl (Solely) has 而且ParentCtrlParentCtrl )具有

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

Clicking the first link will show that this and $scope are the same, since " the scope in effect when the function was called " is the scope associated with the ParentCtrl . 单击第一个链接将显示this$scope相同,因为“ 调用函数时有效的作用域”是与ParentCtrl关联的ParentCtrl

Clicking the second link will reveal this and $scope are not the same, since " the scope in effect when the function was called " is the scope associated with the ChildCtrl . 单击第二个链接将显示this$scope 相同,因为“ 调用函数时有效的作用域”是与ChildCtrl关联的ChildCtrl So here, this is set to ChildCtrl 's $scope . 因此,这里this其设置为ChildCtrl$scope Inside the method, $scope is still the ParentCtrl 's $scope. 在方法内部, $scope仍然是ParentCtrl的$ scope。

Fiddle 小提琴

I try to not use this inside of a function defined on $scope, as it becomes confusing which $scope is being affected, especially considering that ng-repeat, ng-include, ng-switch, and directives can all create their own child scopes. 我尝试不要在$ scope上定义的函数中使用this函数,因为它会使受影响的$ scope变得混乱,尤其是考虑到ng-repeat,ng-include,ng-switch和指令都可以创建自己的子范围。


#4楼

Previous versions of Angular (pre 1.0 RC) allowed you to use this interchangeably with the $scope method, but this is no longer the case. 以前的Angular版本(1.0 RC之前的版本)允许您与$ scope方法互换使用此方法,但情况不再如此。 Inside of methods defined on the scope this and $scope are interchangeable (angular sets this to $scope), but not otherwise inside your controller constructor. 在范围内定义的方法内部,此变量和$ scope是可互换的(将其角度设置为$ scope),但在控制器构造函数中则不可。

To bring back this behaviour (does anyone know why was it changed?) you can add: 要恢复这种行为(有人知道为什么更改了吗?),您可以添加:

return angular.extend($scope, this);

at the end of your controller function (provided that $scope was injected to this controller function). 在控制器功能的末尾(假设$ scope已注入此控制器功能)。

This has a nice effect of having access to parent scope via controller object that you can get in child with require: '^myParentDirective' 通过控制器对象访问父级作用域具有很好的效果,您可以使用require: '^myParentDirective'进入子require: '^myParentDirective'


#5楼

I just read a pretty interesting explanation on the difference between the two, and a growing preference to attach models to the controller and alias the controller to bind models to the view. 我刚刚读到了关于这两者之间区别的一个非常有趣的解释,并且越来越喜欢将模型附加到控制器,并对控制器进行别名以将模型绑定到视图。 http://toddmotto.com/digging-into-angulars-controller-as-syntax/ is the article. 本文是http://toddmotto.com/digging-into-angulars-controller-as-syntax/ He doesn't mention it but when defining directives, if you need to share something between multiple directives and don't want a service (there are legitimate cases where services are a hassle) then attach the data to the parent directive's controller. 他没有提到它,但是在定义指令时,如果您需要在多个指令之间共享某些内容并且不想要服务(在某些情况下,服务很麻烦),则将数据附加到父指令的控制器。 The $scope service provides plenty of useful things, $watch being the most obvious, but if all you need to to bind data to the view, using the plain controller and 'controller as' in the template is fine, and arguably preferable. $ scope服务提供了很多有用的功能,其中$ watch最明显,但是如果您需要将数据绑定到视图,则可以在模板中使用普通控制器和'controller as'很好,并且可以说是更可取的。


#6楼

In this course( https://www.codeschool.com/courses/shaping-up-with-angular-js ) they explain how to use "this" and many other stuff. 在本课程中( https://www.codeschool.com/courses/shaping-up-with-angular-js ),他们介绍了如何使用“ this”和许多其他内容。

If you add method to the controller through "this" method, you have to call it in the view with controller's name "dot" your property or method. 如果通过“ this”方法将方法添加到控制器,则必须在视图中以控制器名称“点”您的属性或方法来调用它。

For example using your controller in the view you may have code like this: 例如,在视图中使用控制器,您可能会具有以下代码:

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

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

    </div>
发布了0 篇原创文章 · 获赞 3 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/p15097962069/article/details/105307870