基础教程 6. 数据去重算法、字符串常用方法

337 阅读7分钟

这是我参与8月更文挑战的第5天,活动详情查看:8月更文挑战

一、数组去重算法

1.1 双 for 循环去重

思路:

  1. 依次拿出数组中的每一项(排除最后一项:最后一项后面没有需要比较的内容)
  2. 和当前取出向后面的每一项依次比较
  3. 如果发现有重复的,我们把找到的这个重复项在原有数组中删除(ary.splice)
var ary = [1, 3, 3, 3, 5, 4];

for (var i = 0; i < ary.length - 1; i++) {
  var item = ary[i];
  // item: 依次拿出数组的每一项
  // i 当前拿出来的数组项的索引值
  // => 用当前项和后面的项比较,所以后面的第一项的索引是 i + 1
  for (var k = i + 1; k < ary.length; k++) {
    if (item === ary[k]) {
      // => 如果我们从容数组中取出来的项和后面的相等说明后面有重复项,所以需要删除当前项
      // ary.splice(k, 1);
      /*
      * 但是直接这样删除后一个问题,就是数组塌陷;当我们把当前项删除后,后面的每一项都要向前移动一个,也就是 原有数组的索引发生了改变,此时我们的k继续累加1,下一次再拿出来的结果就会跳过一位
      * 原数组 [1, 3, 3, 3, 5, 4]
      * 索引:  0  1  2  3  4 5
      * 循环
      * k = 2 后面有重复的3,删除索引为2的位置上的3,删除之后 数组变成:
      *     [1, 3, 3, 5, 4];
      * 索引:0  1  2  3  4
      * 此时,在不删的情况下,原数组中第二个3的索引是2,但是删除后,原来索引为2的那个3的索引变成了1,当i再++时,i就变成了3,所以就会漏掉一项。
      *
      *
      * */
      ary.splice(k, 1);
      k--; // 删除以后不能让k累加了,所以先给k--,然后再++相当于没加没减
    }
  }
}
console.log(ary);

1.2 对象法去重

原理:基于对象的属性名不能重复,我们可以实现高性能的数组去重

步骤:

  1. 创建一个空对象
  2. 遍历数组中的每一项,把数组每一项存储的值,当做对象的属性名和属性值存储起来。形如 {数组项1:数组项1, 数组项2: 数组项2} 第一次遍历时:数组项 1, 对象:{1: 1} 第二次遍历时:数组项 3, 对象:{1: 1, 3: 3}
  3. 在存储起来做一个判断,判断当前对象中是否存在这个属性了,如果不存在 对象[属性名] 就是undefined,说明这一个数组项在之前没有出现过,没出现就说明没有重复,然后直接存储在对象里。如果在之前出现过了,此时 对象[属性名] 的值就不是undefined,此时就不要存储到对象中,同时删除这一项。
var obj = {};

for (var i = 0; i < ary.length; i++) {
  var item = ary[i];
  if (obj[item] !== undefined) {
    // ary.splice(i, 1); 这种删除方式不好,如果数组很长,我们删除中间的某一项,后面的所有的索引都会重新计算,非常消耗性能。所以我们采用下面这种删除方式:
    // 1. 用数组的最后一项替换当前项
    // 2. 把数组的最后一项删除
    // 例如:数组var ary = [12, 23, 23, 34, 56]  想删除第二个23
    // 先把第二个23获取到 ary[2]
    // 再把数组的最后一项获取到:ary[ary.length - 1]
    // 然后再把23换成数组最后一项,ary[2] = ary[ary.length - 1]
    // 最后删除最后一项: ary.length--;

    ary[i] = ary[ary.length - 1]; // ary[i] 就是当前项,并且和再此之前已经重复过了
    ary.length--;
  } else {
    // 否则的情况就是:数组当前项在之前没有重复过,此时需要存储到对象里面
    obj[item] = item
  }
}

二、字符串常用方法

字符串特点:

字符串:字符串是被单引号或双引号包裹的零到多个字符。是js中基本数据类型。 在字符串中的每个字符,浏览器也都给他们分配了一个索引,第一字符的索引是0,第二字符的索引是1,第三个字符的索引是2...,所以通过 字符串[索引]的方式可以获取对应索引位置的字符。 字符串也是有length属性的,代表字符串中字符的个数;

tips: 有长度、有索引是不是可以用通过for 循环遍历它?

