求数组极值、方法封装、箭头函数

一、求数组极值

  • 需求:求数组中的最大值和最小值
  1. let ary = [1, 9, 18, 234, 23];

1. 先升序排序,排序后,数组的第一项就是最小值

  1. ary.sort(function (a, b) {
  2. return a - b;
  3. });
  4. let min = ary[0];
  5. // 接着降序排列,排序后数组的第一项就是最大值;
  6. ary.sort(function (a, b) {
  7. return b - a;
  8. });

2. 假设法

  • 求最小值:假设第一项就是最小值;
  1. let min1 = ary[0];
  2. for (let i = 1; i < ary.length; i++) {
  3. ary[i] < min ? min = ary[i] : void 0;
  4. }
  5. console.log(min1);
  • 求最大值:假设第一项最大值
  1. let max1 = ary[0];
  2. for (let j = 0; j < ary.length; j++) {
  3. ary[j] > max1 ? max1 = ary[j] : void 0;
  4. }
  5. console.log(max1);

3. 排序算法

4. Math.max() 和 Math.min()

  • Math.max() 从一堆数字中取出最大值
  • Math.min() 从一堆数字中取出最小值
  1. let min3 = Math.min(2, 3, 5, 0, -1);
  2. let max3 = Math.max(12, 4, 1);
  3. console.log(min3);
  4. console.log(max3);
  • ? 思考 ? 但是这个时候我们要处理的一个数组,但是 max 和 min 方法都是接收的一个一个的参数,有没有什么办法把数组变成一个一个的或者让 max 和 min 接受一个数组参数呢?
  • 把数组变成一个一个的
  1. ES6 扩展运算符 …对象
  1. let min4 = Math.min(...ary); // ...ary -> 1, 9, 18, 234
  2. let max4 = Math.max(...ary); //
  3. console.log(min4);
  4. console.log(max4);
  1. 让 max 和 min 接受一个数组用 apply 方法:
  1. let min5 = Math.min.apply(null, ary);
  2. let max5 = Math.max.apply(null, ary);
  3. console.log(min5);
  4. console.log(max5);

4.数组转成字符串 再使用 eval 求值

  1. let aryStr = ary.toString();
  2. let min6 = eval(`Math.min(${aryStr})`);
  3. let max6 = eval(`Math.max(${aryStr})`);
  4. // eval() 方法是 js 解释器,可以把字符串转换成代码并执行

二、数组方法模拟实现

1. push 方法:向数组末尾追加项,返回数组的新长度

  1. let ary = [1, 3, 5, 7];
  2. var r = ary.push(9);
  3. console.log(ary);
  4. console.log(r);
  • push 原理:
  1. Array.prototype.myPush = function () {
  2. // this 指向数组的实例
  3. for (let i = 0; i < arguments.length; i++) {
  4. this[this.length] = arguments[i];
  5. }
  6. return this.length;
  7. };
  8. let r2 = ary.myPush(11);
  9. console.log(ary);
  10. console.log(r2);

2. pop 原理:

  1. Array.prototype.myPop = function () {
  2. // this 就是数组实例
  3. let last = this[this.length - 1];
  4. this.length--;
  5. return last;
  6. };
  7. let r3 = ary.myPop();
  8. console.log(r3);

3.forEach

  1. Array.prototype.myForEach = function (callback) {
  2. for (let i = 0; i < this.length; i++) {
  3. callback(this[i], i);
  4. }
  5. };
  6. ary.myForEach(function (item, index) {
  7. console.log(item, index);
  8. });

4.map

  1. Array.prototype.myMap = function (cb) {
  2. let newArr = [];
  3. for (let i = 0; i < this.length; i++) {
  4. let result = cb(this[i], i);
  5. newArr.push(result);
  6. }
  7. return newArr;
  8. };
  9. let r6 = ary.myMap(function (item, idx) {
  10. return item * 2;
  11. });
  12. console.log(r6);

作业:模拟实现 slice 方法

三、类数组转数组

  • 类数组:有索引有 length 的对象;
    常见的类数组:arguments、DOM 集合
    因为类数组不是数组,没办法使用数组中的方法,操作起来不方便,那么有没有办法把类数组转成数组呢?

常见的类数组转数组方法:

1. 准备一个空数组,遍历类数组,把类数组中的每一项 push 到新数组

  1. function sum() {
  2. let ary = []; // 准备一个新数组
  3. // 遍历 arguments
  4. for (let i = 0; i < arguments.length; i++) {
  5. ary.push(arguments[i]);
  6. }
  7. console.log(ary);
  8. }
  9. sum(1, 2, 3, 4);

