Angular 个人深究【Angular中的Typescript 装饰器】

最近进入一个新的前端项目,为了能够更好地了解Angular框架,想到要研究底层代码。


注:本人前端小白一枚,文章旨在记录自己的学习过程,如有大神发现错误,也请评论指正。

Angular 中的装饰器

当安装好Angular后,打开 文件[/my-app/src/app/app.module.ts] 与文件 [/my-app/src/app/app.component.ts]

//app.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
}) export class AppComponent { title = 'app';
}
//app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { AppComponent } from './app.component';
import { Test1Component } from './test1/test1.component';
import { Test2Component } from './test2/test2.component'; @NgModule({
declarations: [
AppComponent,
Test1Component,
Test2Component
],
imports: [
BrowserModule,
FormsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }

两个文件中的@Component与 @Ngmodule 就是我们今天要说的typescript的装饰器的用法。

Typescript装饰器的由来

1) 经过查询资料,装饰器的概念来自于Python(本人Python也是小白)

def decorator(target):
print("You are decorated!")
return targett
#decorator是可以自定义的
@decorator
def yourfunction:
print("This is your function!")
yourfunction() #一下是运行结果
#You are decorated!
#This is your function! #网上还有分析,以上的代码的等价写法有助于理解。

2) ES6 引入了装饰器这个功能。

3) Angular 中 装饰器的测试

注:查询网上说Nodejs 与 Typescript都能支持装饰器,但是本人没有调试成功,以后扩展。

  •   装饰【类】的装饰器:

//test1.component.ts
import { Component, OnInit } from '@angular/core';
function test (target) {
console.log(target);
target.title = "app1";
return target;
}
//装饰一个类
@test
@Component({
selector: 'app-test1',
templateUrl: './test1.component.html',
styleUrls: ['./test1.component.css']
})
export class Test1Component implements OnInit {
title = 'app';
constructor() {}
ngOnInit() {}
}
console.log(Test1Component.title); //输出结果是app1
  •   装饰【类的方法、属性】的装饰器

import { Component, OnInit } from '@angular/core';

function readonly(flag:boolean){
return function readonly(target, name, descriptor) {
console.log(descriptor);
descriptor.writable = flag;
return descriptor;
}
}
export class Test1Component implements OnInit {
ngOnInit() {
this.test = function(){console.log("change")};
}
@readonly(false)
test(){
console.log("inner test function");
}
}
//控制台报错:ERROR TypeError: Cannot assign to read only property 'test' of object '[object Object]'
//打印的descriptor {value: ƒ, writable: true, enumerable: true, configurable: true}
/* 属性与方法都是一样的 */

Angular中的装饰器解读

  • 【NgModule 装饰器】

代码位置:node_modules\@angular\core\fesm5\core.js line1436(直接搜索var NgModule =)

/**
* NgModule decorator and metadata.
*
*
* @Annotation
*/
var NgModule = makeDecorator('NgModule', function (ngModule) { return ngModule; }, undefined, undefined, function (moduleType, metadata) {
var imports = (metadata && metadata.imports) || [];
if (metadata && metadata.exports) {
imports = __spread(imports, [metadata.exports]);
}
moduleType.ngInjectorDef = defineInjector({
factory: convertInjectableProviderToFactory(moduleType, { useClass: moduleType }),
providers: metadata && metadata.providers,
imports: imports,
});
});

格式:

@NgModule({
providers: Provider[]//Defines the set of injectable objects that are available in the injector of this module.
declarations: Array<Type<any> | any[]>//Specifies a list of directives/pipes that belong to this module
imports: Array<Type<any> | ModuleWithProviders | any[]>//Specifies a list of modules whose exported directives/pipes should be available to templates in this module. This can also contain ModuleWithProviders
exports: Array<Type<any> | any[]>//Specifies a list of directives/pipes/modules that can be used within the template of any component that is part of an Angular module that imports this Angular module.
entryComponents: Array<Type<any> | any[]>//Specifies a list of components that should be compiled when this module is defined. For each component listed here, Angular will create a ComponentFactory and store it in the ComponentFactoryResolver.
bootstrap: Array<Type<any> | any[]>//Defines the components that should be bootstrapped when this module is bootstrapped. The components listed here will automatically be added to entryComponents.
schemas: Array<SchemaMetadata | any[]>//Elements and properties that are not Angular components nor directives have to be declared in the schema.
id: string//An opaque ID for this module, e.g. a name or a path. Used to identify modules in getModuleFactory. If left undefined, the NgModule will not be registered with getModuleFactory.
})
//更多内容请访问官网
//https://www.angular.cn/api/core/NgModule
//https://www.angular.cn/guide/architecture-modules
//查看

