广告
返回顶部
首页 > 资讯 > 前端开发 > VUE >怎么编写高效的TS代码
  • 197
分享到

怎么编写高效的TS代码

2024-04-02 19:04:59 197人浏览 薄情痞子
摘要

这篇文章主要介绍“怎么编写高效的TS代码”,在日常操作中,相信很多人在怎么编写高效的TS代码问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”怎么编写高效的TS代码”的疑惑有所帮

这篇文章主要介绍“怎么编写高效的TS代码”,在日常操作中,相信很多人在怎么编写高效的TS代码问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”怎么编写高效的TS代码”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

一、尽量减少重复代码

对于刚接触 typescript 的小伙伴来说,在定义接口时,可能一不小心会出现以下类似的重复代码。比如:

interface Person {   firstName: string;   lastName: string; }  interface PersonWithBirthDate {   firstName: string;   lastName: string;   birth: Date; }

很明显,相对于 Person 接口来说,PersonWithBirthDate 接口只是多了一个 birth属性,其他的属性跟 Person  接口是一样的。那么如何避免出现例子中的重复代码呢?要解决这个问题,可以利用 extends 关键字:

interface Person {    firstName: string;    lastName: string; }  interface PersonWithBirthDate extends Person {    birth: Date; }

当然除了使用 extends 关键字之外,也可以使用交叉运算符(&):

type PersonWithBirthDate = Person & { birth: Date };

另外,有时候你可能还会发现自己想要定义一个类型来匹配一个初始配置对象的「形状」,比如:

const INIT_OPTioNS = {   width: 640,   height: 480,   color: "#00FF00",   label: "VGA", };  interface Options {   width: number;   height: number;   color: string;   label: string; }

其实,对于 Options 接口来说,你也可以使用 typeof 操作符来快速获取配置对象的「形状」:

type Options = typeof INIT_OPTIONS;

而在使用可辨识联合(代数数据类型或标签联合类型)的过程中,也可能出现重复代码。比如:

