第壹章第2节 C#和TS语言对比-代码组织方式

C#和TS的基础语法热身后,在深入语言之前,有必要搞清楚C#和TS代码组织方式。C#和TS都是面向对象语言,但前者是类型语言,所有代码都必须包含在类中(此处类是一个广义概念,它还包括结构、枚举、接口等);后者是函数式语言,函数可以作为值传递和返回,有全局作用域,代码不需要包含在类中。这种差异,导致两者的代码组织方式,存在较大差异。

一、C#的代码组织方式-命名空间

  • C#的代码组织方式有两个层面:**一是文件层面,从里到外分别为“文件>文件夹>项目>解决方案”,这个层面只是文件的组织形式,并不是代码的组织形式。二是代码层面,从里到外分别为“类class(此处类也是一个广义概念)> 命名空间namespace > 程序集assembly。这是代码的实际组织形式,一个程序集里面有多个命名空间,一个命名空间里有很多类,一个类必须属于某个命名空间,一个命名空间必须属于某个程序集。
  • 两个层面的关系:**是并行的,没有必然联系。比如通常一个项目就是一个程序集,一个文件夹就是一个命名空间,一个文件就是一个类。但是,一个文件里也可以定义多个类,一个类在某个文件夹中,但它却可能属于另一个命名空间,一个文件夹也可以不是一个命名空间。实际操作中,反而建议将两者耦合起来,即一个项目对应一个程序集,一个文件夹对应一个命名空间,一个文件对应一个类,不要给自己找麻烦。例外情况,如果多个类的关联性非常强,比如DTO及其验证扩展类,可以考虑放在一个文件中,这样便于管理。
  • 引入外部资源:**在依赖项中,引用同一个解决方案的不同项目,或引用第三方nuget类库,或引用本地程序集文件(DLL),然后使用using引用相应的命名空间,即可使用这个命名空间下的类型。

1.1 文件层面的结构

image.png

1.2 代码层面的结构

image.png

二、TS/JS/UTS的代码组织-模块化

  • 模块化:**任何包含 export 语句的文件,就是一个模块(module)。相应地,如果文件不包含 export 语句,就是一个全局的脚本文件,代码会合并到全局作用域中。模块内的代码,在一个独立的作用域内。模块内部的变量、函数、类等元素,默认只在内部可见,如果需要暴露给外部使用,必须用 export 命令导出,其它模块使用 import 命令来导入。
  • 目前存在两个模块化方案,ES6模块化和CommonJS模块化。uniapp和uniapp-x使用ES6(前端基本都使用ES6),unicloud使用CommonJS(unicloud的后端的nodejs,目前nodejs对CommonJS支持更好)。
  • 如何引入外部模块:方法一:将需要的模块文件直接复制到当前项目中(模块需要export相关接口);方法二:安装第三方的npm包。然后使用import(ES6模块化)或者require(CommonJS模块化)引入,即可使用该模块中导出的元素。
  • 命名空间:TS中还有命名空间的特性,但使用模块化后,不建议再使用。

2.1 ES6模块化

//a.uts,js和ts一样
export const a = 1 //导出常量
export let b = 1 //导出变量
export function myFunction(){} //导出函数
export class MyClass{} //导出类
export type MyType{name:string,age:number} //导出type
export interface IMyInterface{name:string,getName():void} //导出接口
export default const c = {name:"MC",age:28} //默认导出

//b.uts, js和ts一样
import {a,b,myFunction} from "./a.uts" //解构导入
import {MyClass as OtherClass} from "./a.uts" //解构导入并重命名
import MyC from "./a.uts" //导入默认,这里导入的是c,导入时可以重命名
import * as All from "./a.uts" // 导入所有,并挂在All对象上,比如通过All.a访问a
export const d = 10 //在一个文件里,即可以导入,也可以导出

//vue中使用模块化的案例
import axios from 'axios'; //安装了axios的npm包后,导入axios,注意路径格式
import { getToken } from '@/utils/auth' //@表示src文件夹,需要在vite.config中设置

