Typescript 【实用教程】(2024最新版)含类型声明,类型断言,函数,接口,泛型等

简介

TypeScript 是 JavaScript 的超集,是 JavaScript(弱类型语言) 的强类型版本。

  • 拥有类型机制
  • 文件后缀 .ts
  • Typescript = type + ES6
  • TypeScript 和 JavaScript 的关系类似 less 和 css 的关系
  • TypeScript对 JavaScript 添加了一些扩展,如 class / interface / module 等,大大提升代码的可阅读性。
  • 不能在浏览器直接执行,而是编译成 JavaScript (去掉类型和特有语法)后才会运行:

与 JavaScript 相比的优势

  • 静态类型检查,可以在代码开发阶段就预知一些低级错误的发生。

类型声明文件

以为.d.ts 为后缀的文件,内容为 TS 语法编写的各种类型声明(定义数据,函数、接口或类的类型)

  • 通常安装第三方库后,若缺少类型声明文件,会有报错提示安装必要的类型声明文件
    在这里插入图片描述

  • 若没有提示,则可以在 https://www.npmjs.com/ 中搜索相应的类型声明文件

    搜索关键字为 @type/第三方库的名称

    在这里插入图片描述

  • 有的库没有类型声明文件,可以自己写,点我了解详细语法

  • 也可以用命令行生成类型文件,点我了解详情

学习资料

英文官网

https://www.typescriptlang.org/

中文文档
https://www.tslang.cn/docs/home.html

https://typescript.bootcss.com/

在线开发环境

https://www.typescriptlang.org/play/index.html

搭建本地开发环境

  1. 新建文件夹 TSdemo

  2. 初始化项目

npm init -y
  1. 安装必要的依赖
npm i -D typescript nodemon ts-node
  • typescript 用于将 TS 编译成 JS
  • nodemon 用于 node 进程的重启
  • ts-node 用于直接执行 TS 类型的文件
  1. 项目目录下创建文件 index.ts
let myNname: string = "朝阳";

console.log(myNname);
  1. 修改 package.json 中的 scripts 为
  "scripts": {
    "start": "nodemon --exec ts-node index.ts"
  },
  1. 初始化 ts 的配置
npx tsc --init

执行成功后,会生成文件 tsconfig.json

  1. 启动项目
    在这里插入图片描述
    在这里插入图片描述

声明类型

值类型

// 字符串
let myNname: string = "朝阳";

// 数字
let num: number = 10;

// 布尔类型
let ifLogin: boolean = true;
// 布尔类型支持赋值计算之后结果是布尔值的表达式
let bool: boolean = !!0

// null
let n: null = null;

// undefined
let u: undefined = undefined;

// symbol
let s: symbol = Symbol();

数组 []

// 空数组
let arr: [] = [];

// 元素只能是数字的数组(其他类型的写法类似)
let arr1: number[] = [1, 2];

// 元素只能是数字或字符串的数组(| 表示或的关系)
let arr2: (number | string)[] = [1, "朝阳"];

// 即是number类型也可能是string数组
const numbers1: number[] | string[] = ['123', '333'] // 正确
const numbers2: number[] | string[] = [123, '333'] // 错误

// 对象数组
let todoList: {
  id: number;
  label: string;
  done: boolean;
}[] = [
  {
    id: 1,
    label: "吃饭",
    done: false,
  },
  {
    id: 2,
    label: "编程",
    done: false,
  },
];

// 使用类型别名(type alias)
type User = { name: string; age: number }

// 存储对象类型的内容
const objectArr: User[] = [
  {
    name: 'zws',
    age: 18
  }
]

// 构造函数声明类型
let arr_1: Array<number> = [1, 2];
let arr_2: Array<number | string> = [1, "朝阳"];

对象 {}

// 空对象
let o: {} = {};
let o2: object = {};


// 必选属性的对象(赋值时,声明的属性必须有!)
let user: {
  name: string;
  age: number;
} = {
  name: "朝阳",
  age: 35,
};

// 可选属性的对象(可选属性需写在必选属性的后面!)
let user2: {
  name: string;
  age?: number;
} = {
  name: "晚霞",
};

Object 、 {} 、 object 的区别

  • 与Object类型相同的{}是最不具体的,可以将对象、数组和基元分配给它;

  • object是更具体的,类似于{ [key: string]: any };可以给它分配对象和数组,但不能分配原始类型的数据;

  • { [key: string]: string }是最具体的,它不允许任何原始类型、数组或具有非字符串值的对象被分配到它。

var o: object;
o = { prop: 0 }; // OK
o = []; // OK
o = 42; // Error
o = "string"; // Error
o = false; // Error
o = null; // Error
o = undefined; // Error

var p: {}; // or Object
p = { prop: 0 }; // OK
p = []; // OK
p = 42; // OK
p = "string"; // OK
p = false; // OK
p = null; // Error
p = undefined; // Error

var q: { [key: string]: any };
q = { prop: 0 }; // OK
q = []; // OK
q = 42; // Error
q = "string"; // Error
q = false; // Error
q = null; // Error
q = undefined; // Error

var r: { [key: string]: string };
r = { prop: 'string' }; // OK
r = { prop: 0 }; // Error
r = []; // Error
r = 42; // Error
r = "string"; // Error
r = false; // Error
r = null; // Error
r = undefined; // Error

类 class

class Person {}
const me: Person = new Person()

class Teacher {
  name: string
  age: number
}

const objectArr: Teacher[] = [
  new Teacher(),
  {
    name: 'zws',
    age: 18
  }
]

新增类型

以下类型为 TS 新增的,在 js 中不存在的数据类型

任意类型 any

当不确定变量的类型时(比如来自用户输入或第三方代码库的动态内容),可以使用,但尽量少用。

  • 任何类型的值都可以赋值给 any 类型的变量
let a: any = '你好'
a = 0

// 多数据类型的数组
let list: any[] = [1, true, "free"];

未知的类型 unknown

TypeScript3.0版本新增的类型

  • 任何类型的值都可以赋值给 unknown 类型的变量
  • any 与 unknown 的区别 : unknown 需要明确类型后执行操作,any 则不需要
let a: unknown = 1;

let b = a + 1; // 会报错 “a”的类型为“未知”

可通过 as 声明类型解决

let a: unknown = 1;

let b = (a as number) + 1;

永不存在的值 never

用于总会抛出异常或根本不会有返回值的函数表达式的返回值类型。
当变量被永不为真的类型保护所约束时,该变量也是 never 类型。

用途

  • 限制类型
  • 控制流程
  • 类型运算
// 返回never的函数必须存在无法达到的终点
function error(message: string): never {
    throw new Error(message);
}

// 推断的返回值类型为never
function fail() {
    return error("Something failed");
}

// 返回never的函数必须存在无法达到的终点
function infiniteLoop(): never {
    while (true) {
    }
}

无类型 Void

即什么类型都不是,通常用于描述函数没有返回值

function test(): void {
}

void类型的变量只能被赋予undefinednull

let test: void = undefined;

元组 Tuple

即固定长度和类型的数组

let x: [string, number];
x = ['hello', 10];

枚举 enum

一种全新的数据描述方式,用于描述一组数量有限的系列数据。

数值枚举(默认)

// 枚举三原色
enum Color {Red, Green, Blue}
// 按枚举内容的字符串取值,得到的是对应的下标(类似数组的下标,从0开始)
let c: Color = Color.Green;  // c的值为1 
// 枚举方向:上下左右
enum Direction {
  Up,
  Down,
  Left,
  Right
}

// 按下标取值,可得到枚举内容的字符串
console.log(Direction[0]) // "Up"

可以自定义下标的起点

// 将默认的下标 0  改为 下标 1,则后续下标会依次递增
enum Direction {
  Up = 1,
  Down,  // 2
  Left,  // 3
  Right  // 4
}

也可以自定义任意下标,未定义的在上一个的基础上递增

enum Direction {
  Up = 11,
  Down, // 12
  Left = 6, 
  Right, // 7
}

甚至下标可以相同

enum Direction {
  Up = 11,
  Down, // 12
  Left = 11,
  Right, // 12
}

console.log(Direction.Down); // 打印 12

console.log(Direction); // 打印 { '11': 'Left', '12': 'Right', Up: 11, Down: 12, Left: 11, Right: 12 }