interface SaveAction {    type: 'save';   // ... }  interface LoadAction {   type: 'load';   // ... }  type Action = SaveAction | LoadAction; type ActionType = 'save' | 'load'; // Repeated types!

为了避免重复定义 'save' 和 'load',我们可以使用成员访问语法,来提取对象中属性的类型:

type ActionType = Action['type']; // 类型是 "save" | "load"

然而在实际的开发过程中,重复的类型并不总是那么容易被发现。有时它们会被语法所掩盖。比如有多个函数拥有相同的类型签名:

function get(url: string, opts: Options): Promise<Response> {  }  function post(url: string, opts: Options): Promise<Response> {  }

对于上面的 get 和 post 方法,为了避免重复的代码,你可以提取统一的类型签名:

type HttpFunction = (url: string, opts: Options) => Promise<Response>;   const get: HTTPFunction = (url, opts) => {  }; const post: HTTPFunction = (url, opts) => {  };

二、使用更精确的类型替代字符串类型

假设你正在构建一个音乐集,并希望为专辑定义一个类型。这时你可以使用 interface关键字来定义一个 Album 类型:

interface Album {   artist: string; // 艺术家   title: string; // 专辑标题   releaseDate: string; // 发行日期:YYYY-MM-DD   recordingType: string; // 录制类型:"live" 或 "studio" }

对于 Album 类型,你希望 releaseDate 属性值的格式为 YYYY-MM-DD,而 recordingType 属性值的范围为 live 或  studio。但因为接口中 releaseDate 和 recordingType 属性的类型都是字符串,所以在使用 Album  接口时,可能会出现以下问题:

const dangerous: Album = {   artist: "Michael Jackson",   title: "Dangerous",   releaseDate: "November 31, 1991", // 与预期格式不匹配   recordingType: "Studio", // 与预期格式不匹配 };

虽然 releaseDate 和 recordingType 的值与预期的格式不匹配,但此时 TypeScript  编译器并不能发现该问题。为了解决这个问题,你应该为 releaseDate 和 recordingType 属性定义更精确的类型,比如这样:

interface Album {   artist: string; // 艺术家   title: string; // 专辑标题   releaseDate: Date; // 发行日期:YYYY-MM-DD   recordingType: "studio" | "live"; // 录制类型:"live" 或 "studio" }

重新定义 Album 接口之后,对于前面的赋值语句,TypeScript 编译器就会提示以下异常信息:

const dangerous: Album = {   artist: "Michael Jackson",   title: "Dangerous",   // 不能将类型“string”分配给类型“Date”。ts(2322)   releaseDate: "November 31, 1991", // Error   // 不能将类型“"Studio"”分配给类型“"studio" | "live"”。ts(2322)   recordingType: "Studio", // Error };

为了解决上面的问题,你需要为 releaseDate 和 recordingType 属性设置正确的类型,比如这样:

const dangerous: Album = {   artist: "Michael Jackson",   title: "Dangerous",   releaseDate: new Date("1991-11-31"),   recordingType: "studio", };

另一个错误使用字符串类型的场景是设置函数的参数类型。假设你需要写一个函数,用于从一个对象数组中抽取某个属性的值并保存到数组中,在 Underscore  库中,这个操作被称为 “pluck”。要实现该功能,你可能最先想到以下代码:

function pluck(record: any[], key: string): any[] {   return record.map((r) => r[key]); }

对于以上的 pluck 函数并不是很好,因为它使用了 any 类型,特别是作为返回值的类型。那么如何优化 pluck  函数呢?首先,可以通过引入一个泛型参数来改善类型签名:

function pluck<T>(record: T[], key: string): any[] {   // Element implicitly has an 'any' type because expression of type 'string' can't be used to    // index type 'unknown'.   // No index signature with a parameter of type 'string' was found on type 'unknown'.(7053)   return record.map((r) => r[key]); // Error }

通过以上的异常信息,可知字符串类型的 key 不能被作为 unknown 类型的索引类型。要从对象上获取某个属性的值,你需要保证参数 key  是对象中的属性。

说到这里相信有一些小伙伴已经想到了 keyof 操作符,它是 TypeScript 2.1  版本引入的,可用于获取某种类型的所有键,其返回类型是联合类型。接着使用 keyof 操作符来更新一下 pluck 函数:

function pluck<T>(record: T[], key: keyof T) {   return record.map((r) => r[key]); }

对于更新后的 pluck 函数,你的 IDE 将会为你自动推断出该函数的返回类型:

function pluck<T>(record: T[], key: keyof T): T[keyof T][]

对于更新后的 pluck 函数,你可以使用前面定义的 Album 类型来测试一下:

const albums: Album[] = [{   artist: "Michael Jackson",   title: "Dangerous",   releaseDate: new Date("1991-11-31"),   recordingType: "studio", }];  // let releaseDateArr: (string | Date)[] let releaseDateArr = pluck(albums, 'releaseDate');

示例中的 releaseDateArr 变量,它的类型被推断为 (string | Date)[],很明显这并不是你所期望的,它的正确类型应该是  Date[]。那么应该如何解决该问题呢?这时你需要引入第二个泛型参数 K,然后使用 extends 来进行约束:

function pluck<T, K extends keyof T>(record: T[], key: K): T[K][] {   return record.map((r) => r[key]); }  // let releaseDateArr: Date[] let releaseDateArr = pluck(albums, 'releaseDate');

三、定义的类型总是表示有效的状态

假设你正在构建一个允许用户指定页码,然后加载并显示该页面对应内容的 WEB 应用程序。首先,你可能会先定义 State 对象:

interface State {   pageContent: string;   isLoading: boolean;   errORMsg?: string; }

接着你会定义一个 renderPage 函数,用来渲染页面:

function renderPage(state: State) {   if (state.errorMsg) {     return `呜呜呜,加载页面出现异常了...${state.errorMsg}`;   } else if (state.isLoading) {     return `页面加载中~~~`;   }   return `<div>${state.pageContent}</div>`; }  // 输出结果:页面加载中~~~ console.log(renderPage({isLoading: true, pageContent: ""})); // 输出结果:<div>大家好,我是阿宝哥</div> console.log(renderPage({isLoading: false, pageContent: "大家好,我是阿宝哥"}));

创建好 renderPage 函数,你可以继续定义一个 changePage 函数,用于根据页码获取对应的页面数据:

async function changePage(state: State, newPage: string) {   state.isLoading = true;   try {     const response = await fetch(getUrlForPage(newPage));     if (!response.ok) {       throw new Error(`Unable to load ${newPage}: ${response.statusText}`);     }     const text = await response.text();     state.isLoading = false;     state.pageContent = text;   } catch (e) {     state.errorMsg = "" + e;   } }

对于以上的 changePage 函数,它存在以下问题:

  • 在 catch 语句中,未把 state.isLoading 的状态设置为 false;

  • 未及时清理 state.errorMsg 的值,因此如果之前的请求失败,那么你将继续看到错误消息,而不是加载消息。

出现上述问题的原因是,前面定义的 State 类型允许同时设置 isLoading 和 errorMsg  的值,尽管这是一种无效的状态。针对这个问题,你可以考虑引入可辨识联合类型来定义不同的页面请求状态:

interface RequestPending {   state: "pending"; }  interface RequestError {   state: "error";   errorMsg: string; }  interface RequestSuccess {   state: "ok";   pageContent: string; }  type RequestState = RequestPending | RequestError | RequestSuccess;  interface State {   currentPage: string;   requests: { [page: string]: RequestState }; }

在以上代码中,通过使用可辨识联合类型分别定义了 3  种不同的请求状态,这样就可以很容易的区分出不同的请求状态,从而让业务逻辑处理更加清晰。接下来,需要基于更新后的 State 类型,来分别更新一下前面创建的  renderPage 和 changePage 函数:

更新后的 renderPage 函数

function renderPage(state: State) {   const { currentPage } = state;   const requestState = state.requests[currentPage];   switch (requestState.state) {     case "pending":       return `页面加载中~~~`;     case "error":       return `呜呜呜,加载第${currentPage}页出现异常了...${requestState.errorMsg}`;     case "ok":       `<div>第${currentPage}页的内容:${requestState.pageContent}</div>`;   } }

更新后的 changePage 函数

async function changePage(state: State, newPage: string) {   state.requests[newPage] = { state: "pending" };   state.currentPage = newPage;   try {     const response = await fetch(getUrlForPage(newPage));     if (!response.ok) {       throw new Error(`无法正常加载页面 ${newPage}: ${response.statusText}`);     }     const pageContent = await response.text();     state.requests[newPage] = { state: "ok", pageContent };   } catch (e) {     state.requests[newPage] = { state: "error", errorMsg: "" + e };   } }

在 changePage 函数中,会根据不同的情形设置不同的请求状态,而不同的请求状态会包含不同的信息。这样 renderPage 函数就可以根据统一的  state 属性值来进行相应的处理。因此,通过使用可辨识联合类型,让请求的每种状态都是有效的状态,不会出现无效状态的问题。

四、选择条件类型而不是重载声明

假设你要使用 TS 实现一个 double 函数,该函数支持 string 或 number 类型。这时,你可能已经想到了使用联合类型和函数重载:

function double(x: number | string): number | string; function double(x: any) {   return x + x; }

虽然这个 double 函数的声明是正确的,但它有一点不精确:

// const num: string | number const num = double(10);  // const str: string | number const str = double('ts');

对于 double 函数,你期望传入的参数类型是 number 类型,其返回值的类型也是 number 类型。当你传入的参数类型是 string  类型,其返回的类型也是 string 类型。而上面的 double 函数却是返回了 string | number  类型。为了实现上述的要求,你可能想到了引入泛型变量和泛型约束:

function double<T extends number | string>(x: T): T; function double(x: any) {   return x + x; }

在上面的 double 函数中,引入了泛型变量 T,同时使用 extends 约束了其类型范围。

// const num: 10 const num = double(10); // const str: "ts" const str = double('ts'); console.log(str);

不幸的是,我们对精确度的追求超过了预期。现在的类型有点太精确了。当传递一个字符串类型时,double  声明将返回一个字符串类型,这是正确的。但是当传递一个字符串字面量类型时,返回的类型是相同的字符串字面量类型。这是错误的,因为 ts 经过 double  函数处理后,返回的是 tsts,而不是 ts。

另一种方案是提供多种类型声明。虽然 TypeScript 只允许你编写一个具体的实现,但它允许你编写任意数量的类型声明。你可以使用函数重载来改善  double 的类型:

function double(x: number): number; function double(x: string): string; function double(x: any) {   return x + x; }  // const num: number const num = double(10);  // const str: string const str = double("ts");

很明显此时 num 和 str 变量的类型都是正确的,但不幸的是,double 函数还有一个小问题。因为 double 函数的声明只支持 string 或  number 类型的值,而不支持 string | number 联合类型,比如:

function doubleFn(x: number | string) {   // Argument of type 'string | number' is not assignable to    // parameter of type 'number'.   // Argument of type 'string | number' is not assignable to    // parameter of type 'string'.   return double(x); // Error }

为什么会提示以上的错误呢?因为当 TypeScript 编译器处理函数重载时,它会查找重载列表,直到找一个匹配的签名。对于 number | string  联合类型,很明显是匹配失败的。

然而对于上述的问题,虽然可以通过新增 string | number 的重载签名来解决,但最好的方案是使用条件类型。在类型空间中,条件类型就像 if  语句一样:

function double<T extends number | string>(   x: T ): T extends string ? string : number; function double(x: any) {   return x + x; }

这与前面引入泛型版本的 double 函数声明类似,只是它引入更复杂的返回类型。条件类型使用起来很简单,与 javascript  中的三目运算符(?:)一样的规则。T extends string ? string : number 的意思是,如果 T 类型是 string 类型的子集,则  double函数的返回值类型为 string 类型,否则为 number 类型。

在引入条件类型之后,前面的所有例子就可以正常工作了:

// const num: number const num = double(10);  // const str: string const str = double("ts");   // function f(x: string | number): string | number function f(x: number | string) {   return double(x); }

五、一次性创建对象

在 JavaScript 中可以很容易地创建一个表示二维坐标点的对象:

const pt = {};  pt.x = 3;  pt.y = 4;

然而对于同样的代码,在 TypeScript 中会提示以下错误信息:

const pt = {}; // Property 'x' does not exist on type '{}' pt.x = 3; // Error // Property 'y' does not exist on type '{}' pt.y = 4; // Error

这是因为第一行中 pt 变量的类型是根据它的值 {} 推断出来的,你只能对已知的属性赋值。针对这个问题,你可能会想到一种解决方案,即新声明一个 Point  类型,然后把它作为 pt 变量的类型:

interface Point {   x: number;   y: number; }  // Type '{}' is missing the following properties from type 'Point': x, y(2739) const pt: Point = {}; // Error pt.x = 3; pt.y = 4;

那么如何解决上述问题呢?其中一种最简单的解决方案是一次性创建对象:

const pt = {    x: 3,   y: 4,  }; // OK

如果你想一步一步地创建对象,你可以使用类型断言(as)来消除类型检查:

const pt = {} as Point;  pt.x = 3; pt.y = 4; // OK

但是更好的方法是一次性创建对象并显式声明变量的类型:

const pt: Point = {    x: 3,   y: 4,  };

而当你需要从较小的对象来构建一个较大的对象时,你可能会这样处理,比如:

const pt = { x: 3, y: 4 }; const id = { name: "PythaGoras" }; const namedPoint = {}; Object.assign(namedPoint, pt, id);  // Property 'id' does not exist on type '{}'.(2339) namedPoint.name; // Error

为了解决上述问题,你可以使用对象展开运算符 ... 来一次性构建大的对象:

const namedPoint = {...pt, ...id};  namedPoint.name; // OK, type is string

此外,你还可以使用对象展开运算符,以一种类型安全的方式逐个字段地构建对象。关键是在每次更新时使用一个新变量,这样每个变量都会得到一个新类型:

const pt0 = {}; const pt1 = {...pt0, x: 3}; const pt: Point = {...pt1, y: 4}; // OK

虽然这是构建这样一个简单对象的一种迂回方式,但对于向对象添加属性并允许 TypeScript  推断新类型来说,这可能是一种有用的技术。要以类型安全的方式有条件地添加属性,可以使用带 null 或 {} 的对象展开运算符,它不会添加任何属性:

declare var hasMiddle: boolean; const firstLast = {first: 'Harry', last: 'Truman'}; const president = {...firstLast, ...(hasMiddle ? {middle: 'S'} : {})};

如果在编辑器中鼠标移到 president,你将看到 TypeScript 推断出的类型:

const president: {   middle?: string;   first: string;   last: string; }

最终通过设置 hasMiddle 变量的值,你就可以控制 president 对象中 middle 属性的值:

declare var hasMiddle: boolean; var hasMiddle = true; const firstLast = {first: 'Harry', last: 'Truman'}; const president = {...firstLast, ...(hasMiddle ? {middle: 'S'} : {})};  let mid = president.middle console.log(mid); // S

到此,关于“怎么编写高效的TS代码”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

--结束END--

本文标题: 怎么编写高效的TS代码

本文链接: https://www.lsjlt.com/news/84609.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 怎么编写高效的TS代码
    这篇文章主要介绍“怎么编写高效的TS代码”,在日常操作中,相信很多人在怎么编写高效的TS代码问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”怎么编写高效的TS代码”的疑惑有所帮...
    99+
    2022-10-19
  • VSCode中怎么高效写代码
    这篇文章给大家介绍VSCode中怎么高效写代码,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。演示下高效写代码有些代码是重复写过的,还需要继续重复写吗? 答案是 不,因为只要 cv 就行了,那有什么方法比 cv 更优雅、...
    99+
    2023-06-21
  • 编写高效且优雅的 Python 代码(
    貌似只能创建一个专栏,所以这篇文章只好放到“JavaScript从前端到全终端”里了 原文链接:Effective Python Python 作为一门入门极易并容易上瘾的语音,相信已经成为了很多人 “写着玩” 的标配脚本语言。但很多...
    99+
    2023-01-31
    高效 优雅 代码
  • 如何高效编写网页代码
    这篇文章主要介绍了如何高效编写网页代码,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。本文从三个方面着手,一个是企业网站的建设(教育政府类也归纳到企业站点里),二是小型门户站点...
    99+
    2023-06-08
  • 如何在 Unix 上编写高效的代码?
    Unix 是一种常用的操作系统,被广泛用于服务器和大型计算机中。在 Unix 上编写高效的代码是每个程序员必备的技能之一。本文将介绍如何在 Unix 上编写高效的代码,并提供一些示例代码来帮助读者更好地理解。 一、使用合适的编程语言 选择合...
    99+
    2023-08-26
    unix ide 索引
  • 怎么编写高性能的JavaScript代码
    这篇文章主要介绍“怎么编写高性能的JavaScript代码”,在日常操作中,相信很多人在怎么编写高性能的JavaScript代码问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”...
    99+
    2022-10-19
  • 高效编写CSS代码的建议有哪些
    这篇文章将为大家详细讲解有关高效编写CSS代码的建议有哪些,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。1. 基本原则  1.1 把CSS放在HTML页面头...
    99+
    2022-10-19
  • 高效编写Java代码的建议分别是什么
    这期内容当中小编将会给大家带来有关高效编写Java代码的建议分别是什么,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。类名首字母应该大写。字段、方法以及对象(句柄)的首字母应小写。对于所有标识符,其中包含的...
    99+
    2023-06-17
  • ASP API教程:如何编写高效代码?
    ASP API是一种广泛应用于Web开发的技术,它可以帮助我们快速开发高效的Web应用程序。但是,在使用ASP API时,我们经常会遇到一些性能问题,这些问题会影响我们的应用程序的速度和响应时间。那么,如何编写高效的ASP API代码呢?...
    99+
    2023-11-06
    api 教程 学习笔记
  • CSS代码高效编写规范有哪些
    这篇文章将为大家详细讲解有关CSS代码高效编写规范有哪些,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。一些高效的CSS代码编写规范CSS学起来并不难,但在大...
    99+
    2022-10-19
  • 怎么编写高质量的web开发代码
    本文小编为大家详细介绍“怎么编写高质量的web开发代码”,内容详细,步骤清晰,细节处理妥当,希望这篇“怎么编写高质量的web开发代码”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。Spring、Apache Com...
    99+
    2023-06-17
  • 怎么编写高效的MySQL应用
    这篇文章主要介绍“怎么编写高效的MySQL应用”,在日常操作中,相信很多人在怎么编写高效的MySQL应用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”怎么编写高效的MySQL...
    99+
    2022-10-18
  • GO语言学习笔记:如何编写高效的代码?
    GO语言是一种开源的编程语言,由Google开发。它被广泛应用于Web开发、分布式系统、云计算等领域。GO语言拥有高效、简洁、易于学习等特点,因此备受开发者的喜爱。在本文中,我们将探讨如何编写高效的GO语言代码。 一、使用基本数据类型 G...
    99+
    2023-06-28
    学习笔记 教程 开发技术
  • PHP 开发技术:如何编写高效的存储代码?
    在 PHP 开发中,存储数据是一个必不可少的环节。在使用数据库或者文件存储数据时,如何编写高效的存储代码是每个 PHP 开发者都需要掌握的技能。本文将介绍一些优化存储代码的技巧,帮助您编写高效的存储代码。 一、选择正确的存储方式 在 PH...
    99+
    2023-09-02
    学习笔记 开发技术 存储
  • 怎么编写js函数来提高代码的质量
    这篇文章主要介绍了怎么编写js函数来提高代码的质量的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇怎么编写js函数来提高代码的质量文章都会有所收获,下面我们一起来看看吧。函数是实现程序功能的最基本单位,每一个程序...
    99+
    2023-06-17
  • Java异步编程和JavaScript对象:如何编写更高效的代码?
    在现代软件开发中,异步编程是非常重要的一种技术。它可以帮助我们更好地利用现代计算机的多核处理能力,提高程序的执行效率。Java和JavaScript是两种非常流行的编程语言,它们都支持异步编程。本文将介绍如何在Java和JavaScrip...
    99+
    2023-06-15
    异步编程 javascript 对象
  • 怎么编写更好的JS代码
    这篇文章主要介绍“怎么编写更好的JS代码”,在日常操作中,相信很多人在怎么编写更好的JS代码问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”怎么编写更好的JS代码”的疑惑有所帮...
    99+
    2022-10-19
  • 怎么编写更好的React代码
    这篇文章主要介绍“怎么编写更好的React代码”,在日常操作中,相信很多人在怎么编写更好的React代码问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”怎么编写更好的React...
    99+
    2022-10-19
  • 怎么编写高效的CSS选择符
    这篇文章将为大家详细讲解有关怎么编写高效的CSS选择符,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。首先看一小段 CSS 代码:#menus > li { f...
    99+
    2023-06-08
  • 如何使用ASP和bash编写高效的Windows对象代码?
    在Windows操作系统中,ASP和bash是两种非常常见的编程语言。当它们结合使用时,可以编写高效的Windows对象代码。本文将介绍如何使用ASP和bash编写高效的Windows对象代码,以及一些相关的演示代码。 一、ASP和Wind...
    99+
    2023-11-03
    bash 对象 windows
软考高级职称资格查询
推荐阅读
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作