繁体   English   中英

AngularJS 控制器中的“this”与 $scope

[英]'this' vs $scope in AngularJS controllers

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 控制器中是如何工作的?

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

简短的回答

  • this
    • 当控制器构造函数被调用时, this是控制器。
    • 当在$scope对象上定义的函数被调用时, this是“调用该函数时有效的范围”。 这可能(也可能不是!)是定义函数的$scope 所以,在函数内部, this$scope可能一样。
  • $scope
    • 每个控制器都有一个关联的$scope对象。
    • 控制器(构造函数)函数负责在其关联的$scope上设置模型属性和函数/行为。
    • 只有在此$scope对象(和父范围对象,如果原型继承在起作用)上定义的方法才能从 HTML/视图访问。 例如,来自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 中遇到指令的有效范围继承。)

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

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

好吧,红色虚线就是答案。 addPane() 函数的“范围”(我在这里指的是 JavaScript 的函数范围/闭包)为函数提供了对标签隔离 $scope 的访问权限。 即,addPane() 可以访问上图中的“tabs IsolateScope”,因为在定义 addPane() 时创建了一个闭包。 (如果我们改为在选项卡 $scope 对象上定义 addPane(),则窗格指令将无法访问此函数,因此它无法与选项卡 $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 ( ParentCtrl ) 有

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

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

点击第二个链接,就会发现this$scope一样的,因为“有效范围时,函数被称为”与相关的范围ChildCtrl 所以在这里, this被设置为ChildCtrl$scope 在方法内部, $scope仍然是ParentCtrl的 $scope。

小提琴

我尽量不使用this上$范围内定义的函数中,因为它变得扑朔迷离其中$范围受到影响,尤其是考虑到NG-重复,NG-包括NG-开关和指令都可以创建自己的子作用域.

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

pane指令确实require: '^tabs' ,它将来自父指令的选项卡控制器对象放入链接函数。

addPane分配给this以便pane链接功能可以看到它。 那么在pane链接函数中, addPane只是tabs控制器的一个属性,也就是tabsControllerObject.addPane。 因此,pane 指令的链接函数可以访问选项卡控制器对象,从而访问 addPane 方法。

我希望我的解释足够清楚。这有点难以解释。

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

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

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

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

我建议您阅读以下帖子: AngularJS:“Controller as”还是“$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 方法互换使用,但现在已不再如此。 在范围 this 和 $scope 上定义的方法内部是可以互换的(angular 将 this 设置为 $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>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM