如何在JavaScript中查看函数返回值

时间:2014-04-06 18:51:53

标签: javascript angularjs function watch

在浏览器中,对于对象,属性具有其getter和setter。我们可以覆盖它们来观察属性。函数的返回值怎么样? 在AngularJS中,使用  ng-show'控制组件的可见性。它可以这样写:

<ANY ng-show="aFunction()"> ... </ANY>

该功能可以定义为:

var tmp = false;
$scope.aFunction = function() { return tmp; };

如果在运行时,&#39; tmp&#39;变为真,&lt;任何&gt;会出现。 AngularJS如何知道返回值是否已更改?是否有定时检查更改的超时功能?

2 个答案:

答案 0 :(得分:2)

没有超时功能。有一种特定于AngularJS的概念,称为“消化循环” 您可以从文档中了解有关 scope life-cycle 的更多信息 我还发现 this article 对于这种机制的介绍非常有用 最后,我相信这里有很多相关的答案。

一般情况下,您应该尝试确切了解$apply()$digest()$watch()的功能。

答案 1 :(得分:1)

没有魔法或超时,Angular理解某些东西(包括函数返回值)被更改的方式是每次运行摘要循环时执行脏检查。要了解它是如何工作的,让我们看看你的例子,看看Angular为你做的步骤,以及你如何告诉Angular有些事情发生了变化。

第1步:创建观看

如果我们查看ngShowDirective的源代码,我们会看到以下内容

var ngShowDirective = ['$animate', function($animate) {
  return function(scope, element, attr) {
    scope.$watch(attr.ngShow, function ngShowWatchAction(value){ // <= create watch
      $animate[toBoolean(value) ? 'removeClass' : 'addClass'](element, 'ng-hide');
    });
  };
}];

scope.$watch()的第一个参数是一个表达式,它取自DOM元素的ng-show属性,并编译为一个函数,该函数在监视值被更改时返回true。由于传递的是一个函数 - Angular将运行它以获取新值。

第2步:订阅DOM事件并运行摘要循环

Angular订阅了许多DOM事件,以便运行摘要循环并检查每次浏览器中发生某些事情时是否更改了某些内容。例如,让我们来看看Angular在浏览器触发hashchange事件时所做的事情:

$browser.onUrlChange(function(newUrl) {
  if ($location.absUrl() != newUrl) {
    $rootScope.$evalAsync(function() {
      var oldUrl = $location.absUrl();

      $location.$$parse(newUrl);
      if ($rootScope.$broadcast('$locationChangeStart', newUrl,
                                oldUrl).defaultPrevented) {
        $location.$$parse(oldUrl);
        $browser.url(oldUrl);
      } else {
        afterLocationChange(oldUrl);
      }
    });
    if (!$rootScope.$$phase) $rootScope.$digest(); // <= run digest loop if it is not already running
  }
});

第3步:在手表更改的情况下运行所有​​手表并致电回调

Scope.prototype = {
  ...
  $digest: function() {
    ...
    if ((value = watch.get(current)) !== (last = watch.last) &&
                    !(watch.eq
                        ? equals(value, last)
                        : (typeof value == 'number' && typeof last == 'number'
                           && isNaN(value) && isNaN(last)))) {
      ...
      watch.fn(value, ((last === initWatchVal) ? value : last), current); // <= run watch callback function in case watch value has been changed
      ...
    }
    ...
  }
}

就是这样,这就是Angular如何知道何时使<ANY ng-show="aFunction()"> ... </ANY>可见。

在大多数常见情况下,Angular会为您完成所有这些工作,但是在某些情况下Angular不知道某些内容发生了变化。例如,在Angular的范围之外更改值时会自动创建监视。在这些情况下,您应该注意自己致电scope.$digest()scope.$apply()。最常见的情况之一是在指令的事件侦听器中更改范围属性值:

angular.module('demo').directive('clickable', function() {
  return {
    link: function(scope, element) {
      element.bind('click', function() {
        scope.$apply(function() { // <= call scope.$apply() in order to tell Angular that something is changed in the scope
          scope.foo++;
        });
      });
    }
  }
});

$apply()调用$digest()之外,建议使用$apply()回调函数。通过这种方式,Angular会知道在范围更改期间是否出现了问题,如果有任何问题,将会处理错误。

希望有助于理解Angular如何了解范围的变化。

在Angular之外观察函数返回值

如果您想利用Angular在Angular的应用程序代码之外观察函数返回值的功能,您可以执行以下操作:

  1. 获取应用程序的顶级元素
  2. 获取Angular的$rootScope
  3. 使用$watch()
  4. 观看更改

    示例:

    var valueToBeChanged = 0,
        rootElement = document.querySelector('[ng-app]'),
        rootScope = angular.element(rootElement).scope();
    
    function myFunc() {
      return valueToBeChanged;
    }
    
    function myCallback() {
      console.log('Value have been changed!');
    }
    
    rootScope.$watch(myFunc, myCallback);
    
    angular.element(document.querySelector('body')).on('click', function() {
      rootScope.$apply(function() {
        valueToBeChanged++;
      });
    });
    

    Plunker:http://plnkr.co/edit/LRK08EsP0jrOu9n42VwB?p=preview