代码解读:

function makeDecorator(name, props, parentClass, chainFn, typeFn) {var metaCtor = makeMetadataCtor(props);
function DecoratorFactory() {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}if (this instanceof DecoratorFactory) {
       // 将使用装饰器的时候传入的参数放到descratorFactory
       //推荐https://www.jianshu.com/p/00dc4ad9b83f 去查看 .call.apply的作用
       //__spread 方法定义在tslib.js中, 将数组元素经过__read方法后concat
metaCtor.call.apply(metaCtor, __spread([this], args));return this;
}
var annotationInstance = new ((_a = DecoratorFactory).bind.apply(_a, __spread([void 0], args)))();
var TypeDecorator = function TypeDecorator(cls) {
typeFn && typeFn.apply(void 0, __spread([cls], args));
// Use of Object.defineProperty is important since it creates non-enumerable property which
// prevents the property is copied during subclassing.
var annotations = cls.hasOwnProperty(ANNOTATIONS) ?
cls[ANNOTATIONS] :
Object.defineProperty(cls, ANNOTATIONS, { value: [] })[ANNOTATIONS];
annotations.push(annotationInstance);
return cls;
};
if (chainFn)
chainFn(TypeDecorator);
return TypeDecorator;
var _a;
}
if (parentClass) {
DecoratorFactory.prototype = Object.create(parentClass.prototype);
}
DecoratorFactory.prototype.ngMetadataName = name;
DecoratorFactory.annotationCls = DecoratorFactory;
  //最后返回 DecoratorFactory
return DecoratorFactory;
}

注:期待有大神能够看到我的文章,并提出我的问题所在,小白一枚如果有错误还望指正。在此谢过。

 参考网址:

http://es6.ruanyifeng.com/#docs/decorator
http://web.jobbole.com/88572/
https://www.cnblogs.com/Wayou/p/es6_new_features.html#2917341

https://www.jianshu.com/p/00dc4ad9b83f

 

Angular 个人深究(一)【Angular中的Typescript 装饰器】的更多相关文章

  1. 从C#到TypeScript - 装饰器

    总目录 从C#到TypeScript - 类型 从C#到TypeScript - 高级类型 从C#到TypeScript - 变量 从C#到TypeScript - 接口 从C#到TypeScript ...

  2. 基于TypeScript装饰器定义Express RESTful 服务

    前言 本文主要讲解如何使用TypeScript装饰器定义Express路由.文中出现的代码经过简化不能直接运行,完整代码的请戳:https://github.com/WinfredWang/expre ...

  3. TypeScript 装饰器的执行原理

    装饰器本质上提供了对被装饰对象 Property​ Descriptor 的操作,在运行时被调用. 因为对于同一对象来说,可同时运用多个装饰器,然后装饰器中又可对被装饰对象进行任意的修改甚至是替换掉实 ...

  4. Python中利用函数装饰器实现备忘功能

    Python中利用函数装饰器实现备忘功能 这篇文章主要介绍了Python中利用函数装饰器实现备忘功能,同时还降到了利用装饰器来检查函数的递归.确保参数传递的正确,需要的朋友可以参考下   " ...

  5. python 中多个装饰器的执行顺序

    python 中多个装饰器的执行顺序: def wrapper1(f1): print('in wrapper1') def inner1(*args,**kwargs): print('in inn ...

  6. 第7.17节 Python类中的静态方法装饰器staticmethod 定义的静态方法深入剖析

    第7.17节  Python类中的静态方法装饰器staticmethod 定义的静态方法深入剖析 静态方法也是通过类定义的一种方法,一般将不需要访问类属性但是类需要具有的一些能力可以静态方法提供. 一 ...

  7. 第7.26节 Python中的@property装饰器定义属性访问方法getter、setter、deleter 详解

    第7.26节 Python中的@property装饰器定义属性访问方法getter.setter.deleter 详解 一.    引言 Python中的装饰器在前面接触过,老猿还没有深入展开介绍装饰 ...

  8. 使用 Vue + TypeScript 时项目中常用的装饰器

    目录 一.@Component 装饰器 1)父组件 2)子组件 二. @Emit 装饰器 1)父组件 2)子组件 三. @Model 装饰器 1)父组件 2)子组件 四. @Prop 装饰器 1)父组 ...

  9. TypeScript装饰器(decorators)

    装饰器是一种特殊类型的声明,它能够被附加到类声明,方法, 访问符,属性或参数上,可以修改类的行为. 装饰器使用 @expression这种形式,expression求值后必须为一个函数,它会在运行时被 ...

