ES6和ES7、8、9、10常用的

ES6

let和const

  • let
    1. 作用: 与var类似, 用于声明一个变量
    2. 特点: 在块作用域内有效 不能重复声明 不会预处理, 不存在提升
    3. 应用: 循环遍历加监听 使用let取代var是趋势
  • const
    1. 作用: 定义一个常量
    2. 特点: 不能修改 其它特点同let
    3. 应用: 保存不用改变的数据
  • let 定义 变量
  • const 定义 常量
    1. 默认变量使用let定义,今后let使用很多,只有确定不变的量用const 90%以上用let定义的
    2. 默认变量使用const定义,今后const使用很多,只有确定可变的量用let 90%以上用const定义的 默认就用const定义,只有后面的值发生变化,在改为let

变量的解构赋值

  1. 理解:
  • 从对象或数组中提取数据, 并赋值给变量(多个)
    • const person = {name: 'jack', age: 18}; const { age, sex, name } = person; console.log(name, age, sex);
  1. 对象的解构赋值: 没有顺序关系 let {n, a} = {n:'tom', a:12}
  2. 数组的解构赋值: 根据顺序一一对应 let [a,b] = [1, 'atguigu'];
  3. 用途
    • 给多个形参赋值
  4. 对函数参数解构赋值,一个解构赋值语法对应一个参数(与结构赋值语法中多少个变量没有关系)

模板字符串

  1. 模板字符串 : 简化字符串的拼接
  • 模板字符串必须用 `` 包含
  • 变化的部分使用${xxx}定义
const person = {name: 'jack', age: 18};
  console.log('姓名:' + person.name + ' 年龄:' + person.age);
  console.log(`姓名:${person.name} 年龄: ${person.age}`);
复制代码

对象的简写方法

简化的对象写法

  • 省略同名的属性值
  • 省略方法的function
  • 例如:
    let y = 2;
    let point = {
      x,
      y,
      setX (x) {this.x = x}
    };
    复制代码

形参默认值

形参的默认值----当不传入参数的时候默认使用形参里的默认值

function Point(x = 1,y = 2) {
this.x = x;
this.y = y;
}
复制代码

默认值:没有传值就使用默认值,传值了就使用传入的值

三点运算符

用途

  1. rest(可变)参数
    • 用来取代arguments 但比 arguments 灵活,只能是最后部分形参参数
    function fun(...values) {
        console.log(arguments);
        arguments.forEach(function (item, index) {
            console.log(item, index);
        });
        console.log(values);
        values.forEach(function (item, index) {
            console.log(item, index);
        })
    }
    fun(1,2,3);
    复制代码
  2. 扩展运算符
  let arr1 = [1,3,5];
  let arr2 = [2,...arr1,6];
  arr2.push(...arr1);
  function sum(a, ...args) {
    // ...运算符 取代 arguments
    console.log(args); // 真数组
    console.log(arguments); // 伪数组
  }
复制代码

箭头函数

  • 作用: 定义匿名函数

  • 基本语法:

    • 没有参数: () => console.log('xxxx')
    • 一个参数: i => i+2
    • 大于一个参数: (i,j) => i+j
    • 函数体不用大括号: 默认返回结果
    • 函数体如果有多个语句, 需要用{}包围,若有需要返回的内容,需要手动返回
  • 使用场景: 多用来定义回调函数

  • 箭头函数的特点: 1、简洁 2、箭头函数没有自己的this,箭头函数的this不是调用的时候决定的,而是在定义的时候处在的对象就是它的this 3、扩展理解: 箭头函数的this看外层的是否有函数, 如果有,外层函数的this就是内部箭头函数的this, 如果没有,则this是window。

// 箭头函数
  const fn = () => {};
  // 形参只有一个, 可以省略括号
  const fn1 = x => { console.log(x); };
  // 形参没有或者有多个
  const fn2 = (x, y) => {};
  console.log(fn1(1));
  // 当代码只有一条语法时, 可以省略大括号,会将语句结果作为函数的返回值返回
  const fn3 = x => x + 1;
  console.log(fn3(1));
  // 当代码没有或多条语句时
  const fn4 = x => {
    console.log(x);
    return x + 1;
  }
