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\@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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM