请用Typescript写出20个数组方法的声明

这篇具有很好参考价值的文章主要介绍了请用Typescript写出20个数组方法的声明。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

前段时间看直播看到狼叔直播驳斥”前端已死论“,前端死没死不知道,反正前端是拿不到以前那么多工资了;好,进入正题,狼叔在直播间提到要求前端写出20个数组上的方法,这确实不太简单,但是只写出方法没有什么意义,我们今天来写20个数组方法的声明;这要求我们对于每一个方法的每一个参数用法都了解透彻。

第一步:分门别类

一口气写出20个数组方法有点难度,我们可以在脑海里对数组方法进行分类,同一类操作归为一类,这样写是不是更加简单了呢?

添加元素类:push、unshift
删除元素类:pop、shift、splice
数组转字符串类:toString、join
遍历类:forEach、reduce、reduceRight、map、filter、some、every
排序:sort
拼接:concat
索引:indexOf、lastIndexOf

一口气写了整整19个,就是不够那20个,看来我不够资格说”前端已死“,来查一查差哪些:

翻转:reverse
浅拷贝:slice
为什么写这些?因为这些是vscode中lib.es5.d.ts中定义的数组方法

第二步:实现数组接口
数组需要接收一个泛型参数,用来动态获取数组中元素类型

interface MyArray<T> {
  
}

第三步:方法定义

首先是元素添加类方法:push、unshift,千万不要忘了他们有返回值,返回值是新数组的length

push(...args: T[]): number;
unshift(...args: T[]): number;

删除元素类方法,前两个比较好写,它们的返回值都是删除的那个元素,但是需要注意的是空数组调用后返回undefined;

pop(): T | undefined;
shift(): T | undefined;
// 错误的写法:splice(start: number, deleteNum: number, ...args: T[]): T[];

splice这样写还有问题,因为splice只有第一个参数是必传,这样就需要写多个声明了

splice(start: number, deleteNum?: number): T[];
splice(start: number, deleteNum: number, ...args: T[]): T[];

然后是数组转字符串类:toString、join,没有难度直接写

join(param?: string): string;
toString(): string;

遍历类:forEach、reduce、reduceRight、map、filter、some、every 我们一个一个地来写,首先是forEach方法,这个方法我们常用的就只有回调函数,但是其实还有一个参数可以指定回调函数的this

forEach(callbackFn: (value: T, index: number, array: T[]) => void, thisArg?: any): void;

reduce这个方法可以实现累加器,也是我们最常用的方法之一,reduceRight与reduce的区别就在于它是从右往左遍历

reduce(callbackFn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue: T): T;

map方法遍历数组并且会返回一个新的数组,它是一个纯函数

map(callbackFn: (value: T, index: number, array: T[]) => T, thisArg?: any): T[];

后面的一些遍历方法我们就不再赘述,基本上都遵从回调函数,this绑定参数,这种固定模式

后面的一些方法都比较简单,最后把写好的方法定义都汇总起来:

interface MyArray<T> {
  length: number;
  // 数组添加元素
  push(...args: T[]): number;
  unshift(...args: T[]): number;

  // 数组删除元素
  pop(): T | undefined;
  shift(): T | undefined;
  splice(start?: number, deleteNum?: number): T[];
  splice(start: number, deleteNum?: number): T[];
  splice(start: number, deleteNum: number, ...args: T[]): T[];

  // 数组索引
  indexOf(item: T): number;
  lastIndexOf(item: T): number;

  // 数组遍历
  forEach(callbackFn: (value: T, index: number, array: T[]) => void, thisArg?: any): void;
  reduce(callbackFn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue: T): T;
  reduceRight(callbackFn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T): T;
  some(callbackFn: (value: T, index: number, array: T[]) => boolean, thisArg?: any): boolean;
  every(callbackFn: (value: T, index: number, array: T[]) => boolean, thisArg?: any): boolean;
  map(callbackFn: (value: T, index: number, array: T[]) => T, thisArg?: any): T[];

  //   数组与字符串
  join(param?: string): string;
  toString(): string;
  toLocalString(): string;

  //   数组排序
  sort(callbackFn: (a: T, b: T) => number): T[];

  // 数组扁平化
  flat(deepSize: number): T[];

  //   数组的拼接
  concat(...args: T[]): T[];

  //   数组的拷贝
  slice(start?: number, end?: number): T[];