复制代码

Promise对象

  1. promise就是一个异步编程的解决方案,用来解决回调地狱问题
  2. 理解:
  • Promise对象: 代表了未来某个将要发生的事件(通常是一个异步操作)
  • 有了promise对象, 可以将异步操作以同步的流程表达出来, 避免了层层嵌套的回调函数(俗称'回调地狱')
  • ES6的Promise是一个构造函数, 用来生成promise实例
  1. 使用promise基本步骤(2步):
  • 创建promise对象
    let promise = new Promise((resolve, reject) => {
        //初始化promise状态为 pending
      //执行异步操作
      if(异步操作成功) {
        resolve(value);//修改promise的状态为fullfilled
      } else {
        reject(errMsg);//修改promise的状态为rejected
      }
    })
    复制代码
  • 调用promise的then()
    promise.then(function(
      result => console.log(result),
      errorMsg => alert(errorMsg)
    ))
    复制代码
  1. promise对象的3个状态
  • pending: 初始化状态
  • fullfilled: 成功状态
  • rejected: 失败状态
  1. 应用:
  • 使用promise实现超时处理

  • 使用promise封装处理ajax请求

    let request = new XMLHttpRequest();
    request.onreadystatechange = function () {
    }
    request.responseType = 'json';
    request.open("GET", url);
    request.send();
    复制代码
  • new Promise(), 会创建promise实例对象,实例对象内部默认是pending状态(初始化状态)

    • resolve() 将promise状态由初始化状态改为 fullfilled 成功的状态
    • reject() 将promise状态由初始化状态改为 rejected 失败的状态
    • promise状态只能有初始化状态改为成功/失败的状态。不能由成功变成失败或者失败变成成功
  • promise实例对象, then方法

promise.then((result) => {
// 当promise对象状态变成成功的状态时,会调用当前函数
// 成功的回调函数可以接受resolve方法传入参数
console.log('成功的回调函数触发了~');
console.log(result);
sum(1, 2);
}, (error) => {
// 当promise对象状态变成失败的状态时,会调用当前函数
// 失败的回调函数可以接受reject方法传入参数
console.log('失败的回调函数触发了~');
console.log(error);
})
复制代码

Symbol

  • 前言:ES5中对象的属性名都是字符串,容易造成重名,污染环境
  • 每次调用Symbol函数,返回一个唯一的symbol数据 一般给对象设置唯一的属性。 多了一个数据类型:Symbol
    • Symbol: 概念:ES6中的添加了一种原始数据类型symbol(已有的原始数据类型:String, Number, boolean, null, undefined, 对象)
    • 特点:
      • Symbol属性对应的值是唯一的,解决命名冲突问题
      • Symbol值不能与其他数据进行计算,包括同字符串拼串
      • for in, for of遍历时不会遍历symbol属性。
    • 使用:
      • 调用Symbol函数得到symbol值
        let symbol = Symbol();
        let obj = {};
        obj[symbol] = 'hello';
        复制代码
      • 传参标识
        let symbol = Symbol('one');
        let symbol2 = Symbol('two');
        console.log(symbol);// Symbol('one')
        console.log(symbol2);// Symbol('two')
        复制代码
      • 内置Symbol值
        • 除了定义自己使用的Symbol值以外,ES6还提供了11个内置的Symbol值,指向语言内部使用的方法。
        • Symbol.iterator
        • 对象的Symbol.iterator属性,指向该对象的默认遍历器方法(后边讲)

