es6
1、判断数组中是否包含某个值
const arr = ['es6', 'es7', 'es8']
arr.includes('es6') //true, 包含:true 否则:false
arr.includes('es7', 1)//true
arr.includes('es7', 2)//false
arr.includes('ES6')//false
//如果只想知道某个值是否在数组中存在,而并不关心它的索引位置,建议使用includes(),如果想获取一个值在数组中的位置,那么使用indexOf方法。
const arr = ['es6', 'es7', NaN, 'es8']
console.log(arr.includes(NaN)) // true
console.log(arr.indexOf(NaN)) // -1
注意:
1、使用 includes()查找字符串是区分大小写的。
2、只能判断简单类型的数据,对于复杂类型的数据,比如对象类型的数组,二维数组,这些是无法判断的
3、能识别NaN,indexOf是不能识别NaN的
2、es6判断arr数组中的对象是否包含某个key值
arr.findIndex((item) => item.prop === obj.prop);
// >=0 是包含
//当数组里的对象为字符串时用这个方法更简单
arr.indexOf(str)
获取文件后缀
//文件路径
var filePath = "file://upload/jb51.png";
//filePath.lastIndexOf(".");//获取最后一个.的位置
//获取后缀
var ext = filePath.substr(filePath.lastIndexOf(".")+1);
//输出结果
console.log(ext);
3、删除数组中的某一项
arr.splice(arr.findIndex(item => item.i === i), 1)
4、数组排序 sort
let arr = [2,1,3,5,4];
arr= arr.sort((n1,n2)=>{
// return -1; //返回负值 交换顺序
// return 0 或者 1 //返回正值 保持顺序不变
console.log(n1,n2);
return n2-n1;
// n2 - n1 从大到小
// n1 - n2 从小到大
});
5、解构赋值
5.1 对象结构赋值
var obj ={ name:"张三",age:18 };
//用解构赋值的方式获取name、age
let { name } = obj; //创建了一个变量name,值=obj.name
console.log(name); //"张三"
let { age } =obj;
console.log(age); //18
5.2函数参数结构赋值
function f1(obj){
console.log(obj.age);
console.log(obj.height)
}
//等于
function f1({ age,height }){
console.log(age);
console.log(height)
}
f1({age:5,height:180})
6、rest参数
arguments类似Array但是并不是Array。而rest就是一个Array。用rest替代atguments
//arguments变量的写法:
function sortFunc(){
return Array.prototype.slice.call(arguments).sort();
}
//而rest参数的写法:
const sortFunc = (...numbers) => number.sort();
function foo(a,b,...rest){
console.log(a);
console.log(b);
console.log(rest);
}
foo(1,2,3,4,5) //1,2,Array [3,4,5]
foo(1) //1, undefined, Array[]
rest参数只能写在最后,前面用...标识,从运行结果可知,传入的参数先绑定a、b,多余的参数以数组形式交给变量rest,所以,不再需要arguments我们就获取了全部参数。如果传入的参数连正常定义的参数都没填满,也不要紧,rest参数会接收一个空数组(注意不是undefined)。
7、箭头函数
1、基本用法
//匿名函数
div.onclick=function(){
console.log("你好")
}
//==
div.onclick=()=>{
console.log("你好")
}
2、有参数
let fn=(a)=>{
console.log("abc");
}
//==
let fn=a=>{
console.log("abc");
}
//有2个及更多参数的箭头函数
let f=(a,b,c)=>{
console.log("abc")
}
3、还有这种
let p={
age:18,
//es6中对象方法的箭头函数表示形式
run:()=>{
setTimeout(()=>{
//this:window
console.log(this);//this是window
},100)
},
}
8、Promise
8.1 在没有promise都是这样写的回调,一层一层的写,解决es5的魔鬼回调
$.get("/getUser",function(res){
$.get("/getUserDetail",function(){
$.get("/getCart",function(){
$.get("/getBooks",function(){
//...
})
})
})
})
8.2 promise的基本用法
var promise=new Promise((resolve,reject)=>{
//b 把需要执行的异步操作放在这里
$.get("/getUser",res=>{
//获取数据的异步操作已经执行完毕了,等待下一步的执行,通过执行resolve函数,告诉外界你可以执行下一步操作了
//c、
resolve(res)
//而执行的下一步操作,其实就是写在then的回调函数中的
})
})
//a、
promise.then(res=>{
//d、执行后续的操作
console.log(res);
})
8.3 promise实现多层回调
new Promise((resolve,reject)=>{
$.get("/getUser",res=>{
resolve(res)
})
}).then(res=>{
//用户基本信息
return new Promise(resolve=>{
$.get("/getUserDetail",res=>{
resolve(res)
})
})
}).then(res=>{
//用户详情
return new Promise(resolve=>{
$.get("/getCart",res=>{
resolve(res)
})
})
}).then(res=>{
//购物车信息
})
8.4 promise实现错误处理
new Promise((resolve,reject)=>{
$.ajax({
url:"/getUser",
type:"GET",
success:res=>{
resolve(res);
},
error:res=>{
reject(res)
}
})
}).then(resSuccess=>{
//成功的返回值
},resError=>{
//失败的返回值
})
8.5 Promise.prototype.finally()
fulfilled或者是rejected,在执行then()和catch()后,都会执行finally指定的回调函数
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success')
// reject('fail')
}, 1000)
}).then(res => {
console.log(res)
}).catch(err => {
console.log(err)
}).finally(() => {
console.log('finally')
})
使用场景:loading关闭
es7
9、幂运算符
比如想求2的3次方。
1、Math.pow()
console.log(Math.pow(2, 3)); // 8
2、幂运算符 **
console.log(2 ** 10); // 8
es8
10、Object.values()
Object.values 方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值。
const obj = {
name: "jimmy",
age: 18,
height: 188,
};
console.log(Object.values(obj)); // [ 'jimmy', 18, 188 ]
11、Object.entries()
Object.entries() 方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历属性的键值对数组。
const obj = {
name: "jimmy",
age: 18,
height: 188,
};
console.log(Object.entries(obj)); // [ [ 'name', 'jimmy' ], [ 'age', 18 ], [ 'height', 188 ] ]
console.log(Object.entries([1, 2, 3])); // [ [ '0', 1 ], [ '1', 2 ], [ '2', 3 ] ]
12、Object.getOwnPropertyDescriptors()
Object.getOwnPropertyDescriptors() 方法用来获取一个对象的所有自身属性的描述符。
const obj = {
name: "jimmy",
age: 18,
};
const desc = Object.getOwnPropertyDescriptors(obj);
console.log(desc);
// 打印结果
{
name: {
value: 'jimmy',
writable: true,
enumerable: true,
configurable: true
},
age: {
value: 18,
writable: true,
enumerable: true,
configurable: true
}
}
- value表示当前对象的默认值
- writable表示对象属性是否可以修改
- enumerable表示当前这个属性是否可以出现在对象的枚举属性中(false:属性不可被枚举,这时打印对象为空,遍历对象的键也为空。)
- configurable表示当前对象的属性能否用delete删除
当把属性修改为false时,下面是演示:
const obj = {};
Object.defineProperty(obj, "name", {
value: "jimmy",
writable: false,
configurable: false,
enumerable: true,
});
console.log(obj); // { name: 'jimmy' }
obj.name = "chimmy";//修改失败
console.log(obj); // { name: 'jimmy' }
delete obj.name//删除失败
console.log(obj); // { name: 'jimmy' }
13、String.prototype.padStart
把指定字符串填充到字符串头部,返回新字符串。
语法:str.padStart(targetLength [, padString])
- targetLength(当前字符串需要填充到的目标长度。如果这个数值小于当前字符串的长度,则返回当前字符串本身)
- padString 可选(填充字符串。如果字符串太长,使填充后的字符串长度超过了目标长度,则只保留最左侧的部分,其他部分会被截断。此参数的默认值为 " ")
示例:
'abc'.padStart(10); // " abc"
'abc'.padStart(10, "foo"); // "foofoofabc"
'abc'.padStart(6,"123465"); // "123abc"
'abc'.padStart(8, "0"); // "00000abc"
'abc'.padStart(1); // "abc"```
应用场景:
日期格式化:yyyy-mm-dd的格式:
const now = new Date()
const year = now.getFullYear()
// 月份和日期 如果是一位前面给它填充一个0
const month = (now.getMonth() + 1).toString().padStart(2, '0')
const day = (now.getDate()).toString().padStart(2, '0')
console.log(year, month, day)
console.log( `${year}-${month}-${day}` ) //输入今天的日期 2021-12-31
数字替换(手机号,银行卡号等):
const tel = '18781268679'
const newTel = tel.slice(-4).padStart(tel.length, '*')
console.log(newTel) // *******5678
14、String.prototype.padEnd
把指定字符串填充到字符串尾部,返回新字符串。语法同13
'abc'.padEnd(10); // "abc "
'abc'.padEnd(10, "foo"); // "abcfoofoof"
'abc'.padEnd(6, "123456"); // "abc123"
'abc'.padEnd(1); // "abc"
15、async/await
Promise 能很好地解决回调地狱的问题,但如果处理流程比较复杂的话,那么整段代码将充斥着 then,语义化不明显,代码不能很好地表示执行流程,那有没有比 Promise 更优雅的异步方式呢?那就是async/await!
前面添加了async的函数在执行后都会自动返回一个Promise对象:
function foo() {
return 'jimmy'
}
console.log(foo()) // 'jimmy'
添加async后:
async function foo() {
return 'jimmy' // Promise.resolve('jimmy')
}
console.log(foo()) // Promise
foo()
async函数中使用await,那么await这里的代码就会变成同步的了,意思就是说只有等await后面的Promise执行完成得到结果才会继续下去,await就是等待。请看下面的示例:
function timeout() {
return new Promise(resolve => {
setTimeout(() => {
console.log(1)
resolve()
}, 1000)
})
}
// 不加async和await是2、1 加了是1、2
async function foo() {
await timeout()
console.log(2)
}
foo()
使用场景:
假如有这样一个使用场景:需要先请求 a 链接,等返回信息之后,再请求 b 链接的另外一个资源。下面代码展示的是使用 fetch 来实现这样的需求,fetch 被定义在 window 对象中,它返回的是一个 Promise 对象。
fetch('https://blog.csdn.net/')
.then(response => {
console.log(response)
return fetch('https://juejin.im/')
})
.then(response => {
console.log(response)
})
.catch(error => {
console.log(error)
})
//async/await
async function foo () {
try {
let response1 = await fetch('https://blog.csdn.net/')
console.log(response1)
let response2 = await fetch('https://juejin.im/')
console.log(response2)
} catch (err) {
console.error(err)
}
}
foo()
注意:
- await 只能在 async 标记的函数内部使用,单独使用会触发 Syntax error。
- await后面需要跟异步操作,不然就没有意义,而且await后面的Promise对象不必写then,因为await的作用之一就是获取后面Promise对象成功状态传递出来的参数。
es9
16、Object Rest & Spread
16.1 spread 语法,可以把 input 对象的数据都拓展到 output 对象
const input = {
a: 1,
b: 2,
c: 3,
}
const output = {
...input,
c: 4
}
console.log(output) // {a: 1, b: 2, c: 4}
注意:如果属性的值是一个对象的话,该对象的引用会被拷贝,而不是生成一个新的对象。
const obj = { x: { y: 10 } };
const copy1 = { ...obj };
const copy2 = { ...obj };
obj.x.y = "jimmy";
console.log(copy1, copy2); // x: {y: "jimmy"} x: {y: "jimmy"}
console.log(copy1.x === copy2.x); // → true
16.2 当对象 key-value 不确定的时候,把必选的 key 赋值给变量,用一个变量收敛其他可选的 key 数据,这在之前是做不到的。注意,rest 属性必须始终出现在对象的末尾,否则将抛出错误。
const input = {
a: 1,
b: 2,
c: 3
}
let { a, ...rest } = input
console.log(a, rest) // 1 {b: 2, c: 3}
17、for await of
for of:
function TimeOut(time){
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(time)
}, time)
})
}
async function test() {
let arr = [TimeOut(2000), TimeOut(1000), TimeOut(3000)]
for (let item of arr) {
console.log(item.then(console.log))
}
}
test()
结果:
1000
2000
3000
for…await…of :
function TimeOut(time) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(time)
}, time)
})
}
async function test() {
let arr = [TimeOut(2000), TimeOut(1000), TimeOut(3000)]
for await (let item of arr) {
console.log(item)
}
}
test()
结果:
2000
1000
3000
18、Object.fromEntries()
18.1 过滤。course表示所有课程,想请求课程分数大于80的课程组成的对象:
const course = {
math: 80,
english: 85,
chinese: 90
}
const res = Object.entries(course).filter(([key, val]) => val > 80)
console.log(res) // [ [ 'english', 85 ], [ 'chinese', 90 ] ]
console.log(Object.fromEntries(res)) // { english: 85, chinese: 90 }
18.2 把键值对列表转换为一个对象,这个方法是和 Object.entries() 相对的
Object.fromEntries([
['foo', 1],
['bar', 2]
])
// {foo: 1, bar: 2}
18.3 url的search参数转换
/ let url = "https://www.baidu.com?name=jimmy&age=18&height=1.88"
// queryString 为 window.location.search
const queryString = "?name=jimmy&age=18&height=1.88";
const queryParams = new URLSearchParams(queryString);
const paramObj = Object.fromEntries(queryParams);
console.log(paramObj); // { name: 'jimmy', age: '18', height: '1.88' }
es10
19、flat()
方法会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。
const arr1 = [0, 1, 2, [3, 4]];
console.log(arr1.flat()); // [0, 1, 2, 3, 4]
const arr2 = [0, 1, 2, [[[3, 4]]]];
console.log(arr2.flat(2)); // [0, 1, 2, [3, 4]]
//使用 Infinity,可展开任意深度的嵌套数组
var arr4 = [1, 2, [3, 4, [5, 6, [7, 8, [9, 10]]]]];
arr4.flat(Infinity); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
// `flat()` 方法会移除数组中的空项:
var arr5 = [1, 2, , 4, 5];
arr5.flat(); // [1, 2, 4, 5]
20、flatMap()
方法首先使用映射函数映射每个元素,然后将结果压缩成一个新数组。从方法的名字上也可以看出来它包含两部分功能一个是 map,一个是 flat(深度为1)
对比map:
const numbers = [1, 2, 3]
numbers.map(x => [x * 2]) // [[2], [4], [6]]
numbers.flatMap(x => [x * 2]) // [2, 4, 6]
let arr = ['今天天气不错', '', '早上好']
arr.map(s => s.split(''))
// [["今", "天", "天", "气", "不", "错"],[""],["早", "上", "好"]]
arr.flatMap(s => s.split(''))
// ["今", "天", "天", "气", "不", "错", "", "早", "上", "好"]
21、trimStart()
从字符串的开头删除空格,trimLeft()是此方法的别名。
let str = ' foo '
console.log(str.length) // 8
str = str.trimStart() // 或str.trimLeft()
console.log(str.length) // 5
22、.trimEnd()
从一个字符串的右端移除空白字符,trimRight 是 trimEnd 的别名
let str = ' foo '
console.log(str.length) // 8
str = str.trimEnd() // 或str.trimRight()
console.log(str.length) // 6
23、验证参数是否为json格式
const validJSON = json => {
try {
JSON.parse(json)
return true
} catch {
return false
}
}
es11
24、空值合并运算符
24.1 ??逻辑操作符,当左侧的操作数为 null或者undefined时,返回其右侧操作数,否则返回左侧操作数。
const foo = undefined ?? "foo"
const bar = null ?? "bar"
console.log(foo) // foo
console.log(bar) // bar
24.2 ||逻辑或操作符会在左侧操作数为假值时返回右侧操作数,比如为假值(例如’',0,NaN,false)
const foo = "" ?? 'default string';
const foo2 = "" || 'default string';
console.log(foo); // ""
console.log(foo2); // "default string"
const baz = 0 ?? 42;
const baz2 = 0 || 42;
console.log(baz); // 0
console.log(baz2); // 42
注:?? || 不可同时使用(null || undefined ?? “foo”; // 抛出 SyntaxError
24.3 可选链 Optional chaining
当尝试访问可能不存在的对象属性时,就会命中 Uncaught TypeError: Cannot read property… 这种错误
// 对象中使用
let obj = {
name: "jimmy",
age: "18",
};
let property = "age";
let name = obj?.name;
let age = obj?.age;
let ages = obj?.[property];
let sex = obj?.sex;
console.log(name); // jimmy
console.log(age); // 18
console.log(ages); // 18
console.log(sex); // undefined
// 数组中使用
let arr = [1,2,2];
let arrayItem = arr?.[42]; // undefined
// 函数中使用
let obj = {
func: function () {
console.log("I am func");
},
};
obj?.func(); // I am func
与空值合并操作符一起使用
let customer = {
name: "jimmy",
details: { age: 18 }
};
let customerCity = customer?.city ?? "成都";
console.log(customerCity); // "成都"
注意:可选链不能用于赋值
let object = {};
object?.property = 1; // Uncaught SyntaxError: Invalid left-hand side in assignment
25、matchAll()
返回一个包含所有匹配正则表达式的结果及分组捕获组的迭代器。
const regexp = /t(e)(st(\d?))/g;
const str = 'test1test2';
const array = [...str.matchAll(regexp)];
console.log(array[0]); // ["test1", "e", "st1", "1"]
console.log(array[1]); // ["test2", "e", "st2", "2"]```
26、Dynamic Import(按需 import)
import()可以在需要的时候,再加载某个模块。
button.addEventListener('click', event => {
import('./dialogBox.js')
.then(dialogBox => {
dialogBox.open();
})
.catch(error => {
/* Error handling */
})
});
上面代码中,import()方法放在click事件的监听函数之中,只有用户点击了按钮,才会加载这个模块。
es12
27、逻辑运算符和赋值表达式(&&=,||=,??=)
- &&=
逻辑与赋值 x &&= y等效于:
x && (x = y);//当x为真时,x=y
如:
let a = 1;
let b = 0;
let c = -1;
a &&= 2;
console.log(a); // 2
b &&= 2;
console.log(b); // 0
c &&= 2;
console.log(c); //2
- ||=
逻辑或赋值(x ||= y)运算仅在 x 为false时赋值。
x ||= y 等同于:x || (x = y);
如:
const a = { duration: 50, title: '' };
a.duration ||= 10;
console.log(a.duration); // 50
a.title ||= 'title is empty.';
console.log(a.title); // "title is empty"
- ??=
逻辑空赋值运算符 (x ??= y) 仅在 x 是 nullish[3] (null 或 undefined) 时对其赋值。
x ??= y 等价于:x ?? (x = y);
如:
const a = { duration: 50 };
a.duration ??= 10;
console.log(a.duration); // 50
a.speed ??= 25;
console.log(a.speed); // 25
如2:
function config(options) {
options.duration ??= 100;
options.speed ??= 25;
return options;
}
config({ duration: 125 }); // { duration: 125, speed: 25 }
config({}); // { duration: 100, speed: 25 }
28、String.prototype.replaceAll()
返回一个新字符串,原始字符串保持不变
aabbcc'.replaceAll('b', '.'); // 'aa..cc'
'aabbcc'.replaceAll(/b/, '.');//使用正则表达式搜索值时,它必须是全局的
//TypeError: replaceAll must be called with a global RegExp
'aabbcc'.replaceAll(/b/g, '.');//"aa..cc"
29、数字分隔符
欧美语言中,较长的数值允许每三位添加一个分隔符(通常是一个逗号),增加数值的可读性。比如,1000可以写作1,000。
ES2021中允许 JavaScript 的数值使用下划线(_)作为分隔符。
123_00 === 12_300 // true
12345_00 === 123_4500 // true
12345_00 === 1_234_500 // true
注意:
不能放在数值的最前面(leading)或最后面(trailing)。
不能两个或两个以上的分隔符连在一起。
小数点的前后不能有分隔符。
科学计数法里面,表示指数的e或E前后不能有分隔符。
30、Promise.any
只要参数实例有一个变成fulfilled状态,包装实例就会变成fulfilled状态;如果所有参数实例都变成rejected状态,包装实例就会变成rejected状态。
const promise1 = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("promise1");
// reject("error promise1 ");
}, 3000);
});
};
const promise2 = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("promise2");
// reject("error promise2 ");
}, 1000);
});
};
const promise3 = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("promise3");
// reject("error promise3 ");
}, 2000);
});
};
Promise.any([promise1(), promise2(), promise3()])
.then((first) => {
// 只要有一个请求成功 就会返回第一个请求成功的
console.log(first); // 会返回promise2
})
.catch((error) => {
// 所有三个全部请求失败 才会来到这里
console.log("error", error);
});