  //   数组翻转
  reverse(): T[];
}

前面都是前奏,现在开始今天的正题,手写数组的这些方法。

第四步 实现这些方法

首先我们修改一下接口定义的名称:IMyArray,然后定义MyArray类实现该接口,编辑器会自动将上面的方法注入

class MyArray<T> implements IMyArray<T> {
}
先实现push方法:

push(...args: T[]): number {
 const len = args.length;
 for (let i = 0; i < len; i++) {
   this[this.length++] = args[i];
 }
 return this.length;
}
其实我们实现的是一个类数组,只不过含有数组的所有方法,这里经常会使用类数组来考察对push的理解,比如这道题:

const obj = { 
 0:1, 
 3:2, 
 length:2, 
 push:[].push 
} 
obj.push(3);
然后实现一个splice,注意splice是一个原地修改数组的方法,所以我们不能借助额外的空间实现,这里我们还是使用Array.prototype.splice的方式来实现,类数组不能通过length属性删除元素

Array.prototype.splice = function splice(start: number, deleteNum = 1, ...rest: any[]) {
  if (start === undefined) {
    return [];
  }

  const that = this;
  let returnValue: any[] = [];
  // 将begin到end的元素全部往前移动
  function moveAhead(begin: number, end: number, step: number) {
    const deleteArr: any[] = [];
    // 可以从前往后遍历
    for (let i = begin; i < end && i + step < end; i++) {
      if (i < begin + step) {
        deleteArr.push(that[i]);
      }
      that[i] = that[i + step];
    }
    return deleteArr;
  }
  function pushAtIdx(idx: number, ...items: any[]) {
    const len = items.length;
    const lenAfter = that.length;
    // 在idx处添加len个元素,首先需要把所有元素后移len位,然后替换中间那些元素
    for (let i = idx; i < idx + len; i++) {
      if (i < lenAfter) {
        that[i + len] = that[i];
      }

      if (i - idx < len) {
        that[i] = items[i - idx];
      }
    }
  }
  if (deleteNum >= 1) {
    returnValue = moveAhead(Math.max(start, 0), that.length, deleteNum);
    that.length -= deleteNum;
  }

  pushAtIdx(start, ...rest);
  return returnValue;
};

后面的实现我们都是用数组来实现,比如实现其中某一个遍历的方法,我们就实现比较复杂的比如reduce,reduce的实现比较简单

Array.prototype.reduce = function <T>(
  callbackFn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T,
  initialValue?: T
): T {
  // reduce如果有初始值那么以初始值开始计算,如果没有初始值那么用数组第一项作为初始值
  let startIndex = 0;
  const len = this.length;
  let ans = initialValue;
  if (initialValue === undefined) {
    ans = this[0];
    startIndex = 1;
  }

  for (let i = startIndex; i < len; i++) {
    ans = callbackFn(ans, this[i], i, this);
  }
  return ans;
};

然后再实现一个reverse数组翻转方法,我们可以遍历前一半的数据,然后分别与后面一半进行交换,这样就完成了原地翻转:

Array.prototype.reverse = function () {
 const len = this.length;
 const that = this;
 function swap(a, b) {
   const tmp = that[a];
   that[a] = that[b];
   that[b] = tmp;
 }
 for (let i = 0; i < len >> 1; i++) {
   swap(i, len - i - 1);
 }
 return this;
};

至于sort和flat方法这些都有很多实现方式,我们可以参考一下V8官方的文档;从文档中我们可以发现:
请用Typescript写出20个数组方法的声明,typescript,typescript,前端,javascript

之前的sort方法是基于快排,并且是一种不稳定的排序算法,后来V8将sort迁移到了Torque,tq是一种特殊的DSL,利用Timsort算法实现了稳定的排序,Timsort可以看成一种稳定的归并排序

总结
我们先从数组的20个方法为切入点,研究了这些方法的ts定义,用法,顺便手写模拟了一下它们,然后对于比较复杂的sort算法我们了解了一下它的原理,显然sort算法已经不是那个以前用快排实现的不稳定的排序算法了,现在是一种稳定的排序算法,并且基于归并排序,所以归并排序我们一定要掌握好;另外这种由浅入深的学习方法,值得大家去实践;

针对标题,前端有没有死,我想大家自己心里自有答案;文章来源地址https://www.toymoban.com/news/detail-600885.html