Iterator遍历器

  • 概念: iterator是一种接口机制,为各种不同的数据结构提供统一的访问机制
  • 作用:
    • 为各种数据结构,提供一个统一的、简便的访问接口;
    • 使得数据结构的成员能够按某种次序排列;
    • ES6创造了一种新的遍历命令for...of循环,Iterator接口主要供for...of消费。 工作原理:
    • 创建一个指针对象(遍历器对象),指向数据结构的起始位置。
    • 第一次调用next方法,指针自动指向数据结构的第一个成员
    • 接下来不断调用next方法,指针会一直往后移动,直到指向最后一个成员
    • 每调用next方法返回的是一个包含value和done的对象,{value: 当前成员的值,done: 布尔值}
      • value表示当前成员的值,done对应的布尔值表示当前的数据的结构是否遍历结束。
      • 当遍历结束的时候返回的value值是undefined,done值为false 原生具备iterator接口的数据(可用for of遍历)
    • Array
    • arguments
    • set容器
    • map容器
    • String
    • 。。。
  • iterator是一个接口机制,为了让所有数据用统一的方式遍历( for of )
    • 通过查看数据类型上是否有Symbol(Symbol.iterator)方法
    • String 、Array、Set、Map、 arguments、dom元素集合(querySelectorAll)
  • 遍历的方法
    • forEach只能数组使用,推荐使用
    • for 只能数组使用, 性能最好
    • while / do while 任意值使用
    • for in 通常用于对象
    • for of 当你不确定要遍历的是什么数据类型。这时候用for of

Generator函数

概念:
  1、ES6提供的解决异步编程的方案之一
  2、Generator函数是一个状态机,内部封装了不同状态的数据,
  3、用来生成遍历器对象
  4、可暂停函数(惰性求值), yield可暂停,next方法可启动。每次返回的是yield后的表达式结果
特点:
  1、function 与函数名之间有一个星号
  2、内部用yield表达式来定义不同的状态
  例如:
    function* generatorExample(){
      let result = yield 'hello';  // 状态值为hello
      yield 'generator'; // 状态值为generator
    }
  3、generator函数返回的是指针对象(接11章节里iterator),而不会执行函数内部逻辑
  4、调用next方法函数内部逻辑开始执行,遇到yield表达式停止,返回{value: yield后的表达式结果/undefined, done: false/true}
  5、再次调用next方法会从上一次停止时的yield处开始,直到最后
  6、yield语句返回结果通常为undefined, 当调用next方法时传参内容会作为启动时yield语句的返回值。
复制代码
function* fn() {
    console.log('函数开始执行了~');
    const flag = true;
    const result = yield flag ? 123 : 456;
    console.log(result);
    console.log('函数执行完了~');
  }
  // 执行generator函数,返回值是一个iterator对象
  const iteratorObj = fn();
  console.log(iteratorObj);
  // 通过iterator对象的next方法执行函数体代码(推着函数动一下)
  const result1 = iteratorObj.next(111);
  console.log(result1);  // {value: 123, done: false}  value 看yield后面表达式的值, done 看函数是否执行完毕:没有执行完就是false 执行完了就是true
  const result2 = iteratorObj.next(222);
  console.log(result2);
  // 手动给对象添加iterator接口
  console.log(Symbol.iterator);
  const person = {
    name: 'jack',
    age: 18,
    sex: '男'
  }
  Object.prototype[Symbol.iterator] = function* () {
    for (let key in this) {
      yield this[key];
    }
  }

复制代码
  • 案例
/*
 需求:请求a数据,再请求b数据,请求c数据
   */

  function* generator() {
    console.log('函数开始执行了~');

    const result1 = yield setTimeout(() => {
      console.log('请求回来了a数据');
      // 请求成功,让generator继续执行
      iteratorObj.next('a数据');
    }, 3000);

    const result2 = yield setTimeout(() => {
      console.log('请求回来了b数据');
      // 请求成功,让generator继续执行
      iteratorObj.next('b数据');
    }, 2000);

    const result3 = yield setTimeout(() => {
      console.log('请求回来了c数据');
      // 请求成功,让generator继续执行
      iteratorObj.next('c数据');
    }, 1000);

    console.log(result1, result2, result3);

    console.log('函数执行完毕了~');
  }

  const iteratorObj = generator();
  // 为了执行第一个请求
  iteratorObj.next();
复制代码

async函数

  • async函数(源自ES2017 - ES8)
  • 概念: 真正意义上去解决异步回调的问题,同步流程表达异步操作 本质: Generator的语法糖
  • 语法: async function foo(){ await 异步操作; await 异步操作; }
  • 特点:
    • 不需要像Generator去调用next方法,遇到await等待,当前的异步操作完成就往下执行
    • 返回的总是Promise对象,可以用then方法进行下一步操作
    • async取代Generator函数的星号*,await取代Generator的yield
    • 语意上更为明确,使用简单,经临床验证,暂时没有任何副作用
  • 案例1