var str = '江外琉璃EverestTraining';

字符串常用方法

1. 通过制定索引获取字符或ASCII

  • 1.1 charAt(index) 获取字符串中索引为index的字符。
var s = str.charAt(3);
console.log(s);
  • 1.2 charCodeAt(index) 获取字符串中指定索引位置的字符的Unicode编码值,返回的是一个 0 - 65535的整数
var code = str.charCodeAt(5); // 69

2 复制和截取字符串

  • 2.1 substr(n, m); 从n开始截取m个,若不写m,则截取到末尾。如果n和m都不写,这截取全部;
var s1 = str.substr(1, 2);
var s2 = str.substr(1);
var s3 = str.substr();
console.log(s1, s2, s3);
  • 2.2 substring(n, m); 从索引n开始截取,截取到索引为m结束(不包含m),如果只写n,是从n开始截取到末尾;如果一个都不写,那就是截取全部;

var s4 = str.substring(1, 3);
var s5 = str.substring(1);
var s6 = str.substr();
console.log(s4, s5, s6);

3. 转换大小写(只能转英文字母)

  • 3.1 大写转成小写 toLowerCase()
var s7 = 'A'.toLocaleLowerCase();
console.log(s7);
  • 3.2 小写转大写 toUpperCase()
var s8 = 'a'.toUpperCase();
console.log(s8);

4. 获取指定字符在字符串中出现的位置

  • 4.1 indexOf() 获取字符在字符串中首次出现的位置,如果字符串中不包含这个字符,则返回-1
var idx1 = str.indexOf('珠');
console.log(idx1);

  • 4.2 lastIndexOf() 获取字符在字符串中最后一次出现的位置,如果字符串中不包含这个字符,则返回-1
var idx2 = str.indexOf('E');
console.log(idx2);

5. split() 按照指定的分隔符把字符串拆分成数组

数组中的 join 方法这个相反,join 是根据指定的分隔符数组项拼接成字符串

var str2 = 'I am a Front-end Engineer';
var ary = str2.split(' '); // 根据空格把 str2 拆分成一个数组
console.log(ary);

6. replace() 字符串替换

var str3 = 'liuliudashun';
// 5.1 replace(old, new)
var s9 = str3.replace('liuliu', '江外');
console.log(s9);

// 5.2 replace(old, function () { return new})
var s10 = str3.replace('liuliu', function () {
  return '江外'
});
console.log(s10);

7. match() 匹配,

如果匹配到,就返回一个数组,如果匹配不到就返回 null

var str4 = 'abcdefabcggg';
var ary2 = str4.match('abc');
console.log(ary2);

三、Math对象

Math对象,是浏览器中内置的专门处理数学计算的对象,Math内置了很多的数学方法。

1. Math.abs(); 获取绝对值

var m1 = Math.abs(-12.5);
var m2 = Math.abs(12.5);
console.log(m1, m2);

2. Math.floor(); 向下取整

var m3 = Math.abs(12.5);
console.log(m3);

3. Math.ceil(); 向上取整

var m4 = Math.ceil(12.5);
console.log(m4);

4. Math.round() 四舍五入

var m5 = Math.round(2.3);
var m6 = Math.round(3.7);
// 注意:负数是四舍六入
var m7 = Math.round(-2.4);
var m8 = Math.round(-2.6);
console.log(m5, m6, m7, m8);

5. Math.random() 生成一个0-1之间的随机小数

var m9 = Math.random();
console.log(m9);

5.2 生成一个n-m之间的随机数,不包含m。[n,m) 【左开右闭区间】的随机数

var n, m;
var ran = Math.round(Math.random() * (m - n) + n);

思考:如何获取一个字符串里随机的一个字符?

6. Math.sqrt(n) 获取的n的算术平方根

var m10 = Math.sqrt(9);
console.log(m10); // 3

7. Math.PI 获取圆周率

var pi = Math.PI();
console.log(pi);
console.log(pi.toFixed(2)); //给Math.PI() 保留2位小数; toFixed(x)是number的方法,作用:保留x位小数

四、随即验证码