如果下标使用了计算值或常量,那么该字段后面紧接着的字段必须设置初始值,不能默认递增值了!

const getValue = () => {
  return 0;
};
enum ErrorIndex {
  a = getValue(),
  b, // error 枚举成员必须具有初始化的值
  c
}
enum RightIndex {
  a = getValue(),
  b = 1,
  c
}
const Start = 1;
enum Index {
  a = Start,
  b, // error 枚举成员必须具有初始化的值
  c
}

字符串枚举

枚举成员为字符串时,其之后的成员也必须是字符串。

enum Direction {
  Up, // 未赋值,默认为0
  Down = '南',
  Left = '西',
  Right = '东'
}

类型断言 as

当你知道更确切的类型时,可以使用类型断言,类似类型转换,但不进行特殊的数据检查和解构。

它没有运行时的影响,只是在编译阶段起作用。 TypeScript会假设程序员已经进行了必须的检查。

let someValue: any = "this is a string";

方式一:as 【推荐】

let strLength: number = (someValue as string).length;

JSX中,只可用 as 语法断言

方式二:<>

let strLength: number = (<string>someValue).length;

函数

声明函数类型

  • 如果省略参数的类型,TypeScript 会默认这个参数是 any 类型;

  • 如果省略返回值的类型,如果函数无返回值,那么 TypeScript 会默认函数返回值是 void 类型;

  • 如果函数有返回值,那么 TypeScript 会根据我们定义的逻辑推断出返回类型。

  • 函数体内使用的外部变量的类型,不会体现在函数类型定义中。

// 命名函数
function add(arg1: number, arg2: number): number {
  return x + y;
}

// 箭头函数
const add = (arg1: number, arg2: number): number => {
  return x + y;
};
// 定义变量 add 并声明为函数类型
let add: (x: number, y: number) => number;

add = (arg1: number, arg2: number): number => arg1 + arg2;

使用 Interface 声明函数类型

interface Add {
  (x: number, y: number): number;
}

使用 type 声明函数类型

type Add = (x: number, y: number) => number;

可选参数

可选参数需放置在必选参数之后,用 ? 标注

let add: Add = (arg1: number, arg2?: number): string => arg1 + arg2;

默认参数

  • = 号标注参数的默认值
  • 所有必须参数后面的带默认初始化的参数都是可选的
function add(x: number, y: number = 20): number {
    return x + y
}

剩余参数

const handleData = (arg1: number, ...args: number[]) => {
  //
};

函数重载

强类型语言中的函数重载:定义几个函数名相同,但参数个数或类型不同的函数,在调用时传入不同的参数,编译器会自动调用适合的函数。

TS 中的函数重载:通过为一个函数指定多个函数类型定义,从而对函数调用的返回值进行检查。

  • 只能用 function 来定义,不能使用接口、类型别名等。
// 这个是重载的一部分,指定当参数类型为string时,返回值为string类型的元素构成的数组
function handleData(x: string): string[];
// 这个也是重载的一部分,指定当参数类型为number时,返回值类型为string
function handleData(x: number): string; 

// 这个就是重载的内容了,这是实体函数,不算做重载的部分
function handleData(x: any): any { 
  if (typeof x === "string") {
    return x.split("");
  } else {
    return x
      .toString()
      .split("")
      .join("_");
  }
}

handleData("abc").join("_");
handleData(123).join("_"); // error 类型"string"上不存在属性"join"
handleData(false); // error 类型"boolean"的参数不能赋给类型"number"的参数。

接口 interface

用于自定义任意类型

interface Point {
  x: number;
  y: number;
}

interface Point {
  x: number,
  y: number
}
  • 每个属性间的间隔,可以说 ; 也可以是,
interface Person {
  name: string,
  age: number
}

// 使用范例
let user: Person = {
  name: '朝阳',
  age: 30
}

可选属性 ?

interface Point {
  x: number;
  y?: number;
}

可选属性的位置没有限制,无需像函数的可选参数一样,必须放在必传参数的后面。

只读属性 readonly

interface Point {
    readonly x: number;
    readonly y: number;
}

赋值后, xy再也不能被改变

let p1: Point = { x: 10, y: 20 };
p1.x = 5; // error!

属性的合并

interface Person {
  name: string;
}

interface Person {
  age: number;
}

