博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
如何简单并优雅的处理一类操作数组元素的问题
阅读量:6940 次
发布时间:2019-06-27

本文共 4927 字,大约阅读时间需要 16 分钟。

本期题目

「 题目 」: 删除给定一维数组(暂不考虑多维)元素中不符合条件的元素,结果返回新的数组

首先,我们在实际开发中会遇到很多处理数组的场景,其实无非就是四个字——"增删查改"。

但是,真的只是简单的增删查改吗?

NO!

如果只是这么简单,那写这篇博文就有点画蛇添足了!

下面让我们分析一下题目所涉及的知识点:

考点思考


  1. 数组的遍历、处理;
    1. 遍历:使用循环遍历数组;
    2. 循环使用 while 即可,结合判断函数的元素判断的返回值;
  2. 对元素的判断处理;
    1. 传递一个判断函数(可以灵活定义,拓展性比较好);
    2. 判断函数:
      1. 符合条件的返回 true;
      2. 不符合条件的返回 false

相关回顾


让我们简单回顾一下数组 Array 对象的方法:

  • push( ):向数组的末尾添加一个或更多元素,并返回新的长度;
  • unshift( ):向数组的开头添加一个或更多元素,并返回新的长度;
  • pop( ):删除并返回数组的最后一个元素;
  • shift( ):删除并返回数组的第一个元素;
  • concat( ):连接两个或更多的数组,并返回结果;
  • join( ):把数组的所有元素放入一个字符串。元素通过指定的分隔符进行分割;
  • reverse( ):颠倒数组中元素的顺序;
  • sort( ):对数组的元素进行排序;
  • slice( ):从某个已有的数组返回特定的元素;
  • splice( ):删除元素,并向数组添加新的元素;
  • valueOf( ):返回数组对象的原始值;
  • toString( ):把数组转化为字符串,并返回结果;
  • toSource( ):返回该对象那个的源码;
  • toLocaleString( ):把数组转化为本地数组,并返回结果;

PS:以上数据来自

其次,我们分析一下,题目是对数组元素的删除,有关 Array 对象的删除操作就是以下的四种方法:

  1. pop( ):删除并返回数组的最后一个元素;
  2. shift( ):删除并返回数组的第一个元素;
  3. slice(startIndex,endIndex):从某个已有的数组返回特定的元素;
  4. splice(index,howmany,newitem01,newitem02... ):删除/添加元素,并向数组添加新的元素;

简单分析一下区别:

方法名称 方法介绍 是否改变原数组 返回值 备注(适用场景)
pop(  ) 末尾删除 末尾元素
获取数组元素
末尾依次删除数组元素
shift(  ) 开头删除 开头元素
获取数组元素
开头依次删除数组元素
slice(  ) 特定截取 不会 一个新数组 返回新的数组,不改变原数组
splice(  )
特定删除
特定添加
处理后的原数组 直接改变原有数组

再让我们回顾一下常见的几种循环

JavaScript 常见的三种循环

  1. while

  2. do while

  3. for

while 循环

语法结构与使用步骤:
// 语法结构while(/**条件**/){// 代码块;改变条件}// 使用步骤// 1. 初始化变量// 2. 判断条件// 3. 执行代码块// 4. 改变初始条件// 5. 判断条件// 示例var i=0,      _arr=[0,1,2,3,4,5];while(i<=_arr.length-1){    // 做点什么    console.log(i);    // 改变初始条件    i--;}// 结果// 0,1,2,3,4,5复制代码

do while 循环

语法结构与使用步骤
// 语法结构do {// 代码块} while (// 条件);// 使用步骤:// 1.初始化变量// 2.无条件执行一次// 3.判断条件// 4.执行代码块// 5.改变初始条件// 6.判断条件// 示例var i=0,    _arr=[0,1,2,3,4,5,6,7,8];do {    // 做点什么    console.log(_arr[i]);    i++;} while(i<=_arr.length)// 结果// 0,1,2,3,4,5,6,7,8复制代码

for 循环

语法结构与使用步骤
// 语法结构for(//初始化变量;//判断条件;//改变初始化变量){
// 代码块}// 使用步骤// 1. 初始化变量(只会执行一次)// 2. 判断条件// 3. 执行代码块// 4. 改变初始化变量(在循环体里面去做这件事,避免死循环)// PS:建议不要嵌套多层循环(三层以上),// 防止处理逻辑复杂,易进去死循环,造成CPU使用率飙升,// 内存泄漏,要考虑代码执行的性能问题// 示例// for循环的较优写法var i, _arr=[1,3,6,12,3,7];for(i=_arr.length;i--;){ // 使用_arr[i]做点什么吧 console.log(_arr[i]);}// 结果// 7,3,12,6,3,1复制代码
  • do while 会无条件执行一次,再进行条件判断
  • 使用 while 时不知道循环次数,使用 for 时知道循环次数
  • while 是条件循环,for 是限定了循环次数

代码实现


结合以上基本知识点回顾与分析,现给出以下的实现方案:

  1. 定义一个 dropElements 方法:两个传参 arr,judgefn;
    1. arr:原数组参数;
    2. judgefn:条件判断函数[灵活定义判断条件,结果 return true/false];
  2. 对传参 arr,进行代码健壮性测试:类型/空值判断;
  3. 循环对 arr[0]做判断;
  4. 当检测到数组元素不符合 judgefn 中的条件时,对数组进行截取操作;
  5. 截取使用 _arrNew = arr.slice(1); // Array.slice(stratindex,[endindex]);
  6. 截取后的新数组赋值给中间临时变量_arrNew;
  7. 最后 return 处理后的 _arrNew
