为什么我不能像这样覆盖变量的值?

Why can't I overwrite the value of a variable like this?

我想弄清楚为什么我无法覆盖通过隔离范围 (@) 传递给 angularJS 指令的值。我尝试用以下内容覆盖 vm.index 的值:

vm.index = parseInt(vm.index, 10)

但是,由于某些原因,它不起作用。

如果我把它改成:

vm.newIndex = parseInt(vm.index, 10)

有效。此外,在 $scope 上分配值也有效。

为什么第一种方法不起作用?

我创建了这个 example plunker 以供参考。

显然它与范围 index 值的单向绑定有关。所以 Angular 不会更新 scope.index(或 this.index,如果是 bindToController: true),因为范围配置为

scope: {
    index: '@'
},

如果将其更改为双向绑定,例如:

scope: {
    index: '='
},

它将起作用:

<some-directive index="$index"></some-directive>

演示: http://plnkr.co/edit/kq16cpk7gyw8IE7HiaQL?p=preview

UPD。 @pankajparkar 提出了一个很好的观点,即在下一个摘要中更新值解决了这个问题。这种解决问题的方法比我在这个答案中所做的更接近。

正如您在此处使用的 @ 一样,它需要来自具有 {{}} 插值指令的属性的值。似乎指令首先被加载,然后 vm.index 值被评估。因此,更改不会发生在当前的摘要周期中。如果你想让那些被反映出来,你需要 运行 使用 $timeout 以更安全的方式消化循环。

$timeout(function(){
  vm.index = parseInt(vm.index, 10)
})

以上是确保将值转换为十进制值。添加将发生在指令 html <h2>Item {{ vm.index + 1 }}</h2>

Working Demo

这背后的可能原因

根据@dsfq 和我的讨论,我们经历了 angular $compile API, & found that their is one method call initializeDirectiveBindings ,只有当我们在具有隔离范围的指令中使用 controllerAs 时才会调用它。在这个函数中有各种绑定 @,=& 的切换案例,所以当你使用 @ 时,这意味着调用切换案例代码后的一种绑定方式.

代码

case '@':
    if (!optional && !hasOwnProperty.call(attrs, attrName)) {
        destination[scopeName] = attrs[attrName] = void 0;
    }
    attrs.$observe(attrName, function(value) {
        if (isString(value)) {
            destination[scopeName] = value;
        }
    });
    attrs.$$observers[attrName].$$scope = scope;
    if (isString(attrs[attrName])) {
        // If the attribute has been provided then we trigger an interpolation to ensure
        // the value is there for use in the link fn
        destination[scopeName] = $interpolate(attrs[attrName])(scope);
    }
    break;

在上面的代码中,您可以清楚地看到他们放置了 attrs.$observe,这是一种观察者,通常在值带有插值时使用,就像在我们的例子中一样 {{index}},这意味着这个 $observe 在摘要循环 运行 时得到评估,这就是为什么你需要在 index 值作为 decimal.[=33= 时放置 $timeout ]

@dsfq 的回答之所以有效,是因为他使用 = 提供了两种绑定方式,代码不会让观察者直接从隔离范围 here is the code 中获取值。因此,如果没有摘要循环,该值就会更新。