搜索
首页web前端js教程掌握$ Watch在Angularjs

掌握$ Watch在Angularjs

Feb 18, 2025 am 10:47 AM

Mastering $watch in AngularJS

核心要点

  • AngularJS中的$watch函数是观察变量值或表达式变化的强大工具。检测到变化时,它会触发一个回调函数,该函数会在每次被监视的变量发生变化时执行。
  • $watch使用JavaScript的相等运算符(===)进行比较。如果新值与旧值不同,则触发回调函数。但是,需要注意的是,默认情况下,$watch只检查引用相等性,这意味着只有当为被监视的变量分配新值时,才会触发回调函数。
  • AngularJS还提供$watchGroup$watchCollection作为方便的快捷方式,分别用于设置具有相同回调函数的多个监视器或监视数组或对象。但是,这些方法只执行浅监视,只对引用更改做出反应。
  • 使用$watch,尤其是在多个变量上使用,可能会影响性能,因为需要在每个摘要周期中检查所有被监视变量的变化。开发人员应根据情况考虑使用$watchGroup$watchCollection,或限制被监视变量的数量以提高性能。

本文由Mark Brown同行评审。感谢所有SitePoint的同行评审员,使SitePoint的内容达到最佳状态!

AngularJS提供了许多不同的选项,可以通过三种不同的“watch”方法使用发布-订阅模式。每种方法都采用可选参数来修改其行为。

关于$watch的官方文档远非详尽:毕竟,这是一个困扰AngularJS v1整体的问题。即使是解释如何进行的在线资源,充其量也是零散的。

因此,最终,开发人员很难为特定情况选择正确的方法。对于AngularJS初学者来说尤其如此!结果可能会令人惊讶或不可预测,这不可避免地会导致错误。

在本文中,我将假设您熟悉AngularJS概念。如果您觉得需要复习,您可能需要阅读有关$scope、绑定以及$apply$digest的内容。

检查您的理解

例如,监视数组的第一个元素的最佳方法是什么?假设我们在我们的作用域上声明了一个数组,$scope.letters = ['A','B','C']

  • 当我们向数组添加元素时,$scope.$watch('letters', function () {...});是否会触发其回调函数?
  • 当我们更改其第一个元素时,它会触发吗?
  • $scope.$watch('letters[0]', function () {...});呢?它会以相同的方式工作,还是更好?
  • 在上面,数组元素是原始值:如果我们用相同的值替换第一个元素会怎样?
  • 现在假设数组包含对象:会发生什么?
  • $watch$watchCollection$watchGroup之间有什么区别?

如果您对所有这些问题感到困惑,请继续阅读。我的目标是通过几个示例尽可能清楚地说明这一点,从而引导您完成整个过程。

$scope.$watch

让我们从$scope.$watch开始。这是所有watch功能的核心:我们将看到的每种其他方法都只是$watch的便捷快捷方式。

使用$watch

现在,Angular的优点是您可以显式地使用相同的机制在控制器中执行由数据更改触发的复杂操作。例如,您可以对某些数据设置监视器,这些数据可以响应以下内容而更改:

  1. 超时
  2. UI
  3. 由Web Worker执行的复杂异步计算
  4. Ajax调用

您可以只设置一个侦听器来处理任何数据更改,无论是什么原因造成的。

但是,要这样做,您需要自己调用$scope.$watch

实践操作

让我们看看$rootscope.watch()的代码。

这是它的签名:function(watchExp, listener, objectEquality, prettyPrintExpression)

详细来说,它的四个参数:

  1. watchExp 被监视的表达式。它可以是函数或字符串,它在每个摘要周期中都会被评估。

    这里需要注意的一个关键方面是,如果表达式被评估为函数,则该函数需要是幂等的。换句话说,对于相同的输入集,它应该始终返回相同的输出。如果不是这种情况,Angular将假设被监视的数据已更改。反过来,这意味着它将继续检测差异并在摘要周期的每次迭代中调用侦听器。

  2. listener 一个回调函数,在首次设置监视器时触发,然后在摘要周期中每次检测到watchExp值的更改时触发。设置时的初始调用旨在为表达式存储初始值。

  3. objectEquality 当且仅当此值为true时,监视器将执行深度比较。否则,它执行浅比较,即仅比较引用。

    让我们以数组为例:$scope.fruit = ["banana", "apple"]

    objectEquality == false意味着只有重新分配fruit字段才会导致调用侦听器。

    我们还需要检查“深度”比较有多深:我们稍后会讨论这一点。

  4. prettyPrintExpression 如果传递,它将覆盖监视表达式。此参数并非旨在在对$watch()的正常调用中使用;它由表达式解析器内部使用。

    小心:正如您自己所看到的,当意外传递第四个参数时,很容易出现意外的结果。