async function asyncFn() {
    console.log('函数开始执行了~');
    /* const promise = new Promise((resolve, reject) => setTimeout(() => reject(123456), 2000));
    const promise = new Promise((resolve, reject) => setTimeout(reject.bind(null, 123456), 2000));
    */
    const promise = new Promise((resolve, reject) => setTimeout(resolve.bind(null, 123456), 2000));
    // const promise = Promise.resolve();
    // await只等promise对象:等promise对象状态由初始化变成成功状态。
    // (一旦promise对象状态是初始化状态,一直等。一旦promise对象状态变成成功的状态,就不等了,执行后面代码)
    // 一旦promise对象状态变成失败的状态,就不执行后面代码(如果捕获了async函数promise的异常,就不报错,没有捕获,就会报错)
    // result的值就是resolve()传入的参数
    const result = await promise;
    console.log(result);
    await promise;
    console.log('函数执行完毕了~');
    return 666;
  }
  // async函数返回值是一个promise对象: 默认是resolved状态
  // 如果函数中有promise对象变成失败的状态,就是rejected状态
  const result = asyncFn();
  result
    // 看async函数里面返回值,就是result的值
    .then((result) => {
      console.log(result);
    })
    .catch((error) => {
      console.log(error);
    })
  console.log(result);
复制代码
  • 案例2
async function asyncFn() {

    const result1 = await new Promise((resolve, reject) => {
      setTimeout(() => {
        console.log('a数据请求成功了~');
        resolve('a数据');
      }, 3000)
    })

    const result2 = await new Promise((resolve, reject) => {
      setTimeout(() => {
        console.log('b数据请求成功了~');
        resolve('b数据');
      }, 2000)
    })

    const result3 = await new Promise((resolve, reject) => {
      setTimeout(() => {
        console.log('c数据请求成功了~');
        resolve('c数据');
      }, 2000)
    })

    console.log(result1, result2, result3);
    return [result1, result2, result3];
  }

  const promise = asyncFn();

  promise
    .then((res) => {
      console.log(res); // [result1, result2, result3]
    })
复制代码

class类

  1. 通过class定义类/实现类的继承
  2. 在类中通过constructor定义构造方法
  3. 通过new来创建类的实例
  4. 通过extends来实现类的继承
  5. 通过super调用父类的构造方法
  6. 重写从父类中继承的一般方法
// 定义类:构造函数
  class Father {
    // 给实例对象添加属性
    constructor(name, age) {
      this.name = name;
      this.age = age;
    }
    // 给实例对象添加方法
    setName(name) {
      this.name = name;
    }
  }
  // 定义子类继承父类,自动继承父类的属性和方法
  // 使用继承必须在constructor函数中调用super方法或者不写constructor
  class Son extends Father{
    // 给实例对象添加属性
    constructor(name, age, sex) {
      super(name, age); // 调用父类的构造方法: constructor
      this.sex = sex;
    }
    // 给实例对象添加方法
    setAge(age) {
      this.age = age;
    }
  }
  console.log(Father.prototype);
  console.log(typeof Son);
  const s = new Son('bob', 20, '男');
  console.log(s);
复制代码

字符串扩展

  1. String.prototype.includes(str) : 判断是否包含指定的字符串
  2. String.prototype.startsWith(str) : 判断是否以指定字符串开头
  3. String.prototype.endsWith(str) : 判断是否以指定字符串结尾
  4. String.prototype.repeat(count) : 重复指定次数
const str = 'atguigu';
  console.log(str.includes('gug')); // true
  console.log(str.startsWith('atg')); // true
  console.log(str.endsWith('gu')); // true
  console.log(str.repeat(3)); // 'atguiguatguiguatguigu'
复制代码

