• Angular 个人深究(一)【Angular中的Typescript 装饰器】


    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@angularcorefesm5core.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

     
    Stay foolish
  • 相关阅读:
    两个栈实现队列
    重建二叉树
    最大的K个数
    堆排序
    Android 强制竖屏
    屏蔽输入框的焦点
    Android 全屏显示的方法(不包含状态栏)
    android 布局之scrollview
    clean之后R文件消失
    thinkphp
  • 原文地址:https://www.cnblogs.com/primadonna/p/9224452.html
Copyright © 2020-2023  润新知