现在我们准备回答引言中的一些问题。请查看本节的示例:

CodePen 示例

请随意熟悉它们;您可以直接比较行为差异,或按照文章中的顺序进行。

监视数组

因此,您需要监视作用域上的数组以进行更改,但是“更改”是什么意思?

假设您的控制器看起来像这样:

app.controller('watchDemoCtrl', ['$scope', function($scope){
    $scope.letters = ['A','B','C'];
}]);

一种选择是使用这样的调用:

$scope.$watch('letters', function (newValue, oldValue, scope) {
    // 对 $scope.letters 执行任何操作
});

在上面的回调中,newValueoldValue具有不言自明的含义,并且每次$digest周期调用它时都会更新。scope的含义也很直观,因为它保存对当前作用域的引用。

但是,关键是:何时会调用此侦听器?事实上,您可以添加、删除、替换letters数组中的元素,而不会发生任何事情。这是因为,默认情况下,$watch假定您只想要引用相等性,因此只有当您为$scope.letters分配新值时,才会触发回调函数。

如果您需要对数组的任何元素的更改采取行动,则需要将true作为第三个参数传递给watch(即作为上面描述的可选objectEquality参数的值)。

$scope.$watch('letters', function (newValue, oldValue, scope) {
    // 对 $scope.letters 执行任何操作
}, true);

监视对象

对于对象,情况没有改变:如果objectEquality为false,您只需监视对该作用域变量的任何重新赋值,而如果为true,则每次更改对象中的元素时都会触发回调函数。

监视数组的第一个元素

值得注意的是,通过使用objectEquality === true监视数组,每次触发回调函数时,newValueoldValue将是整个数组的新旧值。因此,您必须将它们彼此进行比较才能了解实际发生了什么变化。

假设您只对数组中第一个元素(或第四个元素——原理相同)的更改感兴趣。由于Angular非常出色,它允许您这样做:您可以在作为第一个参数传递给$watch的表达式中以自然的方式表达它:

$scope.$watch('letters[4]', function (newValue, oldValue, scope) {
    //...
}, true);

如果数组只有2个元素会怎样?没问题,除非您添加第四个元素,否则您的回调函数不会被触发。好吧,好的,从技术上讲,它会在您设置监视器时触发,然后只有在您添加第四个元素时才会触发。

如果您记录oldValue,您会看到在这两种情况下它都将是未定义的。将此与监视现有元素时发生的情况进行比较:在设置时,您仍然有oldValue == undefined。所以$watch无法处理!

现在一个更有趣的问题:我们在这里需要传递objectEquality === true吗?

简短的回答:对不起,没有简短的回答。

这确实取决于:

  • 在此示例中,由于我们正在处理原始值,因此我们不需要深度比较,因此我们可以省略objectEquality
  • 但是,假设我们有一个矩阵,例如$scope.board = [[1, 2, 3], [4, 5, 6]];,并且我们想监视第一行。然后我们可能希望在像$scope.board[0][1] = 7这样的赋值更改它时收到警报。

监视对象的字段

也许比监视数组中的任意元素更有用的是,我们可以监视对象中的任意字段。但这并不奇怪,对吧?毕竟,JavaScript中的数组对象。

app.controller('watchDemoCtrl', ['$scope', function($scope){
    $scope.letters = ['A','B','C'];
}]);

深度比较有多深?

在这一点上,我们还需要阐明最后一个但至关重要的细节:如果我们需要监视一个复杂的嵌套对象,其中每个字段都是非原始值,会发生什么?例如树或图,或者只是一些JSON数据。

让我们检查一下!

首先,我们需要一个要监视的对象:

$scope.$watch('letters', function (newValue, oldValue, scope) {
    // 对 $scope.letters 执行任何操作
});

让我们为整个对象设置监视器:我认为,到目前为止,很清楚的是,在这种情况下必须将objectEquality设置为true

$scope.$watch('letters', function (newValue, oldValue, scope) {
    // 对 $scope.letters 执行任何操作
}, true);

问题是:如果像$scope.b.bb[1].bb2a = 7;这样的赋值发生,Angular是否会足够好心地让我们知道?

答案是:是的,幸运的是,它会(在之前的CodePen演示中查看)。

其他方法

$scope.$watchGroup

$watchGroup()真的是一种不同的方法吗?答案是否定的,它不是。

$watchGroup()是一个方便的快捷方式,允许您使用相同的回调函数设置多个监视器,并传递一个watchExpressions数组。