数值扩展

  1. 二进制与八进制数值表示法: 二进制用0b, 八进制用0o
  2. Number.isFinite(i) : 判断是否是有限大的数
  3. Number.isNaN(i) : 判断是否是NaN
  4. Number.isInteger(i) : 判断是否是整数
  5. Number.parseInt(str) : 将字符串转换为对应的数值
  6. Math.trunc(i) : 直接去除小数部分
 console.log(0o666); // 0 - 7
  console.log(0b1010); // 0 - 1   8421法
  console.log(Infinity); // 正无穷大
  console.log(-Infinity); // 负无穷大
  console.log(NaN); // not a number
  console.log(Number.isFinite(Infinity)); // false
  console.log(Number.isNaN(NaN)); // true  x !== x
  console.log(NaN === NaN); // NaN不与任何数相等,包括它自身
  console.log(Number.isInteger(1.1)); // false
  console.log(Number.parseInt('123a.123')); // 123  整型:整数
  console.log(Number.parseFloat('123.123')); // 123.123 浮点型:小数
  console.log(Math.trunc(456.865)); // 456
  console.log(Math.floor(456.865)); // 456
复制代码

数组扩展

  1. Array.from(v) : 将伪数组对象或可遍历对象转换为真数组
  2. Array.of(v1, v2, v3) : 将一系列值转换成数组
  3. Array.prototype.find(function(value, index, arr){return true}) : 找出第一个满足条件返回true的元素
  4. Array.prototype.findIndex(function(value, index, arr){return true}) : 找出第一个满足条件返回true的元素下标
// 伪数组对象
  const btns = document.querySelectorAll('button');
  // 将伪数组转化为真数组
  const newBtns1 = Array.from(btns);
  console.log(newBtns1);
  const newBtns2 = Array.prototype.slice.call(btns);
  console.log(newBtns2);
  const newBtns3 = [...btns];
  console.log(newBtns3);
  console.log(Array.of(1, true, {})); // [1, true, {}]
  const arr = [{age: 18}, {age: 19}, {age: 20}, {age: 21}];
  // const obj = arr.find((item, index, arr) => item.age === 20);
  const index = arr.findIndex((item, index, arr) => item.age === 20);
  console.log(index);
复制代码

对象扩展

  1. Object.is(v1, v2)
    • 判断2个数据是否完全相等
  2. Object.assign(target, source1, source2..)
    • 将源对象的属性复制到目标对象上
  3. 直接操作 proto 属性
let obj2 = {};
obj2.__proto__ = obj1;
复制代码
// 全等运算符的问题
  console.log(0 === -0); // true  false
  console.log(NaN === NaN); // false  true
  // Object.is方法解决
  console.log(Object.is(1, 1)); // true
  console.log(Object.is(0, -0)); // false
  console.log(Object.is(NaN, NaN)); // true
//is方法用原生实现
  function is(a, b) {
    /*if (a === b) {
      // 判断 0 和 -0 的特殊情况 返回 false
      // 0 和 0 / -0 和 -0 的情况返回 true
      // return !(-a === b);
      return !(-1 / a === 1 / b);
    } else {
      // 判断 NaN 和 NaN 的特殊情况
      return a !== a && b !== b;
    }*/
    // return a === b ? ((-1 / a === 1 / b) ? false : true) : (a !== a && b !== b ? true : false);
    // return (a === b && (!(-1 / a === 1 / b)) || (a !== a && b !== b);
    return a === b ? !(-1 / a === 1 / b) : a !== a && b !== b;
  }
  console.log(is(0, -0)); // false
  console.log(is(0, 0)); // true
  console.log(is({}, {})); // false
  console.log(is(NaN, NaN)); // true
  console.log(is(true, true)); // true
  const obj = {};
  const obj1 = {name: 'jack'};
  const obj2 = {age: 18};
  // 将后面目标对象上的属性和方法复制到源对象上
  const result = Object.assign(obj, obj1, obj2);
  console.log(result === obj);
复制代码

