1 ECMAScript 和 JavaScript 概述
浏览器端JavaScript: ECMAScript、BOM、DOM
node端的JavaScript:ECMAScript、nodeAPI
ECMA: 欧洲计算机标准协会
ECMAScript: 一套语法标准
ECMAScript是JavaScript的规格
JavaScript是ECMAScript的实现
ECMAScript的实现: JavaScript、JScript、ActionScript(flash)
1.1 ECMAScript的重要版本
ECMAScript3.0 简称ES3
ES5.0 / ES5.1 新增一些扩展
ES6 2015年6月 又叫ES2015 (之后每年6月份出一个新的版本)
ES7 ES2016
ES8 ES2017
ES9 ES2018
ES10 ES2019
ES11 ES2020
2 关键字扩展
2.1 let 关键字
用于声明变量,类似于var
特点:
① 不能重复声明
② let声明的变量不会提升
③ let声明的变量可以具有块级作用域
④ let声明的全局变量不再是顶层对象的属性
2.2 let 与块级作用域
// 给三个按钮绑定单击事件,点击输出索引号
let btn = document.querySelectorAll('button')
for (var i = 0; i < btn.length; i++) {
btn[i].onclick = function () {
console.log(i); // 3 3 3
};
}
for (let i = 0; i < btn.length; i++) {
btn[i].onclick = function () {
console.log(i); // 0 1 2
};
}
2.3 const 关键字
常量不可改变的量,用途:程序的配置信息习惯用常量定义
特点:
① 值不能修改,更不能重复声明
② 不会变量提升
③ 具有全局、局部、块级作用域
④ 全局的常量不是window的属性
3 对象的简写
const name = '小明'
const age = '18'
// 属性同名可简写
const obj = {
name
age
say() { //方法简写
},
}
console.log(obj) // { name: '小明', age: '18' }
4 解构赋值
4.1 数组解构赋值
// 1. 解构声明
const [a, b, c] = [value1, value2, value3]
// 2. 修改变量的值
[a, b, c] = [value1, value2, value3]
// 3 复杂数组 (保证两边的数组形式一致)
const [a, [b], [c, [d,e]]] = [100, [200], [300, [400, 500]]]
// 4. 声明变量的时候可以有默认值 (与函数传参类似)
const [a, b, c, d = 5] = arr
console.log(d) // 5
4.2 对象解构赋值
// 简写形式
{name, age} = {name: '张三', age: 18} //张三 ,18
// 对象形式
const obj = {
name: '小明',
age: 18,
sex: '男',
love: {
eat: '吃饭',
sleep: '睡觉',
peas: '打豆豆',
}
}
const { name, age, sex } = obj
console.log(name, age, sex) // 小明 18 男
// 解构重名
const { name: myname } = obj
console.log(myname) // 小明
// 嵌套解构
const { love: { sleep } } = obj
console.log(sleep) // 睡觉
5 字符串扩展
5.1 模板字符串
两个反引号 ``
特点:
${变量} 直接解析
${表达式} 得到表达式的结果
5.2 字符串对象新增的方法
① ES5
trim() 去除两边的空格
② ES6+
startsWith() 返回布尔值
endsWith() 返回布尔值
includes() 返回布尔值
repeat()
padStart() ES8 补全 //message.padStart(100, '#')
padEnd() ES8 补全 //message.padEnd(100, '#')
matchAll() ES10 message.matchAll(/\w/) //返回迭代器(是所有匹配到的结果)
trimStart() ES10
trimEnd() ES10
6 数值的扩展
6.1 指数运算符 (**) ES7
2 ** 4; // 计算2的4次方
2 ** 2 ** 3; // 运算顺序,先算右边的
6.2 二进制和八进制的表示
// 二进制
0b101010
// 八进制
0o17
// 比以前的八进制表示方式语法更合理,在严格模式可用(0开头表示八进制,严格模式不可用)
6.3 Math对象新增的方法
Math.trunc() 去掉小数部分
Math.sign() 判断一个数字是正数、负数、还是0
Math.cbrt() 求立方根
Math.hypot() 求所有参数的平方和的平方根(用于勾股定理计算斜边长度)
7 函数扩展
7.1 参数默认值
// ES6的写法
function fn(a,b=默认值) {
}
// ES6之前的写法
function fn(a,b) {
if (b === undefined) {
b = 默认值
}
}
7.2 rest参数
// 1、arguments获取实参
function fn() {
console.log(arguments);
}
// 2、rest参数获取
function fn(...numbers) {
console.log(numbers); //得到一个数组,里面是所有的实参; numbers的名字只要符合标识名命名规范即可
}
与arguments类似
rest参数得到是数组,arguments得到是伪数组
7.3 箭头函数
① 语法
// 以前定义函数的方式 (表达式方式)
const fn = function () {}
// 箭头函数写法
const fn = () => {}
// 箭头函数简写,如果参数只有一个,可以省略括号
const fn = name => {}
// 只有一个参数,且只有一条返回语句
const fn = num => num * num
// 如果返回的是对象
const fn = name => ({ name: name })
② 特点
1. this指向。 与谁调用了箭头函数无关,与声明箭头函数位置有关
看声明箭头函数的地方,是不是嵌套在函数内,如果嵌套在了函数内,看外层函数的this指向;如果没有被函数嵌套,指向window
2. 箭头函数内无法获取aruguments,可以使用rest参数
3. 箭头函数不能作为构造函数
4. 箭头函数不能作为生成器
③ 适用场景
使用场景:作为回调函数
不适合的场景:给对象添加方法(this指向)、构造函数、生成器函数
7.4 函数对象新增属性
name 返回函数名(声明函数时给的名字)
8 数组扩展
8.1 扩展运算符
① 定义
rest参数的逆运算 把数组转为用逗号分隔的参数序列
② 应用
const nums = [100, 200, 300, 250];
console.log(...nums); // 100 200 300 250
// 1. call 数组传参
fn.call({}, ...nums);
fn.apply({}, nums);
// 2. 计算数组中最大的元素
console.log(Math.max(...nums));
// 3. 把一个数组的成员 追加到另一个数组的尾部
const names = ['曹操', '张仁', '刘备'];
nums.push(...names); // nums, push('曹操', '张仁', '刘备')
console.log(nums); //[100, 200, 300, 250, "曹操", "张仁", "刘备"]
// 4. 克隆数组
// const nums1 = nums; //引用类型
const nums1 = [...nums]; //克隆版
nums1[2]= '啦啦啦';
console.log(nums1); //[100, 200, "啦啦啦", 250, "曹操", "张仁", "刘备"]
console.log(nums); //[100, 200, 300, 250, "曹操", "张仁", "刘备"]
// 5. 合并数组
const newArr = [...nums, ...nums1, ...names];
console.log(newArr);
// 6. 把字符串转换为数组
const newArr1 = [...'hello'];
console.log(newArr1); // ["h", "e", "l", "l", "o"]
// 7. 把类数组对象转为数组
const btns = document.querySelectorAll('button');
console.log(btns);
console.log([...btns]);
③ 解构赋值版的rest参数
// 与解构赋值一起使用 (解构赋值版的rest参数)
const [a, ...b] = [10,20,30,40,50,50,60];
console.log(a, b); // a是10, b是数组[20, 30, 40, 50, 50, 60]
8.2 Array函数新增方法
Array.from() 把类数组/字符串转为纯数组
Array.of() 创建数组,参数是数组的成员(任意个数的参数)
8.3 Array实例新增的方法
find() 参数是回调函数,返回第一个满足条件的元素
findIndex() 参数是回调函数,返回第一个满足条件的元素的索引
fill() 填充数组,覆盖数组中所有的元素;适合填充 new Array(20)创建的数组
includes() 判断数组中是否包含某个元素,返回布尔值; ES7新增的
flat() 把数组拉平(多维数组变为一维数组),参数默认是1(只拉1层), 可设置Infinity,不论维位数租 ES10新增
flatMap() 参数是回调函数,相当于map和flat的结合 ES10新增
9 对象的扩展
9.1 属性名表达式
{
[表达式]:值,
属性名: 值
}
9.2 super 关键字
1. super指向调用该函数的实例的原型
2. 只有对象的方法中才有super关键字,且简写形式定义的方法
{
foo(){
super; //得到super
}
}
9.3 对象的扩展运算符 ... (ES9新增)
定义:把对象转为用逗号分隔的键值对序列
作用:对象的解构赋值,对象操作(对象合并、对象克隆)
// 定义对象
const obj = {
name: '曹操',
age: 100,
say() {
console.log('My Name is ' + this.name);
},
};
console.log({ ...obj });
// 相当于
console.log(name:'曹操', age:100, say:fn);
// 对象克隆 (浅克隆)
const obj2 = { ...obj };
obj2.name = '刘备';
console.log(obj2);// {name: "刘备", age: 100, say: ƒ}
console.log(obj); // {name: "曹操", age: 100, say: ƒ}
// 对象合并 如果有重名属性,后面覆盖前面的
const obj3 = { width: 100, height: 200, name: '孙权' };
const obj4 = { ...obj, ...obj3 };
console.log(obj4); // {name: "孙权", age: 100, width: 100, height: 200, say: ƒ}
// 用于对象的解构赋值
const { age, ...b } = obj;
console.log(age); // 100
console.log(b); // {name: "曹操", say: ƒ}
9.4 Object函数新增的方法
Object.is() 用于比较两个数据是否相等,返回布尔值; 类似于全等,不同点NaN和Nan相等、+0和-0不相等
Object.assign() 合并对象
Object.getOwnPropertyDescriptor() 获取某个自身属性的描述信息
Object.getOwnProppertyDescriptors() 获取对象所有自身属性的描述信息 ES8新增
Object.getPrototypeOf() 获取对象的原型
Object.setPrototypeOf() 给对象设置原型
Object.keys() 返回数组,由对象的属性名组成。
Object.values() 返回数组,由对象的属性值组成。 ES8新增
Object.entries() 返回二维数组,由属性名和属性值 组成 ES8新增
Object.getOwnPropertyNames() 返回数组,有对象的属性名组成
Object.formEntries() Object.entries()的逆运算 ES8新增
10 Class语法
10.1 定义类(构造函数)
// 定义类
class Person {
// 属性,会添加到实例上
// 把所有的属性在这里声明
name = null;
age = null;
// 定义构造方法 实例化的时候自动执行
constructor(name, age = 10) {
this.name = name;
this.age = age;
}
// 方法,添加到原型上
say() {
console.log('MY Name is ' + this.name);
}
eat() {
console.log('My age is ' + this.age);
}
// 静态方法 没有添加到实例上,构造函数本身的方法
// static getClassName() {
// console.log('类名是 Person 构造函数本身的方法');
// }
}
// Person.getClassName(); // 相当于 Person.getClassName = function(){}
console.log(Person); //输出整个函数
console.log(typeof Person); // Function
console.log(Person.name); // Person ===> name指的是这个对象的名字
// 不能调用
// Person();
// 实例化
var p = new Person('曹操', 19);
console.log(p); // Person {name: "曹操", age: 19}
p.say(); // MY Name is 曹操
var p1 = new Person('吕布', 21);
console.log(p1); // Person {name: "吕布", age: 21}
p1.say(); // MY Name is 吕布
var p2 = new Person();
console.log(p2); // Person {name: undefined, age: 10}
注意:
class定义的类 本质还是个函数,但是不能被调用,只能被实例化
typeof 类名 === 'funciton'
10.2 实例化
new 类名;
new 类名(构造方法的参数);
10.3 静态方法
class Person{
static 方法名() {
}
}
Person.方法名()
// 静态方法没有添加给实例,添加给构造函数(类)本身
10.4 getter 和 setter
class Person {
firstName = '东方';
lastName = '不败';
get fullName() {
return this.firstName + '_' + this.lastName;
}
set fullName(val) {
const name = val.split('_');
this.firstName = name[0];
this.lastName = name[1];
}
}
let p = new Person();
console.log(p); //Person {firstName: "东方", lastName: "不败"}
console.log(p.fullName); //可读可写 东方_不败
10.5 继承
1. 使用 extends 来继承
2. 继承之后:
子类的实例的原型指向父类的一个实例
子类自己的原型指向父类 (静态方法也可以继承)
3. 可以在子类上添加属性和方法
4. 在子类上重写父类的方法,子类重写的方法必须调用super()
class 子类 extends 父类 {
constructor() {
super();
}
}
11 新增的数据类型(原始类型)
11.1 Symbol
1. 创建一Symbol数据(只能调用,不能实例化)
Symbol()
2. symbol数据特点:
① 每创建一个symbol类型的数据,都是唯一的。
② symbol类型的数据可以作为属性名,同字符串一样
3. 应用:
给对象添加属性(不会被覆盖)
4. 注意:(可以作为对象的属性名,(字符串)symbol创建的都是唯一的)
for...in、Object.keys()、Object.values()、Object.entries()、Object.getOwnPropertyNames() 这些方法都取不到属性名时Symbol类型的属性
Object.getOwnPropertySymbols() 获取类型是symbol的属性名
Reflect.ownKeys(obj) 获取对象自身所有的属性(不论属性名时什么类型)
11.2 BigInt (ES10)
① 安全数
通过 Number.MAX_SAFE_INTEGER 和 Number.MIN_SAFE_INTEGER 两个属性获得
如果整数超过了这个范围,无法按照整型的方式存储,计算会造成不精确
② BigInt类型
// 1. 字面量
var a = 100n
console.log(typeof a); //bigint
// 2 转换函数
var b = BigInt(1000)
console.log(b); //1000n
bigInt类型的数据适合比较大的数字运算
bigInt类型的数据只能和BigInt类型的数据运算,不能和number类型数据 相互运算
12 Set 和 Map
12.1 Set
① 描述
无序且不重复的多个值的 集合
② 创建一个Set类型的数据
new Set(); //创建的是空的Set
new Set(数组); //把数组变为Set,去掉重复的值
new Set(类数组)
③ Set实例的方法
add(value) 添加一个值
delete(value) 删除一个值
has(value) 判断是否存在某个值
clear() 删除所有的值
keys() 返回遍历器
values() 返回遍历器
entries() 返回遍历器
forEach() 用于遍历
size 属性 获取Set成员的个数
④ Set应用
1. 实现数组去重
const arr = new Set([100, 200, 300, 400, 300, 500, 500, 500]);
console.log(arr); //Set(5) {100, 200, 300, 400, 500}
12.2 Map
① 描述
Object对象是一种键值对(key-value)的集合,属性名就是键(key),属性值就是值(value)
Map类似于对象,也是键值对的集合,对象的Key只能是字符串和Symbol类型,Map的Key可以是任意类型
② 创建Map
// 创建空的
new Map();
// 创建的时候,指定初始值
new Map([
[key,value],
[key,value]
]);
③ Map实例的方法
get(key) 获取指定key的值
set(key,value) 设置或添加某个key的值
delete(key) 删除指定的某个key和他值
clear() 清空所有
has(key) 判断某个key是否存在
keys() 返回遍历器,所有key的集合
values() 返回遍历器,所有值的集合
entries() 返回遍历器,所有key-value的集合(二维)
forEach() 用于遍历
13.2 iterable 可遍历对象
① 什么是 iterable 可遍历对象
把部署了 iterator 接口的数据结构,称之为'iterable'(可遍历对象)
可以使用 for...of 遍历 iterable对象
iterator接口部署在了数据结构的Symbol.iterator属性上
一个对象,只有具有Symbol.iterator属性,且该属性指向一个返回遍历器的函数,该对象就是
② 原生实现了iterator接口的数据结构 (可遍历对象)
Array
Set
Map
String
Arguments
NodeList
HTMLcollection
14 generator 生成器
14.1 什么是生成器
生成器就是生成遍历器的函数
14.2 定义生成器
function* 生成器名() {
yield 值;
yield 值;
yield 值;
yield 值;
}
14.3 yield 关键字
yeild关键返回一个值, 遍历的时候每次得到就是yield的值
调用next(),执行到yield就会停止; 下一次调用next(),执行到下一个yield停止
调用生成器函数的时候,函数内不会执行
当调用next()的时候,才开始执行生成器函数内的代码; 执行到yield停止
14.4 使用生成器函数给对象部署iterator接口
const obj = {
name: '曹操',
age: 18,
score: 80,
height: 170
};
// 把obj变为一个 iterable
// 部署iterator接口
obj[Symbol.iterator] = function* (){
for (let i in obj) {
yield [i, obj[i]];
}
};
for (let i of obj) {
console.log(i); //可遍历对象
}
15 模块
15.1 模块中导出数据
// 模块内部
function say() {}
function eat() {}
export {
say,
eat
}
15.2 导入模块
import {say, eat} from '模块文件路径';
16 总结
16.1 ECMAScript中数据类型
原始类型(值类型): string、number、boolean、null、undefined、symbol、bigint
对象类型(引用类型): array、object、regexp、set、map......
16.2 ECMAScript中声明变量的方式
var 、 let 、 const (常量) 、 class 、 import、 function
16.3 实现数组扁平化的方式
const arr = [['a', 'b'],[10, [100, 200]],[['A', 'B'],['一', '二'],],1000,];
//方式一
//console.log(arr.flat(Infinity)); //["a", "b", 10, 100, 200, "A", "B", "一", "二", 1000]
//方式二 利用字符串的join方法 缺点:数组的元素都会变为字符串类型
//const arr2 = arr.join().split(',');
//console.log(arr2); //["a", "b", "10", "100", "200", "A", "B", "一", "二", "1000"]
//方式三: 递归
console.log(flatArray(arr));
function flatArray(array) {
//创建一个空数组
let res = [];
// 遍历传进来的数组
for (var i = 0; i < array.length; i++) {
//判断数组的元素还是不是数组
if (array[i] instanceof Array) {
res = res.concat(flatArray(array[i])); //继续调用把返回值拼起来,然后再赋值给res
// res = [...res, ...flatArray(arr[i])];
// res = res.concat(arguments.callee(arr[i]));
} else {
res.push(array[i]); //添加一个数组
}
}
//返回新数组
return res;
}
16.4 实现数组对象拷贝(克隆)的方式 (浅拷贝)
数组Array:
1. [...arr]
2. arr.concat() 不写参数 数组合并方式
3. arr.splice(0) / arr.substring(0) / arr.substr(0) 数组截取方式
对象Object:
1. {...obj}
2. Object.assign(obj) 对象合并方式
16.5 实现对象的深度克隆(深拷贝)
let sons = ['曹丕', '曹植', '曹冲'];
let sister = { name: '曹芹', age: 18 };
const obj = {
name: '曹操',
age: 100,
sons,
sister,
say() {},
eat() {},
};
// 1. 借助于JSON,无法拷贝方法,适合于纯数据对象
// JSON.parse(JSON.stringify(obj));
// 2. 使用递归函数 实现深度克隆
let obj1 = deepClone(obj);
obj1.sister.name = '曹雪芹';
console.log(obj);
console.log(obj1);
//定义函数 获取对象的构造函数(类)名
function getObjectClass(obj) {
return Object.prototype.toString.call(obj).slice(8, -1);
}
//深拷贝的函数
function deepClone(obj) {
//判断obj是对象是数组还是其他
if (getObjectClass(obj) === 'Object') {
var res = {}; //创建空的对象
} else if (getObjectClass(obj) === 'Array') {
var res = []; //创建空数组
} else {
return obj;
}
//对传入的对象(遍历)进行遍历
for (let i in obj) {
res[i] = deepClone(obj[i]);
}
//返回新数组或对象
return res;
}
16.6 遍历对象属性的方式
1. for ... in 遍历自身以及原型上可以被遍历的属性,属性名是symbol类型不可以
2. Object.keys()、Object.value()、Object.entries() 自身的属性,属性名是symbol类型不可以
3. Object.getOwnPropertyNames() 自身属性名的集合, 属性名是symbol类型不可以
4. Object.getOwnPropertySymbols() 自身属性名时symbol类型的属性名的集合
5. Reflec.ownKeys() 自身所有的属性名的集合 (字符串和symbol都可以)
16.7 Promise 对象
// promise对象状态:成功 -> 触发then的第一个回调
// promise对象状态:失败 -> 触发then的第二个回调
// then(onFulfilled, onRejected)
// 传了两个函数,这两个仅会执行一个
// then方法默认返回值 成功状态promise对象
// 什么时候会返回失败状态promise对象呢?
// 1. 方法中函数的返回值是一个失败状态的promise对象
// 2. 方法报错
// 除了以上两个方式,默认就是成功promise
const promise = new Promise((resolve, reject) => {
// 同步调用
resolve();
// reject();
console.log(111);
});
promise
.then(
() => {
console.log(222);
},
() => {
console.log(333);
// 返回一个失败状态promise对象
// return Promise.reject();
return new Promise((resolve, reject) => {
reject();
});
// 报错
// 抛异常(立即产生一个错误)
// throw 'error';
} // 默认返回成功状态promise对象
)
// 下一个then触发哪个?看上一个then的返回值promise状态
.then(
() => {
console.log(444);
},
() => {
console.log(555);
}
);
console.log(666); // 运行结果 111 666 222 444
16.8 Promise 对象其它状态
// Promise 一个异步编程的解决方案
// 作用:用来解决异步回调地狱问题(消除回调函数,以同步方式表达异步代码)
// 特点:
// 状态:
// 1. pending 初始化状态
// 2. resolved / fulfilled 成功状态
// 3. rejected 失败状态
// 注意:
// 同一时间,只能是一个状态
// 只能由初始化状态变成成功/失败状态
// 不能由成功变成失败,也不能由失败变成成功
// (状态初始化为pending,只能改变一次,要么成功,要么失败)
// 怎么判断promise对象的状态?
// then() / catch()
// 结果值:内部的结果值(value/reason)
// resolve(value)
// reject(reason)
// 怎么得到promise对象内部的结果值?
// then((value) => {}) / await
// catch((reason) => {})
// 怎么创建promise对象?
// new Promise() 默认是pending
// Promise.resolve() 默认是resolved
// Promise.reject() 默认是rejected
// 其他方法:
// Promise.all([promise1, promise2...])
// 返回值是一个新的promise对象,新promise对象状态看传入的promise
// 如果传入的promise状态都是成功的状态,新promise也成功
// 如果传入的promise状态有一个失败,新promise立即失败
// Promise.race([promise1, promise2...])
// 返回值是一个新的promise对象,新promise对象状态看传入的promise
// 只看传入的n个promise,哪一个传入promise状态先发生变化
// 新promise和先发生变化promise的状态一致
// Promise.allSettled([promise1, promise2...]) 源自ES11/ES2020
// 返回值是一个新的promise对象,一定是成功状态
// promise对象内部状态值,包含传入的n个promise对象的状态值
const promise11 = Promise.resolve();
const promise22 = Promise.reject();
console.log('成功状态', promise11); //成功状态 Promise {<fulfilled>: undefined}
console.log('失败状态', promise22); //失败状态 Promise {<rejected>: undefined}
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
reject(111);
}, 1000);
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject(222);
}, 2000);
});
const promise3 = new Promise((resolve, reject) => {
setTimeout(() => {
reject(333);
}, 3000);
});
// 只有全部成功才成功,只要有一个失败即失败
// Promise.all([promise1, promise2, promise3])
// .then(value => {
// console.log("成功了", value);
// })
// .catch(reason => {
// console.log("失败了", reason);
// });
// 只看执行最快那个,结果和先发生变化promise的状态一致,无论成功或失败
// Promise.race([promise2, promise1, promise3])
// .then(value => {
// console.log("成功了", value);
// })
// .catch(reason => {
// console.log("失败了", reason);
// });
// 等所有promise都执行完,返回成功状态
Promise.allSettled([promise1, promise2, promise3])
.then((value) => {
console.log('成功了', value);
})
.catch((reason) => {
console.log('失败了', reason);
});
16.9 防抖和节流
// 1、事件防抖 html代码部分
<input type="text" id="myInput" />
<script>
// 触发事件后,代码延迟执行 实用---> Keyup
// 持续触发事件,如果一定时间间隔内事件没有再次触发,执行事件逻辑
// 如果一定时间间隔内容事件再次触发,再次延迟一段事时间执行。多次事件只执行最后一次(无论触发多少次,只执行最后一次)
//获取元素
var myInput = document.querySelector('#myInput');
//事件防抖
var delay = 1000;
var timeId = null;
myInput.addEventListener('keyup', function () {
//清除掉上次的定时
clearTimeout(timeId);
//事件逻辑延迟执行
timeId = setTimeout(function () {
console.count();
}, delay);
});
</script>
// 2、事件节流 html代码部分
<input type="text" id="myInput" />
<script>
// 持续触发事件,保证一段时间内只触发一次
// 两次事件的时间间隔只有达到一定时间才能触发--->首先执行一次,然后在规定时间内执行
//获取元素
var myInput = document.querySelector('#myInput');
//监听事件 事件节流方式,1s之内只能触发一次
var prev = Date.now(); //上一次触发时间
var delay = 1000; //最小时间间隔
myInput.addEventListener('keyup', function () {
//记录此时的事件
var now = Date.now();
//两次事件的时间间隔 >= 1s种才能触发
if (now - prev < delay) {
return false;
}
//事件的逻辑
console.count();
//更新一下时间
prev = now;
});
</script>
牛人不是培养出来的,都是自己努力拼搏出来的,靠谁都不如靠自己,自己都不想主动多学习,只期望用一把锤子,就能搞定所有钉子,那你还不如想想怎么买彩票中500万吧,还更实际些,喜欢收藏,不喜勿喷,谢谢 ^_^