// 代码如下 :function dropElements(_arr, judgefn) {	// arr健壮性	// 1.是否是数组	if (!Array.isArray(_arr)) {		// console.error("不是数组,请检查参数!");		return false;		// 如果是需要对结果做容错处理,可以直接返回空数组 : [];		// return [];	}	// 2.是否为空,为空时,直接返回原值	else if (_arr.length === 0) {		console.debug("数组为空,原值返回!");		return _arr;	}	// 数组元素判断处理	// 判断参数是否是空数组,同时判断是否符合 judgeefn 的判断条件	// 不是空数组的话,并且不满足条件的话--judgefn(_arr[0])为false时,做截取操作并返回新的数组;	let _arrNew;	while (_arr.length > 0 && !judgefn(_arr[0])) {		_arrNew = _arr.slice(1);	}	// 返回结果	return _arrNew;}复制代码

结果测试


function dropElements(_arr, judgefn) {	// 健壮性	// 1.是否是数组	if (!Array.isArray(_arr)) {		// console.error("不是数组,请检查参数!");		return false;	}	// 2.是否为空,为空,直接返回原值	else if (_arr.length === 0) {		console.debug("数组为空,原值返回!");		return _arr;	}	// 数组元素判断处理	// 判断参数是否是空数组,同时判断是否符合 judgeefn 的判断条件	// 不是空数组的话,并且不满足条件的话--judgefn(_arr[0])为false时,做截取操作并返回新的数组;	while (_arr.length > 0 && !judgefn(_arr[0])) {		_arr = _arr.slice(1);	}	// 返回结果	return _arr;}// _arr健壮性测试:String,Object,Array,Boolean,Null,Undefined,Number,Symbol// 测试环境(参数,方法)搭建var _undefined, // 提前定义基本类型Undefined的数值	// 条件判断函数	testJudgeFn = (n) => n >= 3,	// 测试数据	testData = [		{ type: "string", value: "_string", result: "" },		{ type: "object", value: { a: 1, b: 2 }, result: "" },		{ type: "array", value: [0, 1, 2, 3, 4, 5, 6, 7, 8], result: "" },		{ type: "boolean", value: true, result: "" },		{ type: "boolean", value: false, result: "" },		{ type: "null", value: null, result: "" },		{ type: "number", value: 100, result: "" },		{ type: "number", value: 0, result: "" },		{ type: "number", value: NaN, result: "" },		{ type: "undefined", value: _undefined, result: "" },	];// 结果测试并打印for (let i = 0, testLength = testData.length; i < testLength; i++) {	testData[i].result =		dropElements(testData[i].value, testJudgeFn) === false			? `Params Type Error:${testData[i].type}`			: dropElements(testData[i].value, testJudgeFn);	// 打印结果	console.table(`第${i + 1}次测试结果:`, testData[i].result);}复制代码

贴出测试结果的截图:

对于这个简单的数组问题,你想到了什么?

小总结


你是否会有着以下问题:

  • 为什么使用传递一个函数而不是把具体判断条体放进函数体内部?
  • 为什么使用 while 循环,而不是 for 循环等其他方式?
  • 为什么还要考虑它的传参类型,空值,容错...等等?

简单解答:

  • 定义一个判断函数,是为了增加它的判断灵活度,可能它的期望是返回数组中的字符串对象...;
  • 循环的使用应该根据实际处理的方式,选择相应的,而不是用到循环就是 for 循环,还有时候 do while,while 循环相比 for 循环更优;
  • 对于与一个函数,它的传参多数情况下是不可控制,必要的类型校验,空值校验处理,容错处理,代码的健壮性都需要考虑,只有这样才可以保证代码逻辑的稳定性...

更深的思考:

  1. 数组的 slice()、splice()用法,还使用在哪些具体的实际应用,它的高级使用有哪些?
  2. 为什么使用单 var 的变量命名方式,有什么好处?
  3. 一般我们是如何写 for 循环,如何结合实际场景写一个较优的 for 循环处理逻辑?
  4. 如何拆分一个功能,实现高内聚低耦合、细分确定功能逻辑的单一职责...

转载地址:http://erinl.baihongyu.com/

你可能感兴趣的文章
084:QuerySet API详解prefetch_related方法
查看>>
RMQ算法
查看>>
Myeclipse 启动tomcat项目报Out of memory: java heap space
查看>>
easyui-笔记
查看>>
php include 绝对路径 dirname(__FILE__)
查看>>
软考倒计时19天:招投标法、合同法、采购法
查看>>
通过style控制圆形imageView显示
查看>>
K - 4 Values whose Sum is 0(中途相遇法)
查看>>
实验五 Servlet过滤器
查看>>
GIT版本控制系统(二)
查看>>
关于一些测绘软件的评价
查看>>
UISearchBar--改变内部输入框的背景颜色
查看>>
使用redis-cli --pipe快速插入数据
查看>>
数据结构----队列:顺序队列&顺序循环队列、链式队列、顺序优先队列
查看>>
福大软工1816 · 第三次作业 - 结对项目1(原型设计)
查看>>
三国杀的10个人生感悟
查看>>
nginx错误:unknown directive "锘? in F:\nginx/conf/nginx.conf:3
查看>>
【数据结构-文都】第二章 线性表(1)
查看>>
Ubuntu快捷键
查看>>
mycp
查看>>