基础版

  • 需求:
  1. 生成一个4位的随机验证码
  2. 把验证码插入到页面中展示出来 原理: 分析需求:
  3. 我们学习过的能够随机的只有随机数,我们需要通过数字和字符连接起来。
  4. 而字符串和数字有关联的就是索引和length,而字符和索引数字是一一对应的,我们要是生成一个随机数字,然后通过字符串索引取得这个随机数对应的字符,就可以达到随机字符的目的,既然是
  5. 我们需要4个,就是说上面的事情需要干4回,显然需要一个for循环
  • 具体步骤:
  1. 准备随机范围A-Z a-z 0-9
  2. 设置一空字符串,后面得到的字符都拼接到这个空字符串上
  3. 设置for循环,循环四次
  4. 获取页面中的div元素对象
  5. 通过设置div的innerHTML属性,把验证码插入到页面中

HTML代码:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>江外-随机验证码</title>
</head>
<body>
<div id="codeBox"></div>

<script src="js/7-随机验证码while循环版.js"></script>
</body>
</html>
var strbase = 'ABCDEFGHIGKLMNOPQRSTUVWXYZabcdefghigklmnopqrstuvwxyz0123456789';

var code = '';
for (var i = 0; i < 4; i++) {
  // 1.
  var ran = Math.round(Math.random() * (strbase.length - 0) + 0);
  var char = strbase[ran];
  code += char;
}
var codeBox = document.getElementById('codeBox');
codeBox.innerHTML = code;

不重复验证码

  • 需求:不重复验证码,A和a算重复

  • 分析:

  1. 我们之所以会重复,是因为随机出字符串后拼接之前没有检查在已有的验证码中是否已经存在相同字符;所以我们需要在拼接之前需要检查当前字符在已有的验证码字符串中是否放出现过(indexOf)
  2. 如何解决大小写也算重复呢?这样解决,我们把已经有的验证码全部转成大写,然后把我们本次获得字符也转成大写(toUpperCase)然后再判断是否出现过。如果没有出现过再拼接,如果出现过就不拼接。
  3. 如果出现过了,对于for循环来说已经跑了一轮了,此时不能给i ++,因为我们本轮没有获得有效的字符。如果++了就会导致如果出现重复了,有一次的字符没有拼接,最后循环四次只有三个字符。
  4. 为了解决3中中说的问题,我们不是直接在for循环中i++了,我们在满足拼接条件,成功拼接后i++
function validateCode() {
  var strbase = 'ABCDEFGHIGKLMNOPQRSTUVWXYZabcdefghigklmnopqrstuvwxyz0123456789';
  var code = '';
  for (var i = 0; i < 4;) {
    // 1.
    var ran = Math.round(Math.random() * (strbase.length - 0) + 0);
    var char = strbase[ran];
    var upperChar = char.toUpperCase();
    var upperCode = code.toUpperCase();
    if (upperCode.indexOf(upperChar) === -1) {
      code += char;
      i++;
    }
  }
  return code;
}

var ranCode = validateCode();
var codeBox = document.getElementById('codeBox');
codeBox.innerHTML = ranCode;

不重复验证码 while 循环版

while循环

js中还有一种循环,就是while循环, while单词的意思是当...的时候一直做某件事情,一直到条件不成立。

所以while循环表示只要条件成立就会执行循环体里面的代码。

while (循环的条件) {
    循环体
 }

思考:while循环的条件时什么?只要不满足什么条件我们就该一直循环? ? 我们循环干什么?获取验证码 ? 验证码有什么要求?4位不重复的 ? 我们在循环中判断重复与否,如果不重复,就拼接给code字符串,这个时候相当于获取到一个有效的字符串。如果我们获得字符串在之前已经存在过,这相当于我们没有获取到有效字符,所以就需要继续再来一次。重复执行这个操作,直到什么时候就不再找了?是已经获取到了4位验证码了。所以此时就该停止循环了

所以停止的条件是 code.length < 4 即只要code的字符串个数小于4就该接着随机

function validateCode() {
  var strbase = 'ABCDEFGHIGKLMNOPQRSTUVWXYZabcdefghigklmnopqrstuvwxyz0123456789';
  var code = '';
  while (code.length < 4) {
    var ran = Math.round(Math.random() * (strbase.length - 0) + 0);
    var char = strbase[ran];
    var upperChar = char.toUpperCase();
    var upperCode = code.toUpperCase();
    if (upperCode.indexOf(upperChar) === -1) {
      code += char;
    }
  }
  return code;
}
var codeBox = document.getElementById('codeBox');
codeBox.innerHTML = validateCode();