2. 扩展运算符(将 arguments 中的内容展开到一个新的数组中)

  1. function sum2() {
  2. let ary = [...arguments];
  3. console.log(ary)
  4. }
  5. sum2(1, 4, 5, 7);

3. slice.call() 使用 call 借用数组 slice 方法复制一个数组

  • Array.prototype.slice.call()
  • [].slice.call() 这种写法在 IE 低版本会报错
  1. function sum3() {
  2. var ary = Array.prototype.slice.call(arguments); // 借用数组中的 slice 方法,在 slice 方法执行的时候把 slice 方法中的 this 修改成 arguments
  3. // var ary = [].slice.call(arguments); // 利用 [].slice 找到数组原型上的 slice 方法,然后把 slice 中的 this 修改成 arguments
  4. console.log(ary)
  5. }
  6. sum3(2, 3, 4);

4. Array.from() ES6新增的方法,将类数组结构(类数组、iterator 对象)转换成数组

  1. function sum4() {
  2. let ary = Array.from(arguments);
  3. console.log(ary);
  4. }
  5. sum4(1, 3, 4, 5);

方法封装与容错处理

  • 封装一个将类数组转换成数组的方法
  • 版本1
  1. function arrLikeToAry(arg) {
  2. return Array.from(arg);
  3. }

但是上面的代码有兼容性问题,因为 Array.from 是 ES6 新的方法,IE 低版本不兼容,一旦在 IE 低版本执行会报错,而js单线程,一旦报错后面的代码就不执行了,因此需要做容错处理:

JS的容错语句

try-catch 语句,会先 try,如果 try 过程中报错了,会捕获错误继续执行容错处理,而不会停止执行;

  1. try {
  2. // 这里是尝试执行的语句;
  3. // 通常这里是第一方案
  4. } catch (e) {
  5. // 这里是异常情况的处理,如果上面
  6. // catch是捕获异常,异常信息
  7. // 上面代码执行报错后胡执行这里的代码,所以这里一般设置方案二
  8. console.log(e);
  9. }
  • 版本2 改写方法
  1. function arrLikeToAry(arg) {
  2. // 使用 try-catch 语句
  3. try {
  4. // 首先执行这里,如果浏览器支持 ES6,不会报错正常执行,下面的 catch 语句就不会执行了
  5. return Array.from(arg)
  6. } catch (e) {
  7. // 如果浏览器不支持 es6,就执行这里的代码,我们使用最原始的方式转数组
  8. console.warn(e);
  9. var ary = [];
  10. for (var i = 0; i < arg.length; i++) {
  11. ary.push(arg[i])
  12. }
  13. return ary;
  14. }
  15. }

箭头函数

  • 箭头函数:ES6的新语法
  1. function fe(a, b) {
  2. return a + b;
  3. }
  4. let add = (a, b) => {
  5. return a + b;
  6. };

注意事项:

  1. 函数体里面只有一行代码时,可以省略 return 和花括号

如果函数需要 return 一个对象时,对象需要用小括号包裹;

  1. let sum = (a, b) => a + b;
  2. let getObj = (a, b) => ({a: a, b: b});
  1. 只有一个形参时,可以省略小括号
  1. let say = msg => console.log(msg);
  1. 箭头函数里面没有 arguments,但是可以使用不定参数(剩余参数)
  1. let allIn = (...arg) => {
  2. let total = 0;
  3. for (let i = 0; i < arg.length; i++) {
  4. total += arg[i];
  5. }
  6. return total;
  7. };

不定参数(剩余参数):在函数形参中 …形参名

  1. 不定参数是一个数组,可以使用数组方法
  2. 不定参数可以用作非必传参数
  1. let fn = (a, b, ...arg) => {
  2. console.log(arg);
  3. };
  4. fn(1, 2); // arg = []
  5. fn(1, 2, 3); // arg =[3]
  6. fn(1, 3, 5, 7, 9, 11); // arg = [5, 7, 9, 11]
  1. 箭头函数中的 thi s指向其声明时所在作用域中的 this;
    原理:箭头函数没有自己的 this;
  • this 和 arguments 是两个特殊的变量,是在函数执行时 js 解析引擎传入给函数的,但是箭头函数执行时,解析引擎给箭头函数;
  • 箭头函数没有自己的 this,所以不能用作构造函数;
  • 箭头函数不能用 call、apply、bind 修改 this

四、utils 工具包封装

  1. window.utils = (function () {
  2. function arrLikeToAry(args) {
  3. try {
  4. return Array.from(args);
  5. } catch (e) {
  6. var arr = [];
  7. for (var i = 0; i < args.length; i++) {
  8. arr.push(args[i])
  9. }
  10. return arr;
  11. }
  12. }
  13. return {
  14. arrLikeToAry // arrLikeToAry: arrLikeToAry
  15. }
  16. })();