Freewind @ Thoughtworks scala java javascript dart 工具 编程实践 月结 math python english [comments admin] [feed]

(2013-01-01) 05. 表达式

广告: 云梯:翻墙vpn (省10元) 土行孙:科研用户翻墙http proxy (有优惠)

表达式(Expressions)是与javascript相似的代码片断。虽然相似,但并不完全与javascript相同,也不是由javascript引擎直接执行的。所以某些javascript语法并不能直接在angularjs的表达式中使用。

表达式通常放在binding中,比如{{expression}}

表达式由$parse服务处理。

下面是几种合法的angularjs表达式:

Angular Expressions vs. JS Expressions

把angularjs的表达式当成javascript表达式是一件很诱人的事情,可惜这不完全正确,因为它不是用Javascript的eval()来执行的。

它们之间有以下几点区别:

另外,如果你想运行Javascript代码,你必须在controller中新建一个方法,然后在angularjs表达式中调用它。如果你想在Javascript中执行angularjs表达式,可使用由angularjs提供的$eval()方法。

例子

index.html

<!doctype html>
<html ng-app>
  <head>
    <script src="http://code.angularjs.org/angular-1.0.1.min.js"></script>
  </head>
  <body>
    1+2={{1+2}}
  </body>
</html>

End to end test

it('should calculate expression in binding', function() {
expect(binding('1+2')).toEqual('3');
});

jsfiddle link?

你可以在下面的示例中尝试不同的表达式(需要到相应的jsfiddle页面上):

index.html

<!doctype html>
<html ng-app>
  <head>
    <script src="http://code.angularjs.org/angular-1.0.1.min.js"></script>
    <script src="script.js"></script>
  </head>
  <body>
    <div ng-controller="Cntl2" class="expressions">
      Expression:
      <input type='text' ng-model="expr" size="80"/>
      <button ng-click="addExp(expr)">Evaluate</button>
      <ul>
       <li ng-repeat="expr in exprs">
         [ <a href="" ng-click="removeExp($index)">X</a> ]
         <tt>{{expr}}</tt> => <span ng-bind="$parent.$eval(expr)"></span>
        </li>
      </ul>
    </div>
  </body>
</html>

script.js

function Cntl2($scope) {
  var exprs = $scope.exprs = [];
  $scope.expr = '3*10|currency';
  $scope.addExp = function(expr) {
     exprs.push(expr);
  };

  $scope.removeExp = function(index) {
    exprs.splice(index, 1);
  };
}

End to end test

it('should allow user expression testing', function() {
   element('.expressions :button').click();
   var li = using('.expressions ul').repeater('li');
   expect(li.count()).toBe(1);
   expect(li.row(0)).toEqual(["3*10|currency", "$30.00"]);
});

jsfiddle link

属性求值

属性的求值发生在scope上。在Javascript中,属性名默认是在全局的window对象上,在angular表达式中,使用$window对象来引用全局window对象。比如,你想调用alert(),在angularjs中就必须使用$window.alert()。这么做是为了防止我们的代码意外访问了全局状态,容易引起bug。

示例源代码

index.html

<!doctype html>
<html ng-app>
  <head>
    <script src="http://code.angularjs.org/angular-1.0.1.min.js"></script>
    <script src="script.js"></script>
  </head>
  <body>
    <div class="example2" ng-controller="Cntl1">
      Name: <input ng-model="name" type="text"/>
      <button ng-click="greet()">Greet</button>
    </div>
  </body>
</html>

script.js

function Cntl1($window, $scope){
  $scope.name = 'World';

  $scope.greet = function() {
    ($window.mockWindow || $window).alert('Hello ' + $scope.name);
  }
}

End to end test

it('should calculate expression in binding', function() {
  var alertText;
  this.addFutureAction('set mock', function($window, $document, done) {
    $window.mockWindow = {
      alert: function(text){ alertText = text; }
    };
    done();
  });
  element(':button:contains(Greet)').click();
  expect(this.addFuture('alert text', function(done) {
    done(null, alertText);
  })).toBe('Hello World');
});

jsfiddle link ?

空值友好

表达式对于undefinednull是友好的。在Javascript中,对于表达式a.b.c,如果a不是一个对象,则会抛出异常。虽然这么做对于一个通用语言来说是很有意义的,但对于表达式求值这种主要用来绑定数据的用法来说,意义不大而且很繁琐。

因为我们经常会写下这样的代码:

{{a.b.c}}

aundefined的时候(可能我们正在等服务器端返回数据),什么也不显示通常更有意义一些。如果我们不这么处理,上面的代码就必须写成这种让人头晕的形式:

{{((a||{}).b||{}).c}}

同样,调用一个undefinednull上的函数,如a.b.c(),也会简单地返回undefined.

没有控制语句

在angularjs表达式中,不能使用如条件判断、循环或抛异常这种控制语句。主要原因是这种通常与业务逻辑相关的代码,应该放在controller中,而不是view中。

如果你的确需要,可以在controller中定义一个javascript函数,再在angularjs表达式中调用它。

过滤器 Filters

name | uppercase

name的值将会直接传给uppercase这个filter.

Filter还可以串起来:

value | filter1 | filter2

你可还以使用冒号:向filter传参数。比如,把数字123显示为两个小数点的形式:

123 | number:2

The $

你可能会注意到,有一些对象或者方法,它们以$开头,是什么意思?这是一个默认约定,由angularjs提供的api以$开头,与其它相区别。

所以我们在定义变量或者函数时,不要使用$开头,以免跟angularjs冲突。

comments powered by Disqus