ES6
let和const
- let
- 作用: 与var类似, 用于声明一个变量
- 特点: 在块作用域内有效 不能重复声明 不会预处理, 不存在提升
- 应用: 循环遍历加监听 使用let取代var是趋势
- const
- 作用: 定义一个常量
- 特点: 不能修改 其它特点同let
- 应用: 保存不用改变的数据
- let 定义 变量
- const 定义 常量
- 默认变量使用let定义,今后let使用很多,只有确定不变的量用const 90%以上用let定义的
- 默认变量使用const定义,今后const使用很多,只有确定可变的量用let 90%以上用const定义的 默认就用const定义,只有后面的值发生变化,在改为let
变量的解构赋值
- 理解:
- 从对象或数组中提取数据, 并赋值给变量(多个)
const person = {name: 'jack', age: 18};
const { age, sex, name } = person;
console.log(name, age, sex);
- 对象的解构赋值: 没有顺序关系
let {n, a} = {n:'tom', a:12}
- 数组的解构赋值: 根据顺序一一对应
let [a,b] = [1, 'atguigu'];
- 用途
- 给多个形参赋值
- 对函数参数解构赋值,一个解构赋值语法对应一个参数(与结构赋值语法中多少个变量没有关系)
模板字符串
- 模板字符串 : 简化字符串的拼接
- 模板字符串必须用 `` 包含
- 变化的部分使用${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;
}
复制代码
默认值:没有传值就使用默认值,传值了就使用传入的值
三点运算符
用途
- 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); 复制代码
- 扩展运算符
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对象
- promise就是一个异步编程的解决方案,用来解决回调地狱问题
- 理解:
- Promise对象: 代表了未来某个将要发生的事件(通常是一个异步操作)
- 有了promise对象, 可以将异步操作以同步的流程表达出来, 避免了层层嵌套的回调函数(俗称'回调地狱')
- ES6的Promise是一个构造函数, 用来生成promise实例
- 使用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) )) 复制代码
- promise对象的3个状态
- pending: 初始化状态
- fullfilled: 成功状态
- rejected: 失败状态
- 应用:
-
使用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属性,指向该对象的默认遍历器方法(后边讲)
- 调用Symbol函数得到symbol值
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类
- 通过class定义类/实现类的继承
- 在类中通过constructor定义构造方法
- 通过new来创建类的实例
- 通过extends来实现类的继承
- 通过super调用父类的构造方法
- 重写从父类中继承的一般方法
// 定义类:构造函数
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);
复制代码
字符串扩展
- String.prototype.includes(str) : 判断是否包含指定的字符串
- String.prototype.startsWith(str) : 判断是否以指定字符串开头
- String.prototype.endsWith(str) : 判断是否以指定字符串结尾
- 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'
复制代码
数值扩展
- 二进制与八进制数值表示法: 二进制用0b, 八进制用0o
- Number.isFinite(i) : 判断是否是有限大的数
- Number.isNaN(i) : 判断是否是NaN
- Number.isInteger(i) : 判断是否是整数
- Number.parseInt(str) : 将字符串转换为对应的数值
- 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
复制代码
数组扩展
- Array.from(v) : 将伪数组对象或可遍历对象转换为真数组
- Array.of(v1, v2, v3) : 将一系列值转换成数组
- Array.prototype.find(function(value, index, arr){return true}) : 找出第一个满足条件返回true的元素
- 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);
复制代码
对象扩展
- Object.is(v1, v2)
- 判断2个数据是否完全相等
- Object.assign(target, source1, source2..)
- 将源对象的属性复制到目标对象上
- 直接操作 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在栈内存的引用 复制代码
- 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数据结构
- Set容器 : 无序不可重复的多个value的集合体
- Set()
- Set(array)
- Set.prototype.add(value) 给set容器添加一个值
- Set.prototype.delete(value) 删除一个
- Set.prototype.has(value)
- Set.prototype.clear() 清空所有
- size
- 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(常用的)
- 指数运算符(幂): **
- 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);
}
}
复制代码