每个传递的表达式都将使用标准$scope.$watch()方法进行监视。

$scope.$watch('letters[4]', function (newValue, oldValue, scope) {
    //...
}, true);

值得注意的是,使用$watchGroupnewValuesoldValues将保存表达式的值列表,包括发生更改的值和保持相同值的那些值,顺序与它们在第一个参数的数组中传递的顺序相同。

如果您检查了此方法的文档,您可能会注意到它没有采用objectEquality选项。这是因为它浅监视表达式,并且只对引用更改做出反应。

如果您使用下面的$watchGroup()演示进行操作,您可能会对一些细微之处感到惊讶。例如,unshift将导致调用侦听器,至少在某种程度上是这样:这是因为当将表达式列表传递给$watchGroup时,任何一个表达式触发都会导致执行回调函数。

CodePen 示例

此外,请注意,$scope.obj.b的任何子字段的任何更改都不会产生任何更新——只有为b字段本身分配新值才会产生更新。

$scope.$watchCollection

这是监视数组或对象的另一个便捷快捷方式。对于数组,当替换、删除或添加任何元素时,将调用侦听器。对于对象,当更改任何属性时。同样,$watchCollection()不允许objectEquality,因此它只会浅监视元素/字段,并且不会对它们的子字段的更改做出反应。

CodePen 示例

结论

希望这些示例能帮助您发现此Angular功能的强大功能,并了解使用正确的选项有多么重要。

随意复制CodePen并尝试在不同的上下文中使用这些方法,并且不要忘记在评论区留下您的反馈!

如果您想更深入地了解我们在本文中讨论的一些概念,以下是一些进一步阅读的建议:

  1. AngularJS作用域
  2. 理解Angular的$apply()$digest()
  3. JavaScript事件处理中的新兴模式
  4. AngularJS作用域中的原型继承
  5. $watch等的文档

关于在AngularJS中掌握$watch的常见问题解答 (FAQ)

$watch在AngularJS中的主要目的是什么?

AngularJS中的$watch函数主要用于观察变量或表达式的值的变化。它是AngularJS作用域对象的一部分,用于监视变量或表达式的值的变化。检测到变化时,$watch函数会触发一个回调函数,该函数会在每次被监视的变量发生变化时执行。

$watch在AngularJS中是如何工作的?

AngularJS中的$watch函数通过比较被监视变量或表达式的旧值和新值来工作。它使用JavaScript的相等运算符(===)进行比较。如果新值与旧值不同,$watch函数将触发回调函数。

我如何在AngularJS中使用$watch

要在AngularJS中使用$watch,您需要在作用域对象上调用$watch方法,并向其传递两个参数:要监视的变量或表达式的名称,以及在被监视的变量发生变化时要执行的回调函数。这是一个示例:

app.controller('watchDemoCtrl', ['$scope', function($scope){
    $scope.letters = ['A','B','C'];
}]);

$watch$apply在AngularJS中的区别是什么?

AngularJS中的$watch函数用于观察变量或表达式的变化,而$apply函数用于手动启动AngularJS摘要周期,该周期会检查被监视变量的任何变化并相应地更新视图。$apply函数通常在AngularJS上下文之外进行模型更改时使用,例如在DOM事件处理程序或setTimeout函数中。

我可以使用$watch在AngularJS中监视多个变量吗?

是的,您可以使用$watch在AngularJS中监视多个变量。您可以通过将变量名称数组传递给$watch函数来实现此目的。但是,请记住,监视多个变量可能会影响性能,因为$watch函数需要在每个摘要周期中检查所有被监视变量的变化。

我如何在AngularJS中停止监视$watch中的变量?

当您在AngularJS中调用$watch函数时,它会返回一个注销函数。您可以调用此函数来停止监视变量。这是一个示例:

$scope.$watch('letters', function (newValue, oldValue, scope) {
    // 对 $scope.letters 执行任何操作
});

AngularJS中的$watchGroup是什么?

AngularJS中的$watchGroup函数用于监视一组表达式。它的工作方式类似于$watch函数,但它只在每个摘要周期触发一次回调函数,即使多个被监视的表达式发生了变化也是如此。这可以在监视多个表达式时提高性能。

AngularJS中的$watchCollection是什么?

AngularJS中的$watchCollection函数用于监视对象的属性或数组的元素。只要任何属性或元素发生变化,它就会触发回调函数,但与$watch不同,它不会深度监视对象或数组,这可以提高性能。

我可以在AngularJS指令中使用$watch吗?

是的,您可以在AngularJS指令中使用$watch。事实上,在指令中使用$watch来响应指令的属性或作用域变量的变化是一种常见的做法。