//如果一个文件不包含 export 语句,但是希望把它当作一个模块,可以在脚本头部添加一行语句
export {};

2.2 CommonJS模块化

//在node.js环境下,没有type和interface

//a1.js,导出单个值,使用module.export
module.export = 100 //导出单个值
//b1.js
const a = require("./a1.js")


//a2.js,导出单个值,使用export.XXX
export.add = ()=>{} //导出单个值
//b2.js
const add = require("./a1.js")


//a3.js,导出多个值,使用module.export
const a = 1
const b = {name:"MC",age:28}
function myFunction(){}
class MyClass{} 
module.export = {a,b,myFunction,Myclass} //使用module.exports导出
//b3.js
const {a,b,myFunction,Myclass} = require("./a3.js")

2.3 类型声明

第三方库,无论是JS,还是TS,最后都会被编译成JS。而要在TS中使用,就需要借助类型申明。一般类型声明在单独的声明文件中,通常命名为*.d.ts。正常情况下,应用开发很少接触类型声明,因为绝大多数第三方库,都提供了类型声明文件。有以下几种情况:

  • 首先会找三方库本身提供的d.ts类型申明文件,如node_modules/jquery/index.d.ts。或者在package.json文件中配置,如"types": “xxx.d.ts”
  • 如果三方库本身没有提供,可以安装社区提供的声明文件,如npm i --save-dev @types/jquery,会自动安装在node_modules/@types/jquery/index.d.ts,TS会自动加载@types这个目录的类型申明文件,如果想修改自动加载的路径,可以修改配置文件tsconfig.json,“compilerOptions”: { “typeRoots”: [“./typings”],会去与tsconfig同级的typings目录找。
  • 以上两种方法找不到,就需要自己写类型申明文件
//1、声明类型============================================================
//let/const/var、function、class、enum、module、namespace,使用declare声明
//interface和type,可以不用declare声明,但建议统一加上
//declare的module或namespace里面,可以不需要再declare
//例子:
declare let x:number; //声明x为number类型
declare let x; //申请x为any类型
//声明方法
declare function sayHello(
  name:string
):void;
//声明类
declare class Animal {
  constructor(name:string);
  eat():void;
  sleep():void;
}
//声明枚举
declare Color{
  Green,
    Red,
    Blue
}
//声明type和interface,declare可用可不用
type Student = {
  name:string,
  age:number
}
declare interface Student{
  name:string,
  age:number
}
//声明模块,模块内可以不用再declare
declare module AnimalLib {
  class Animal {
    constructor(name:string);
    eat(): void;
    sleep(): void;
  }
  type Animals = 'Fish' | 'Dog';
}



//2、类型申明文件的例子===================================================
//模块moment的类型申明文件
//类型申明和模块化是两个不同组件,如果项目中需要使用到类型,还是要export
//但是模块和命名空间的申明中,可以不用再export
declare module 'moment' {
  export interface Moment {
    format(format:string): string;
    add(
      amount: number,
      unit: 'days' | 'months' | 'years'
    ): Moment;
    subtract(
      amount:number,
      unit:'days' | 'months' | 'years'
    ): Moment;
  }
  function moment(
    input?: string | Date
  ): Moment;
  export default moment; //默认导出
}
//加载配置类型声明文件,在package.json中配置
{
  "name": "awesome",
  "author": "Vandelay Industries",
  "version": "1.0.0",
  "main": "./lib/main.js",
  "types": "./lib/main.d.ts"
}



//3、为外部模块扩展属性或方法,需要借助declare=============================
//《函数方法》章节,也有扩展方法的说明
//例1:为外部模块扩展对象的类型
// a.ts,包含export,是一个模块
export interface A {
  x: number;
}
// b.ts,利用interface的类型合并特性
import { A } from './a';
declare module './a' {
  interface A {
    y: number;
  }
}
const a:A = { x: 0, y: 0 };

//例2:为全局模块中的内置类型扩展方法
export {}; //将当前文件模块化
declare global {
  interface String {
    toSmallString(): string;
  }
}
String.prototype.toSmallString = ():string => {
  // 具体实现
  return '';
};

  • 18
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值