Angular2以Web Component组件来构建应用,一个组件包括:业务逻辑、模板、样式等。同一业务逻辑可以根据不同的模板和样式来渲染,比如同一逻辑可能需要:大小屏幕、微信端上展示但只不过是渲染不同而已。

Angular2通过注解(Annotation)的形式来确认所需要的模板、样式信息。我会努力的解释为什么如何使用注释以及原由,以及装饰器(Decorator)又是什么鬼?

注解(Annotation)

任何通过Angular2 快速入门开始Angular2,都会看到这么一段代码:

@Component({
    selector: 'my-app',
    template: '<h1>My First Angular 2 App</h1>'
})
export class AppComponent { }

我们看到有一个 AppComponent 空类,同时该类包括一个 @Component 注解,假如我们移除注解那么类就变成完全没有任何意义了。@Component 告诉Angular这个类以什么形式与该组件连接。selector 表明连接位置,是一个CSS选择器;template 表明渲染的内容,现在是一段HTML代码。

这看起来非常简单,但是我们需要理解几个问题:

  • 这些注解从哪来?JavaScript如何解析它?
  • 为什么是 @Component,谁来定义它?
  • 如果这是TypeScript特有的,那么现流行浏览器是怎么支持和解释它们?

首先要回答第一个问题。我们需要完成上面的示例代码,定义一个组件之间需要先从Angular2框架导入 Component,例如:

import {Component} from 'angular2/core';

源代码可以查看他实现定义:

export class ComponentMetadata extends DirectiveMetadata { }

可以从源代码库中查找到所有Angular2所提供的注解的具体实现细节。这也间接回答我们第二个问题。既然定义由Angular2来做,那么怎么去解析这些带有 @ 符号的特殊语言呢?事实目前浏览器还不能直接支持并解析它,虽然注解有可能成为ES7标准,这还是相当长的路要走;所以我们还是需要借助解析器。

解析器的选择非常多,比如有名的Babel、Traceur、TypeScript都可以来解析注解。上面代码被TypeScript解析成:

AppComponent = (function () {
    function AppComponent() {
    }
    AppComponent = __decorate([
        core_1.Component({
            selector: 'my-app',
            template: '<h1>My First Angular 2 App</h1>'
        }), 
        __metadata('design:paramtypes', [])
    ], AppComponent);
    return AppComponent;
}());

最后我们看到他被编译成一个函数,而且这里的 @Component 实则变成具体的函数调用 core_1.Component()。事实上,Angular2已经把 @Component 等相关的注解做了定义和具体实现,最终并交由编译器解析。注解并没有什么特殊之处,我们完全可以单纯理解为语法糖,从Web组件的结构上来看,注解解决我们最核心的解耦问题。

然而,注解中的参数值是由我们 @Component 直接定义好的,那么问题来了,假如我想在执行中改变这些值怎么办?这个可以交由装饰器来解决。

装饰器(Decorators)

一个简单的装饰器,看起来像这样子:

@decoratorExpression
class MyClass { }

这个感觉就跟注解一个样,但是从开发的角度来讲完全不一样。一个完成的装饰器还需要包括对 decoratorExpression 的具体实现:

function decoratorExpression(target) {
   target.annotated = true;
}

修饰器的第一个参数 target 就是所要修饰的目标类,我们可以通过target来修改、添加属性、方法等等操作。

结论

注解和修饰器从语法层面完全是一样的,而唯一不同的是注解我们无法过多参与控制行为能力;修饰器则不然。虽然最后都是以注解(也可以说是修饰符,因为对于ES6而言它已经是标准了)被编译。当然了,Angular2所提供的相应注解可以让我们更专注于业务层面开发。

注解的实在太优雅了!