随机推荐

  1. LOJ#2983. 「WC2019」数树

    传送门 抄题解 \(Task0\),随便做一下,设 \(cnt\) 为相同的边的个数,输出 \(y^{n-cnt}\) \(Task1\),给定其中一棵树 设初始答案为 \(y^n\),首先可以发现, ...

  2. Mac 删除应用卸载后无法正常移除的图标

    经常会不通过appstore下载软件,也就是从网页中下载dmg,自己安装,但是当我不再想要这个软件,然后把它卸载掉之后就会发现,launchpad里还是遗留了这个软件的图标,而且删不掉.这个时候,就可 ...

  3. 汉诺塔hanoi

    问题描述: 有一个梵塔,塔内有三个座A.B.C,A座上有诺干个盘子,盘子大小不等,大的在下,小的在上(如图). 把这些个盘子从A座移到C座,中间可以借用B座但每次只能允许移动一个盘子,并且在移动过程中 ...

  4. P3932 浮游大陆的68号岛

    P3932 浮游大陆的68号岛 妖精仓库的储物点可以看做在一个数轴上.每一个储物点会有一些东西,同时他们之间存在距离. 每次他们会选出一个小妖精,然后剩下的人找到区间[l,r]储物点的所有东西,清点完 ...

  5. css radial-gradient()函数用法

    radial:半径的:放射状的:射线:光线:径向 gradient:梯度,坡度:渐变 radial-gradient:径向渐变 radial-gradient()函数:用径向渐变创建函数.径向渐变由中 ...

  6. bzoj千题计划289:bzoj 2707: [SDOI2012]走迷宫

    http://www.lydsy.com/JudgeOnline/problem.php?id=2707 dp[i] 表示从点i到终点的期望步数 dp[i]= Σ (dp[j]+1)/out[i] j ...

  7. Git与GitHub学习笔记(三).gitignore文件忽略和删除本地以及远程文件

    一.Git提供了文件忽略功能.当对工作区某个目录或者某些文件设置了忽略后,git将不会对它们进行追踪 HELP:如何在IntelliJ IDEA中使用.ignore插件忽略不必要提交的文件 问题:最近 ...

  8. [转载]HTML5浏览器测试网站汇总

    http://www.cnblogs.com/javawebsoa/archive/2012/04/19/2458224.html 浏览器支持情况统计 When Can IUse:图表经常更新,展示了 ...

  9. ASP.NET生成二维码

    下面使用ThoughtWorks.QRCode.dll这个类库,实现生成二维码 使用时需要增加:下面三个命名空间 using ThoughtWorks.QRCode.Codec; using Thou ...

  10. 20155215 2016-2017-2 《Java程序设计》第7周学习总结

    20155215 2016-2017-2 <Java程序设计>第7周学习总结 教材学习内容总结 第十二章 lambda语法:Lambda去重复,回忆DRY原则,Lambda表达式可读性更好 ...