到了这里,关于请用Typescript写出20个数组方法的声明的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • TypeScript中的类型声明declare

    在 TypeScript 中, declare 用于定义 全局 变量、函数和类型等 ,提供了一种在编译过程中告诉TypeScript编译器某个标识符的类型的方式。它告诉编译器:虽然它在当前文件中没有声明,但它在其他地方已经存在了。也就是说,declare让 编译器 知道 这些声明的实体是在编译

    2024年02月12日
    浏览(47)
  • TypeScript的变量声明的各种方式

    TypeScript是一种静态类型的JavaScript超集,它为JavaScript代码提供了类型检查和更好的代码组织结构。在TypeScript中,变量声明是非常重要的,因为它们定义了变量的类型和范围。本文将详细介绍TypeScript的变量声明,并通过代码案例分析来说明其用法。 变量声明 在TypeScript中,变

    2024年02月10日
    浏览(78)
  • 【TypeScript】类型断言-类型的声明和转换(五)

    一、简介 TypeScript 断言是指在编写代码时,开发者能够告诉编译器某个值的具体类型,从而可以在编译阶段强制类型检查。 这其实在某些强类型语言中,类似于强制类型转换的操作。 类型断言有两种形式实现: 尖括号语法 as语法 二、断言形式 2.1 尖括号语法 尖括号语法:开

    2024年02月13日
    浏览(46)
  • 【TypeScript】中关于 { 声明合并 } 的使用及注意事项

    概念 : 在TS中,如果定义了多个 相同命名 的函数,接口或者class 类,那么它们会自动合并成一个类型 函数的合并: 前面章节讲解的函数重载就是使用了定义多个函数的类型进行合并: 接口的合并: 注意 : 合并时,如果出现同名的属性,类型 必须要保持唯一一致 接口中

    2024年02月13日
    浏览(76)
  • 【TypeScript】TS类型断言-类型的声明和转换(五)

    🐱个人主页: 不叫猫先生 🙋‍♂️作者简介:前端领域新星创作者、华为云享专家、阿里云专家博主,专注于前端各领域技术,共同学习共同进步,一起加油呀! 💫系列专栏:vue3从入门到精通、TypeScript从入门到实践 📝个人签名:不破不立 📢资料领取:前端进阶资料以

    2024年02月22日
    浏览(37)
  • 前端TypeScript学习day05-索引签名、映射与类型声明文件

    (创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,请留下您的足迹)              目录 索引签名类型  映射类型 索引查询(访问)类型 基本使用  同时查询多个索引的类型  TypeScript 类型声明文件  概述 TS 的两种文件类型  类型声明文件的

    2024年02月08日
    浏览(47)
  • TypeScript入门指南:特性、安装配置、类型声明、编译选项、面向对象等详解

    了解TypeScript的特性、安装配置步骤、类型声明方式、编译选项及面向对象编程方法。适合初学者学习和实践。

    2024年02月12日
    浏览(49)
  • 解决 TypeScript 引入第三方包,无法找到模块“XXX”的声明文件

    例子: 报错 :无法找到模块“three”的声明文件。“e:/VScode/vite-demo/node_modules/three/build/three.module.js”隐式拥有 “any” 类型。 该包如果存在可尝使用 npm i --save-dev @types/three 安装,或者添加一个包含 declare module \\\'three\\\' 的新声明文件(.d.ts后缀,例如 vite-env.d.ts) 原因:npm安装的版本

    2024年02月06日
    浏览(61)
  • 【TypeScript】TS中type和interface在类型声明时的区别

    🐱 个人主页: 不叫猫先生 🙋‍♂️ 作者简介:2022年度博客之星前端领域TOP 2,前端领域优质作者、阿里云专家博主,专注于前端各领域技术,共同学习共同进步,一起加油呀! 💫优质专栏: vue3+vite+typeScript从入门到实践 📢 资料领取:前端进阶资料可以找我免费领取 🔥

    2023年04月26日
    浏览(59)
  • TypeScript系列, 通过vue3实例说说declare module语法怎么用[模块声明篇]

    本系列文章是我20年开始写的, 这个模块声明也是本系列的最后一课, 中间因为时间安排间隔了1年, 当时答应大家要补充的, 现在来还债😊. 中间的时间我写了vue3的入门教程, 现在写了一半了吧, 带视频的, 如果有需要的小伙伴可以去看看. https://www.yuque.com/books/share/c0ab3348-87ab-4

    2023年04月22日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包