let user: Person = {
  name: "朝阳",
  age: 35,
};

但已经指定过类型的属性,不能改为新类型

interface Person {
  name: string;
}

interface Person {
  name: number; // 报错 后续属性声明必须属于同一类型
}

若想定义为联合类型,也需在最初的地方定义!

interface Person {
  name: string | number;
}

定义函数类型

interface SumFunc {
  (a: number, b: number): number;
}

let c: SumFunc = (a, b) => a + b;

let d = c(1, 2);

定义索引类型

当定义了索引类型之后,数组的length方法,将不存在,包括Array原型链上的其他方法也不存

interface Dic {
  [id: number]: string;
}

const dic1: Dic = {
  0: "你",
  1: "好",
};

const dic2: Dic = ["你", "好"];

定义类类型(含接口的实现 implements )

用于给类添加约束,比如限定类必须含有某类型的属性/方法等。

// 定义接口 ClockInterface,有一个属性 currentTime,值类型为 Date
interface ClockInterface {
  currentTime: Date;
}

// 定义类 Clock 实现接口 ClockInterface
class Clock implements ClockInterface {
  // 因接口 ClockInterface 中有一个Date 类型的属性 currentTime,所以 类 Clock 也必须有这个属性
  currentTime: Date;
  constructor(arg: Date) {
    // 在构造方法中,需给接口 ClockInterface 限定的属性 currentTime 赋值
    this.currentTime = arg;
  }
}

可简写为

class Clock implements ClockInterface {
  constructor(public currentTime: Date) {}
}

绕开多余属性的类型检查

在这里插入图片描述

方式一:索引签名 【推荐】

interface myType {
  name: string;
  // 添加索引签名来兼容多余属性
  [prop: string]: any;
}

方式二:类型断言 【不推荐】

强行声明其为目标类型

let myInfo: myType = {
  name: "朝阳",
  age: 30,
} as myType;

方式三:类型兼容 【不推荐】

interface myType {
  name: string;
}

// 使用解构赋值,避开多余属性
let getName = ({ name }: myType) => {
  return name;
};

let myInfo = {
  name: "朝阳",
  age: 30,
};

console.log(getName(myInfo));

接口的继承 extends

与类的继承类似

// 基础类型 Person
interface Person {
  name: string;
}

// Student 类型在 Person类型的基础上,新增了学号 sid
interface Student extends Person {
  sid: number;
}

// Teacher 类型在 Person类型的基础上,新增了学科 class
interface Teacher extends Person {
  class: string;
}

let student1: Student = {
  name: "朝阳",
  sid: 1,
};

let teacher1: Teacher = {
  name: "朝阳",
  class: "前端开发",
};

同时继承多个接口

extends 后写多个接口即可,用 , 间隔

interface Shape {
    color: string;
}

interface PenStroke {
    penWidth: number;
}

interface Square extends Shape, PenStroke {
    sideLength: number;
}

接口继承类

  • 接口继承了类之后,会继承成员(类型),但是不包括实现;
  • 接口还会继承 private 和 protected 修饰的成员,但是这个接口只可被这个类或它的子类实现
// 定义类 Person
class Person {
  name: string;
  constructor(arg: string) {
    this.name = arg;
  }
}

// 接口 I 继承类 Person
interface I extends Person {}

// 接口 I 只能被 类 Person 或 类 Person 的子类实现 implements
class Student extends Person implements I {}

泛型

在定义函数、接口或类的时候不预先指定数据类型,而在使用时再指定类型的特性。

泛型的作用

泛型可以提升应用的可重用性,如使用其创建组件,则可以使组件可以支持多种数据类型。

使用泛型

let printNum = (arg: number) => {
  console.log(arg);
};

printNum(123);
printNum("123"); // 会报错,因参数只能是数字
let printString = (arg: string) => {
  console.log(arg);
};

printString(123); // 会报错,因参数只能是字符串
printString("123");

怎样才能写一个通用的打印方法呢?
使用泛型!

let printAnyType = <T>(arg: T) => {
  console.log(arg);
};

printAnyType(123);
printAnyType("123");

可见泛型即将类型设定为一个变量,当代码执行时传入的类型是啥,它就是啥,从而大大拓展了代码的通用性。

