AngularJS中$scope的变量作用域是如何工作的?

3

我是一个angular JS的初学者,在教程中找到了这段代码。

var phonecatApp = angular.module('phonecatApp', []);

phonecatApp.controller('PhoneListCtrl', function($scope) {
  $scope.phones = [
    {'name': 'Nexus S',
     'snippet': 'Fast just got faster with Nexus S.'},
    {'name': 'Motorola XOOM™ with Wi-Fi',
     'snippet': 'The Next, Next Generation tablet.'},
    {'name': 'MOTOROLA XOOM™',
     'snippet': 'The Next, Next Generation tablet.'}
  ];
});

这段代码工作得很好,但我想知道$scope变量的作用域是如何工作的。从代码中看,$scope似乎是一个局部变量,其作用域仅限于函数内部。
那么为什么我不能更改$scope变量的名称呢?如果我在函数内部所有出现的地方都更改变量名,它似乎无法正常工作。

$scope 是您保存要向用户显示的值和函数的位置。您想要绑定到元素的任何内容都添加到 $scope 中。如果您想要了解更多关于这个的信息,请阅读有关 digest cycle 的内容。令我惊讶的是,当变量 $scope 的名称更改时,代码似乎不起作用。这是因为 Angular 在各个地方都使用依赖注入。 - Zack Patterson
我的疑惑比较偏向于 JavaScript 而不是 AngularJS。$scope 变量的值如何在函数块外获得?它没有返回 $scope,也不是全局变量。 - M S
在 Angular 或控制器函数之外? - squiroid
3个回答

2

来自 AngularJS 文档:

作用域是应用控制器和视图之间的粘合剂... 控制器和指令都有对作用域的引用,但没有 相互引用。

$scope 是由 Angular 创建并通过引用(依赖注入)注入到您的控制器函数中。

想象一下这个简单的 JavaScript 示例,然后将您的思路扩展到 AngularJS。

(function() {
     // var myscope is not global. it's in the closure
     // of my anonymous function
     var myscope = {
        "samplekey" : "samplevalue"
     }

     // .... You can do anything with scope

     // Imagine this function as your controller
     function myController($scope) {
        // Here I can work with $scope variable
        $scope.data = { "anotherkey" : "anothervalue" };
        console.log($scope.samplekey); // It works fine
     }

     // inject myscope into the controller function
     myController(myscope);

     // I can access the new property added to myscope variable
     // by the controller function (maybe I can use it in a view).  
     console.log(myscope.data.anotherkey); // anothervalue 

}());

在AngularJS中,您可以使用任何变量作为作用域。但是,您必须指定您创建的变量正在引用作用域变量。

phonecatApp.controller('PhoneListCtrl',['$scope', function(varAsScope) {
  varAsScope.phones = [
    {'name': 'Nexus S', 'snippet': 'Fast just got faster with Nexus S.'},
    {'name': 'Motorola XOOM™ with Wi-Fi', 'snippet': 'The Next, Next Generation tablet.'},
    {'name': 'MOTOROLA XOOM™', 'snippet': 'The Next, Next Generation tablet.'}
  ];
}]);

这是一个工作示例,与IT技术有关。

我的疑问更多地涉及 JavaScript 而非 AngularJS。如何在函数块之外获取变量 $scope 的值?它不会返回 $scope,而且 $scope 也不是全局的。 - M S
我已经更新了我的答案,试图解释Angular如何将作用域变量注入到您的控制器中。 - nanndoj
如果我在您的函数内更改变量$scope的名称,它仍然可以正常工作。但在Angular中,它不起作用。这就是我的疑问。为什么我不能在AngularJS中更改函数作用域内的变量名呢? - M S
请问你能否将代码反过来写呢?也就是说,你能不能让你的代码中的$scope变量不可修改?或者如果我在你的代码中修改了$scope变量,它会有不同的效果吗? - M S

2
Angular使用依赖注入。$scope是一个被注入的值。它本质上是一个对象,包含该模块相对控制器内所有ng-引用。
“模块是服务、指令、控制器、过滤器和配置信息的集合。”——来自Angular源代码的引述。
当您从模块中的集合访问某些内容时,该访问的范围会被注入。例如,创建模块时,模块会创建一个控制器属性。
/**
* @ngdoc method
* @name angular.Module#controller
* @module ng
* @param {string|Object} name Controller name, or an object map of controllers where the
 *    keys are the names and the values are the constructors.
 * @param {Function} constructor Controller constructor function.
 * @description
 * See {@link ng.$controllerProvider#register $controllerProvider.register()}.
 */
 controller: invokeLater('$controllerProvider', 'register'),

这个属性已经在controllerProvider中注册。

该控制器是可注入的(并支持方括号表示法),可以使用以下本地变量:
*
* * $scope - 与该元素相关联的当前作用域

因此,当您使用此代码时:

phonecatApp.controller('PhoneListCtrl', function($scope){

你所做的是从控制器提供者访问'PhoneListCtrl控制器,然后调用与存储在该模块中的PhoneListCtrl相关联的作用域的函数。关于变量名$scope,Angular能够判断你是否使用了这个“关键字”的原因是通过正则表达式处理。如果你在一个函数上使用.toString(),它会将整个函数转换为字符串,然后你可以解析它来查看函数中的内容。Angular就是这样做的,“最简单的形式是从函数的参数中提取依赖项。这是通过使用.toString()方法将函数转换为字符串并提取参数名称来完成的。” 正则表达式在Angular中定义为var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m; 你可以在https://regex101.com/r/qL4gM8/1测试它。所以这就是Angular如何知道你在函数参数中使用了变量$scope的方式。

1
你回答的最后一部分解决了我的疑惑。非常感谢。 - M S
1
@MS,补充一下Travis的回答。这种函数参数的正则匹配无法经受代码压缩,因此在压缩代码时需要显式注释 - New Dev

0

Angular 中以“$”开头的所有内容都是服务,其中 scope 也是绑定视图和控制器的服务,允许您使用 双向绑定

是的,$scope 仅限于特定组件,我们可以说是指令或控制器。但是,我们也有 $rootScope 的父级。

因此,您可以将 $rootScope 用作全局内容的服务。

希望它解决了您的疑惑。

以下是一些有用的链接:

Github(最佳资源)

Doc


我的疑问更多涉及JavaScript而非Angular。如何在函数块外部获取变量$scope的值?它没有返回$scope,$scope也不是全局的。 - M S
在Angular之外还是只使用单个控制器? - squiroid
如果你从 Angular 的内部调用函数,可以将简单的 $scope 作为变量发送到其他函数。例如,如果我想要调用 add() 函数,我可以像这样调用 add($scope),并发送简单的 scope 并提取其值 :-) - squiroid
1
我不确定你是否理解我的问题。假设我们有一个函数function fun(a){ a = "Hello"},那么变量a的值无法在函数范围之外获得。但在所示的示例中,值是在函数外部获取的。此外,在函数内部,变量名并不重要。即function fun(b){b="Hello'}也应该可以工作。但在上面的示例中,如果我们将$scope更改为函数内所有位置上的$scope2,则似乎不起作用。 - M S

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接