深度克隆

  • 数据类型:
    • 数据分为基本的数据类型(String, Number, boolean, Null, Undefined)和对象数据类型
    • 基本数据类型: 特点: 存储的是该对象的实际数据
    • 对象数据类型: 特点: 存储的是该对象在栈中引用,真实的数据存放在堆内存里
  • 复制数据
    • 基本数据类型存放的就是实际的数据,可直接复制 let number2 = 2; let number1 = number2;
    • 克隆数据:对象/数组
      • 区别: 浅拷贝/深度拷贝 判断: 拷贝是否全部产生了新的数据还是拷贝的是数据的引用
        • 知识点:对象数据存放的是对象在栈内存的引用,直接复制的是对象的引用
        let obj = {username: 'kobe'}
        let obj1 = obj; // obj1
        ```复制了obj在栈内存的引用
        复制代码
      2、常用的拷贝技术
      • arr.concat(): 数组浅拷贝 2). arr.slice(): 数组浅拷贝
      • JSON.parse(JSON.stringify(arr/obj)): 数组或对象深拷贝, 但不能处理函数数据
      • 浅拷贝包含函数数据的对象/数组
      • 深拷贝包含函数数据的对象/数组
  • 浅度克隆
  let obj3 = Object.assign({}, obj1);
  obj3.hobby.push('rap');
  console.log(obj3);
  console.log(obj1);
复制代码
  • 深度克隆
    • JSON能实现深度克隆,不能克隆函数数据
let obj1 = {name: 'jack', age: 18, hobby: ['篮球', '唱', '跳'], setName (name) {this.name = name;}};
const json = JSON.stringify(obj1);
const obj4 = JSON.parse(json);
console.log(obj1, obj4);
obj4.hobby.push('rap');
console.log(obj1, obj4);
复制代码
// 检查数据类型
  function checkType(target) {
    return Object.prototype.toString.call(target).slice(8, -1);
  }
复制代码
// 深度克隆: 深度克隆所有数据
  function deepClone(target) {
    // 因为不确定克隆的是什么数据,但是能确定的是一定是引用数据类型
    let result = null;
    // 检查数据的类型
    const type = checkType(target);
    // 判断数据的类型,如果是对象/数组就处理,不是就直接返回
    if (type === 'Object') {
      result = {};
    } else if (type === 'Array') {
      result = [];
    } else {
      // 其他类型就直接返回
      return target;
    }
    // for in 即能遍历对象也能遍历数组
    for (let key in target) {
      // 获取属性值
      const value = target[key];
      // 将克隆的值作为新对象的某个属性的值
      // const newValue = deepClone(value);
      // result[key] = newValue;
      result[key] = deepClone(value);
    }
    return result;
  }
  const person = {name: 'jack', age: 18, hobby: ['篮球', '唱', '跳'], sex: { option1: '男', option2: '女' }, setName (name) {this.name = name;}};
  const newObj = deepClone(person);
  newObj.hobby.push('rap');
  console.log(person, newObj);
复制代码

Set和Map数据结构

  1. Set容器 : 无序不可重复的多个value的集合体
    • Set()
    • Set(array)
    • Set.prototype.add(value) 给set容器添加一个值
    • Set.prototype.delete(value) 删除一个
    • Set.prototype.has(value)
    • Set.prototype.clear() 清空所有
    • size
  2. Map容器 : 无序的 key不重复的多个key-value的集合体
    • Map()
    • Map(array)
    • set(key, value)//添加
    • get(key)
    • delete(key)
    • has(key)
    • clear()
    • size
const arr = [2, 5, 8, 5, 1, 4, 8];
  const s1 = new Set(arr);
  console.log(s1);
  // 数组去重
  console.log([...new Set(arr)]);

  s1.add(9);
  console.log(s1);
  console.log(s1.has(9));
  s1.clear();
  console.log(s1);

  // 无序的 key不重复的多个key-value的集合体
  const array = [1, 2, 3];
  const m1 = new Map([[{name: 'jack'}, function fn() {}], [array, true], [array, false]]);
  console.log(m1);
复制代码

ES7(常用的)

  1. 指数运算符(幂): **
  2. Array.prototype.includes(value) : 判断数组中是否包含指定value
console.log(3 ** 3);//27
const arr = [1, 2, 5, 6, 8];
console.log(arr.includes(3));//true
复制代码

ES8(常用的)

==async函数也是ES8中提出的==

  • Object.values()
  • Object.entries()
  • Object.keys()
 const person = {name: 'jack', age: 18}; // [['name', 'jack'], ['age': 18]]
  // 提取对象中所有属性名,作为一个数组返回
  console.log(Object.keys(person));
  // 提取对象中所有属性值,作为一个数组返回
  console.log(Object.values(person));
  console.log(Object.entries(person)); // [['name', 'jack'], ['age': 18]]
复制代码

ES9(常用的)Promise.finally

const promise = new Promise((resolve, reject) => setTimeout(reject, 1000));
  promise
    .then(() => {
      console.log('then');
    })
    .catch(() => {
      console.log('catch');
    })
    .finally(() => {
      // 不管成功还是失败都会触发
      console.log('finally');
    })
复制代码

ES10(常用的)

  • Array扩展方法
    • 数组降维、数组的扁平化
// 数组降维、数组的扁平化
  const arr = [[1, 2], [[[3]]], [[4], [[[[5]], 6]]]];
  console.log(arr.flat(1));
  console.log(arr.flat(Infinity));
/*
    1. flat 全部降成1维
    2. 可以传参,根据参数降维
  flat方法的实现源代码
  Array.prototype.flat = function (num) {
    // this 就指向要处理的数组  --> arr.flat()
    let result = [];
    /!*this.forEach((item, index) => {
      if (Array.isArray(item)) {
        result = result.concat(item.flat());
      } else {
        result.push(item);
      }
    })*!/
    this.forEach((item) => Array.isArray(item) ? result = result.concat(item.flat()) : result.push(item));
    return result;
  }

  Array.prototype.flat = function (num) {
    // this 就指向要处理的数组  --> arr.flat()
    num--;
    if (num < 0) return this;
    let result = [];
    /!*this.forEach((item, index) => {
      if (Array.isArray(item)) {
        result = result.concat(item.flat());
      } else {
        result.push(item);
      }
    })*!/
    this.forEach((item) => Array.isArray(item) ? result = result.concat(item.flat(num)) : result.push(item));
    return result;
  }
*/
复制代码
  • 动态import
// 按需加载
  document.getElementById('btn').onclick = function () {
    // 只会加载一次
    import('./a.js');
  }
复制代码

函数节流和函数防抖

  • 节流函数
// 绑定滚轮事件
  // 需求:滚轮事件发现单位时间内触发回调函数的次数太多,性能不好
  // 解决:让函数调用次数更少
  // 节流函数:在单位时间内让函数只调用一次
  document.onscroll = throttle(function (e) {
    console.log('滚轮事件触发了~');
    console.log(e);
    console.log(this);
  }, 1000)

  // 节流函数
  function throttle(fn, time) {
    // 开始时间
    let startTime = 0;
    // 实际上下面函数就是DOM事件回调函数
    return function () {

      // 结束时间: 调用当前函数的时间
      const endTime = Date.now();
      // fn函数的this指向问题,参数有问题(少event)
      if (endTime - startTime >= time) {
        // 大于1s, 可以触发, 小于1s就不触发
        fn.apply(this, arguments);
        // 重置开始时间
        startTime = endTime;
      }
    }
  }
复制代码
  • 防抖函数
// 绑定滚轮事件
  // 需求:滚轮事件发现单位时间内触发回调函数的次数太多,性能不好
  // 解决:让函数调用次数更少
  // 节流函数:在单位时间内让函数只调用一次,是第一次生效
  // 防抖函数:在单位时间内让函数只调用一次,是最后一次生效
  document.onscroll = debounce(function (e) {
    console.log('滚轮事件触发了~');
    console.log(e);
    console.log(this);
  }, 1000)
  // 防抖函数
  function debounce(fn, time) {
    let timerId = null;
    // 实际上下面函数就是DOM事件回调函数
    return function () {
      clearTimeout(timerId);
      const args = arguments;
      timerId = setTimeout(() => {
        // fn函数的this指向问题,参数有问题(少event)
        // 大于1s, 可以触发, 小于1s就不触发
        fn.apply(this, args);
      }, time);
    }
  }
复制代码

转载于:https://juejin.im/post/5cebd136f265da1bc94eccf1

你可能感兴趣的:(ES6和ES7、8、9、10常用的)