使用$watch在AngularJS中有哪些性能方面的考虑?

使用$watch在AngularJS中可能会影响性能,尤其是在监视许多变量或表达式时。这是因为$watch函数需要在每个摘要周期中检查所有被监视变量的变化。为了提高性能,请根据情况考虑使用$watchGroup$watchCollection,或限制被监视变量的数量。

以上是掌握$ Watch在Angularjs的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
Python vs. JavaScript:您应该学到哪种语言?Python vs. JavaScript:您应该学到哪种语言?May 03, 2025 am 12:10 AM

选择Python还是JavaScript应基于职业发展、学习曲线和生态系统:1)职业发展:Python适合数据科学和后端开发,JavaScript适合前端和全栈开发。2)学习曲线:Python语法简洁,适合初学者;JavaScript语法灵活。3)生态系统:Python有丰富的科学计算库,JavaScript有强大的前端框架。

JavaScript框架:为现代网络开发提供动力JavaScript框架:为现代网络开发提供动力May 02, 2025 am 12:04 AM

JavaScript框架的强大之处在于简化开发、提升用户体验和应用性能。选择框架时应考虑:1.项目规模和复杂度,2.团队经验,3.生态系统和社区支持。

JavaScript,C和浏览器之间的关系JavaScript,C和浏览器之间的关系May 01, 2025 am 12:06 AM

引言我知道你可能会觉得奇怪,JavaScript、C 和浏览器之间到底有什么关系?它们之间看似毫无关联,但实际上,它们在现代网络开发中扮演着非常重要的角色。今天我们就来深入探讨一下这三者之间的紧密联系。通过这篇文章,你将了解到JavaScript如何在浏览器中运行,C 在浏览器引擎中的作用,以及它们如何共同推动网页的渲染和交互。JavaScript与浏览器的关系我们都知道,JavaScript是前端开发的核心语言,它直接在浏览器中运行,让网页变得生动有趣。你是否曾经想过,为什么JavaScr

node.js流带打字稿node.js流带打字稿Apr 30, 2025 am 08:22 AM

Node.js擅长于高效I/O,这在很大程度上要归功于流。 流媒体汇总处理数据,避免内存过载 - 大型文件,网络任务和实时应用程序的理想。将流与打字稿的类型安全结合起来创建POWE

Python vs. JavaScript:性能和效率注意事项Python vs. JavaScript:性能和效率注意事项Apr 30, 2025 am 12:08 AM

Python和JavaScript在性能和效率方面的差异主要体现在:1)Python作为解释型语言,运行速度较慢,但开发效率高,适合快速原型开发;2)JavaScript在浏览器中受限于单线程,但在Node.js中可利用多线程和异步I/O提升性能,两者在实际项目中各有优势。

JavaScript的起源:探索其实施语言JavaScript的起源:探索其实施语言Apr 29, 2025 am 12:51 AM

JavaScript起源于1995年,由布兰登·艾克创造,实现语言为C语言。1.C语言为JavaScript提供了高性能和系统级编程能力。2.JavaScript的内存管理和性能优化依赖于C语言。3.C语言的跨平台特性帮助JavaScript在不同操作系统上高效运行。

幕后:什么语言能力JavaScript?幕后:什么语言能力JavaScript?Apr 28, 2025 am 12:01 AM

JavaScript在浏览器和Node.js环境中运行,依赖JavaScript引擎解析和执行代码。1)解析阶段生成抽象语法树(AST);2)编译阶段将AST转换为字节码或机器码;3)执行阶段执行编译后的代码。

Python和JavaScript的未来:趋势和预测Python和JavaScript的未来:趋势和预测Apr 27, 2025 am 12:21 AM

Python和JavaScript的未来趋势包括:1.Python将巩固在科学计算和AI领域的地位,2.JavaScript将推动Web技术发展,3.跨平台开发将成为热门,4.性能优化将是重点。两者都将继续在各自领域扩展应用场景,并在性能上有更多突破。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

螳螂BT

螳螂BT

Mantis是一个易于部署的基于Web的缺陷跟踪工具,用于帮助产品缺陷跟踪。它需要PHP、MySQL和一个Web服务器。请查看我们的演示和托管服务。

EditPlus 中文破解版

EditPlus 中文破解版

体积小,语法高亮,不支持代码提示功能

WebStorm Mac版

WebStorm Mac版

好用的JavaScript开发工具

安全考试浏览器

安全考试浏览器

Safe Exam Browser是一个安全的浏览器环境,用于安全地进行在线考试。该软件将任何计算机变成一个安全的工作站。它控制对任何实用工具的访问,并防止学生使用未经授权的资源。