泛型的语法

  • <> 包裹
  • 类型的变量通常用大写字母 T 表示,也可以是任意其他大写字母

多个泛型

// 定义函数 - 让元组中的两个元素互换位置
let exchange = <T, U>(tuple: [T, U]): [U, T] => {
  return [tuple[1], tuple[0]];
};

let tuple1: [number, string] = [1, "朝阳"];

let tuple2 = exchange(tuple1);

console.log(tuple2);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/753393.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

探索Facebook的未来世界:数字社交的演进之路

在数字化和全球化的浪潮中&#xff0c;社交网络如Facebook已经成为了人们日常生活不可或缺的一部分。然而&#xff0c;随着技术的迅猛发展和用户需求的不断变化&#xff0c;Facebook正在经历着社交平台的演进之路。本文将探索Facebook的未来世界&#xff0c;分析数字社交的发展…

上海六十中学多功能气膜馆项目:轻空间全速推进

项目进展捷报频传 上海六十中学多功能气膜馆项目土建工作已基本完工&#xff0c;今天轻空间团队正式进场&#xff0c;展开气膜部分的施工。我们将为上海六十中学打造一个现代化、环保、高效的多功能气膜馆&#xff0c;提供优质的运动和活动场所。 现场施工一片繁忙 在施工现场&…

Windows部署MinIO,搭建本地对象存储服务

一、前言 二、MinIO介绍 三、Windows部署MinIO服务 1、准备工作 2、下载MinIO服务 3、启动MinIO服务 4、设置用户名密码 5、创建.bat文件启动服务 四、MinIO基本操作 1、存储桶管理 2、对象管理 3、数据查看 一、前言 基于外网的项目&#xff0c;可以使用阿里云等…

python数据分析与可视化二

公共部分 # 引入数据分析工具 Pandas import pandas as pd # 引入数据可视化工具 Matplotlib import matplotlib.pyplot as plt # 引入科学计算库numpy import numpy as np from scipy import stats #解决输出时列名对齐问题 pd.set_option(display.unicode.east_asian_wid…

【Redis-04 补充】Redis事务

【Redis-04 补充】Redis事务 1. 事务冲突的问题1.1 举例1.2 悲观锁1.3 乐观锁1.4 Redis中的乐观锁 WATCH key [key …]1.5 Redis事务三特性 2. 秒杀案例2.1 相关代码2.2 模拟并发工具httpd-tools 3. 设计一个秒杀系统3.1 预热库存3.2 秒杀请求3.3 生成订单3.4 限流与防刷 4. 总…

如何找合适的C++项目给自己的简历加分?

在开始前刚好我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「嵌入式的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家&#xff01;&#xff01;&#xff01; C的工作多种多样&#x…

[深度学习] 前馈神经网络

前馈神经网络&#xff08;Feedforward Neural Network, FFNN&#xff09;是人工神经网络中最基本的类型&#xff0c;也是许多复杂神经网络的基础。它包括一个输入层、一个或多个隐藏层和一个输出层。以下是详细介绍&#xff1a; 1. 结构 1. 输入层&#xff08;Input Layer&am…

入门网络安全工程师要学习哪些内容

大家都知道网络安全行业很火&#xff0c;这个行业因为国家政策趋势正在大力发展&#xff0c;大有可为!但很多人对网络安全工程师还是不了解&#xff0c;不知道网络安全工程师需要学什么?知了堂小编总结出以下要点。 网络安全工程师是一个概称&#xff0c;学习的东西很多&…

Flexsim物流仿真入门-利用网络节点控制行走路线

在布局优化过程中&#xff0c;往往叉车&#xff0c;操作人员的搬运&#xff0c;是会按照一定的行走路线进行的&#xff0c;这就需要我们进行节点的设计&#xff0c;以此来实现特定路径的行走。 在构建过程中&#xff0c;这里将会以案例的形式进行讲解说明。 1&#xff09;构建…

【Linux】进程间通信_3

文章目录 七、进程间通信1. 进程间通信分类命名管道 未完待续 七、进程间通信 1. 进程间通信分类 命名管道 管道应用的一个限制就是只能在具有共同祖先&#xff08;具有亲缘关系&#xff09;的进程间通信。如果我们想在不相关的进程之间交换数据&#xff0c;可以使用FIFO文件…

操作系统之《死锁与银行家算法》【知识点+详细解题过程】

知识点&#xff1a; 1、什么是死锁&#xff1f;&#xff08;别名"三角恋"&#xff0c;我喜欢你你喜欢他他喜欢我&#xff0c;明明都单身但是就是‘占有’不了&#xff09; 一组进程中&#xff0c;每个进程都无限等待被该组进程中另一进程所占有的资源,因而永远无法…

vue-cli的搭建过程

一、创建一个vue2的项目 二、创建成功后删除这三个文件 三、新建一个App.vue文件 四、在文件中添加这一段话 五、打开命令框输入指令下载router路由 六、新建一个router目录&#xff0c;新建index.js文件 七、导入你的路由&#xff0c;进行配置 打开命令行工具&#xff0c;进入…

【Python Tips】创建自己的函数包并安装进Anaconda,像引入标准包一样直接import导入

目录 一、引言 二、方法步骤 步骤一&#xff1a;创建包目录结构 步骤二&#xff1a;配置__init__.py文件 步骤三&#xff1a;文件夹外配置setup.py文件 步骤四&#xff1a;终端Pip安装 三、结尾 一、引言 在编写项目代码的时候&#xff0c;有些自定义功能的函数是可以复用的。…

Java面向对象特性

Java继承&#xff1a; 继承的概念&#xff1a; 在Java中&#xff0c;继承&#xff08;inheritance&#xff09;是面向对象编程的一个重要概念&#xff0c;它允许一个类&#xff08;子类&#xff09;继承另一个类&#xff08;父类&#xff09;的属性和方法。通过继承&#xff0c…

MySQL高级-SQL优化- order by 优化(尽量使用覆盖索引、注意联合索引创建的规则、增大排序缓冲区大小)

文章目录 0、order by优化原则1、Using filesort2、Using index3、连接数据库4、查看索引5、删除索引6、按照年龄进行排序7、执行计划 order by age8、执行计划 order by age,phone9、创建联合索引 (age,phone)10、再次执行计划 order by age11、再次执行计划 order by age,pho…

SpringMVC处理器映射器HandlerMapping详解

目录 一、前言 二、initHandlerMappings 三、处理器映射器架构 策略接口 请求链 模版类 四、RequestMappingHandlerMapping的初始化 HandlerMethod映射器模版类的初始化 AbstractHandlerMethodMapping.MappingRegistry&#xff1a;内部类注册中心 五、Reques…

从菌群代谢到健康影响——认识肠道丙酸和丁酸

谷禾健康 短链脂肪酸这一词经常出现在谷禾的文章和报告中&#xff0c;那你真的了解短链脂肪酸吗&#xff1f;短链脂肪酸(SCFA)主要是肠道微生物群在结肠内通过发酵碳水化合物(包括膳食和内源性碳水化合物&#xff0c;主要是抗性淀粉和膳食纤维)和一些微生物可利用的蛋白质而产生…

一个人 三个月 干了二十万

相信很多人是被这个标题吸引进来的&#xff0c;但我并不是标题党&#xff0c;我也很讨厌标题党&#xff0c;这篇文章也不在乎流量&#xff0c;更多的是想记录下。 出来创业三个多月了&#xff0c;给大家汇报一下这段时间的业绩吧。一个人&#xff0c;三个多月&#xff0c;干了…

线性图标绘制指南:从基础到精通

图标在生活中随处可见。相比文字来说&#xff0c;图标可以让人在更短的时间内认知并了解信息&#xff0c;并且大大提升信息的视觉美观性&#xff0c;增加设计的艺术感染力。在用户界面中使用图标&#xff0c;是一种用户熟知的设计模式。而线性图标是通过提炼图形轮廓&#xff0…

TIOBE 6月榜单出炉!编程语言地位大洗牌,谁才是王?

C历史上首次超越C&#xff01;&#xff01;&#xff01; TIOBE 公布了 2024 年 6 月编程语言的排行榜&#xff1a;https://www.tiobe.com/tiobe-index/ 排行榜 以下列出的语言代表了第51至第100名。由于它们之间的差异相对较小&#xff0c;编程语言仅以字母顺序列出。 ABC, A…