【发布时间】:2014-03-28 16:42:15
【问题描述】:
我在不同的地方读到过,始终使用范围内的对象很重要,但我还没有找到明确的答案来解释为什么会这样。有人可以帮帮我吗?
【问题讨论】:
-
Cherniv:我认为您所链接的答案确实为这个问题提供了指导,并且深入探讨了更大范围的问题。但我相信这个页面上的问题讨论了 Angular 开发人员应该知道的一个重要且更具体的问题。因此,我相信它有必要做出自己的回应。
标签: angularjs
我在不同的地方读到过,始终使用范围内的对象很重要,但我还没有找到明确的答案来解释为什么会这样。有人可以帮帮我吗?
【问题讨论】:
标签: angularjs
我喜欢 Ryan Q 的答案,但在做了更多研究后,我想添加一个更强调 javascript 原型继承的答案。
这里的问题是对象与原始问题(按引用传递和按值传递)以及 Javascript 的原型继承如何工作。
当 javascript 类从父类继承时,它会将值复制到子类中。有两种类型的值可以被复制,对象或基元。
当通过继承复制对象时,它是通过引用传递的。这意味着我在子对象中所做的任何更新也会在父对象中看到。
当通过继承复制原语时,它是按值传递的。这意味着在父类中不会看到任何更新。
这与 Angular 作用域有什么关系?当我们创建指令时,将为该指令创建一个作用域,我们可以将其声明为隔离作用域或继承作用域。如果它是继承范围,它将继承其父范围项。现在,如果我的父作用域中有原始值,我会将它们作为按值传递继承到我的子作用域中。这意味着当我在父作用域中进行更改时,它不会在我的子作用域中看到,反之亦然。现在我可以在我的子范围和父范围中拥有相同的继承变量,但具有不同的值。这会导致混乱......还有可能是愤怒……哈哈。
所以如果你只是使用一个对象,那么这个问题就不会发生。这就是为什么你应该总是在范围内的对象。
【讨论】:
假设您有 3 个控制器、一个主控件和另外两个从主控件继承的控制器。
您的 html 可能如下所示。
<div ng-controller="MainCtrl">
<div ng-show="helloWorld">Hello World</div>
<div ng-controller="Sub1Ctrl">
<button type="button" ng-click="helloWorld = false">Hide Hello World</button>
</div>
<div ng-controller="Sub2Ctrl">
<button type="button" ng-click="helloWorld = false">Hide Hello World</button>
</div>
</div>
你的主控制器
angular.module('MyModule').controller('MainCtrl', function( $scope ){
$scope.helloWorld = true;
});
一切都很好,花花公子,你的 hello world 元素按预期显示。现在尝试单击将 helloWorld 设置为 false 的按钮之一。您的 Sub1Ctrl 现在将如下所示:
angular.module('MyModule').controller('Sub1Ctrl', function( $scope ){
$scope.helloWorld = false;
});
但您的 MainCtrl 仍将是
angular.module('MyModule').controller('MainCtrl', function( $scope ){
$scope.helloWorld = true;
});
这是为什么呢?好吧,因为当 Angular 评估 "helloWorld = false" 时,它会在内部设置 $scope["helloWorld"] = false。问题是因为您将它设置在较低的 Sub1Ctrl 上,永远不会设置较高的控制器。
如果您将 Html 和 MainCtrl 更改为:
<div ng-controller="MainCtrl">
<div ng-show="myModel.helloWorld">Hello World</div>
<div ng-controller="Sub1Ctrl">
<button type="button" ng-click="myModel.helloWorld = false">Hide Hello World</button>
</div>
<div ng-controller="Sub2Ctrl">
<button type="button" ng-click="myModel.helloWorld = false">Hide Hello World</button>
</div>
</div>
angular.module('MyModule').controller('MainCtrl', function( $scope ){
$scope.myModel = {
helloWorld: true
}
});
然后 Angular 会在设置值之前查找对象是否存在于作用域的原型中(这是控制器通过Scope Hierarchy 继承的方式)。
所以现在 Angular 在 Sub1Ctrl 上评估“myModel.helloWorld”,最终在父 MainCtrl 上找到“myModel”,因此正确地将 helloWorld 属性设置为 false。
【讨论】:
因为您将数据保存在一个地方。例如,子范围(不是孤立范围)可以隐藏属性“消息”。所以父作用域和子作用域都有一个“消息”属性。但是如果父作用域有“data.message”属性,子作用域不能遮蔽它,除非首先在子作用域中创建一个属性“data”,然后是“data.message”,但这不是AngularJS所做的。但 AngularJS 确实在父范围内创建了第一个“数据”,然后创建了“data.message”。
【讨论】: