1. JS 2015(ES6)
1.2 Let关键字
用来声明变量
特点
- 不允许重复声明
- 块儿级作用域
- 不存在变量提升
- 不影响作用域链
案例
// 变量不能重复声明
let star = '罗志祥';
let star = '小猪'; //报错,变量不能重复声明
// 块儿级作用域
{
let girl = '周扬青';
}
console.log(girl); // 报错
// 不存在变量提升
console.log(song); //报错,如果是var song="",才能挑用
let song = '恋爱达人';
// 不影响作用域链
{
let school = '555';
function fn () {
console.log(school);
}
fn();
}
补充作用域知识
-
函数作用域 function{ },块级作用域 {}。 一定要有 function 关键字,才会有函数作用域。
-
js里面 var声明的变量只有函数作用域,没有块级作用域。(也就是说,函数可以隔离变量, *在{}、if、else、while、for里面 *不能隔离变量)。
// 有两个for循环: for (var i = 0; i < 3; i++) {} for (var i = 0; i < 4; i++) {} console.log(i); //在for循环外面可以打印i的值 -
由于两个并列的for只是两个并列的代码块,并不是两个并列的函数,因此它们里面声明的 i 同为一个全局变量。(第二个for里面的 i 相当于将已经存在的 i 重新声明并赋值而已)
-
因此,可在全局(外部)通过console.log看到 i 的值。
1.2 const关键字
用于定义常量,值不能修改,就算重新赋值不会报错,值也不会改变
特点
- 声明必须赋初始值
- 标识符一般为大写
- 不允许重复声明
- 值不允许修改
- 块儿级作用域
案例
// 一般变量使用大写(潜规则)
// 一定要赋初始值,不赋值报错
// 常量的值不能被修改
const SCHOOL = "西南石油大学";
// 对于数组和对象元素的修改,不算对常量的修改,不会报错
const LIKE = ["HG", "MC", "LZZ"];
LIKE.push("ZZC");
console.log(LIKE); // ['HG', 'MC', 'LZZ', 'ZZC']
1.3 变量的解构赋值
ES6 允许按照一定模式从数组和对象中提取值,对变量进行赋值,这被称为解构赋值
// 数组结构赋值
const F4 = ["小沈阳", "赵四", "刘能", "宋小宝"];
let [xiao, zhao, liu, song] = F4;
console.log(xiao); // 小沈阳
console.log(zhao); // 赵四
console.log(liu); // 刘能
console.log(song); // 宋小宝
// 对象结构赋值
const zhao = {
name: "赵本山",
age: "65",
xiaoping: function () {
console.log("我会演小品");
},
};
let { name, age, xiaoping } = zhao;
console.log(name); // 赵本山
console.log(age); // 65
console.log(xiaoping); // 输出ƒ(){}
xiaoping(); // 我会演小品
// 如果不用结构的形式
console.log(zhao.name);
console.log(zhao.age);
zhao.xiaoping();
zhao.xiaoping();
1.4 模板字符串
用于字符串声明,以及简化变量拼接
// 内容可以直接出现换行符
let str =
`<ul>
<li>张三1</li>
<li>李四2</li>
<li>王五3</li>
</ul>`;
// 变量拼接
let str = "许巍";
let lovest = `我喜欢${str}的歌,名字叫做<<蓝莲花>>。`;
1.5 对象的简化写法
ES6 允许在大括号里面,直接写入变量和函数,作为对象的属性和方法。
// ES6 允许在大括号里面, 直接写入变量和函数, 作为对象的属性和方法
let name = '小康';
let change = function () {
console.log('我们可以改变你!');
}
const school = {
name,
// 老方式
change,
// 新方式直接写入变量和函数
improve() {
console.log('我们可以提高你的技能');
}
}
console.log(school);
1.6 箭头函数
使用「箭头」(=>)简化定义函数
特点
- 如果形参只有一个,则小括号可以省略
- 函数体如果只有一条语句,则花括号可以省略,函数的返回值为该条语句的执行结果
- 箭头函数中 this 是静态的. this 始终指向函数声明时所在作用域下的this 的值
- 箭头函数不能作为构造函 数实例化
- 不能使用 arguments
案例
function getName() {
console.log(this.name);
}
// 声明函数
let getName2 = () => {
console.log(this.name);
};
window.name = "红石榴21";
const school = {
name: "博商学院",
};
getName(); // 红石榴21
getName2(); // 红石榴21
getName.call(school); // 博商学院
// this 是静态的,this 始终指向函数声明时所在作用域下的 this 的值
getName2.call(school); // 红石榴21
// 不能作为构造函数实例化对象
let Person = (name, age) => {
this.name = name;
this.age = age;
};
let me = new Person("hong", 18);
console.log(me); // 报错:Person is not a constructor
// 不能使用 arguments 变量
let fn = () => {
console.log(arguments);
};
fn(1, 2, 3); // 报错:arguments is not defined
// 箭头函数的简写
// 1) 省略小括号,当形参有且只有一个的时候
let add = n => {
return n + n;
};
console.log(add(9)); // 18
// 2) 省略花括号,当代码体只有一条语句的时候,此时 return 必须省略
// 而且语句的执行结果就是函数的返回值
let pow = (n) => n * n;
console.log(pow(9)); // 81
应用场景
// 需求-1 点击 div 2s 后颜色变成『粉色』
// 获取元素
let add = document.getElementById("add");
//绑定事件
add.addEventListener("click", function () {
// 1、setTimeout未使用箭头函数
//保存 this 的值
let _this = this;
let that = this;
let self = this;
setTimeout(function () {
_this.style.background = "pink";
}, 2000);
// 2、setTimeout使用箭头函数, this 是静态的
setTimeout(() => {
this.style.background = "pink";
}, 2000);
});
// 需求-2 从数组中返回偶数的元素
const arr = [1, 2, 4, 6, 10, 13];
const result1 = arr.filter(function (item) {
if (item % 2 === 0) {
return true;
} else {
return false;
}
});
// const result = arr.filter((item) => {
// if (item % 2 === 0) {
// return true;
// } else {
// return false;
// }
// });
// 简写形式
const result2 = arr.filter((item) => item % 2 === 0);
console.log(result2);
// 箭头函数适合与 this 无关的回调,定时器,数组的方法回调
// 箭头函数不适合与 this 有关的回调,事件回调,对象的方法
17. 函数参数的默认值设置
给函数的参数设置默认值
// 形参初始值 具有默认值的参数,一般位置要靠后(潜规则)
// 设置默认值
function add(a, b, c = 4) {
return a + b + c;
}
// 与结构赋值结合
function connect({ host, username, password, port }) {
console.log(host);
console.log(username);
console.log(password);
console.log(port);
}
connect({
host: "127.0.0.1",
username: "admin",
password: "admin",
port: 80,
});
1.8 rest参数
用于获取函数的实参,用来代替 arguments
// rest 参数必须要放到参数最后
function fn(a, b, ...args) {
console.log(a); // 1
console.log(b); // 2
console.log(args); // [3, 4, 5, 6] ,变成数组就可以使用 filter、some、every、map
}
fn(1, 2, 3, 4, 5, 6);
1.9 扩展运算符的介绍
『...』 扩展运算符能将『数组』转换为逗号分隔的『参数序列』
// 声明一个数组
const tfbody = ["朴树", "许巍", "刀郎"];
console.log(...tfbody);// 朴树,许巍,刀郎
// 数组的合并,将两个输出合并成一个
const a = ["1", "2"];
const b = ["3", "4"];
// const v = a.concat(b); // 使用concat实现数组拼接
// console.log(v); // ["1", "2", "3", "4"]
const c = [...a, ...b];
console.log(c); // ["1", "2", "3", "4"]
// 数组的克隆
const a1 = ["A", "B", "C"];
const a2 = [...a1];
console.log(a1); // ["A", "B", "C"]
console.log(a2); // ["A", "B", "C"]
// 将伪数组转为真正的数组
const divS = document.querySelectorAll("div");
const divArr = [...divS];
console.log(divArr);
1.10 Symbol
一种新的原始数据类型 Symbol,表示独一无二的值。它是 JavaScript 语言的第七种数据类型,是一种类似于字符串的数据类型。
特点
- Symbol 的值是唯一的,用来解决命名冲突的问题
- Symbol 值不能与其他数据进行运算
- Symbol 定义 的 对象属性 不能 使 用 for…in 循 环遍 历 ,但 是可 以 使 用 Reflect.ownKeys 来获取对象的所有键名
案例
// 创建Symbol
let s = Symbol();
console.log(s, typeof s); // Symbol() 'symbol'
let s2 = Symbol("嘀嘀咕咕");
let s3 = Symbol("嘀嘀咕咕");
console.log(s3.description);// 嘀嘀咕咕 description取值
console.log(s2, typeof s2); // Symbol(嘀嘀咕咕) 'symbol'
console.log(s2 === s3); // false
// Symbol.for 创建
let s4 = Symbol.for("我的心思");
let s5 = Symbol.for("我的心思");
console.log(s4); // Symbol(我的心思)
console.log(s4 === s5); // true
// 不能与其他数据进行运算
let result = s + 100; // Cannot convert a Symbol value to a number
let result = s > 100; // Cannot convert a Symbol value to a number
let result = s + s; // Cannot convert a Symbol value to a number
// 对象添加Symbol类型的属性
let phws = {
name: "排核污水",
[Symbol("say")]: function () {
console.log("打断小日子的狗腿");
},
[Symbol("woof")]: function () {
console.log("小日子公开食海鲜,真香");
},
};
console.log(phws);
内置属性
// 当其他对象使用 instanceof 运算符,判断是否为该对象的实例时,会调用这个方法
class Person {
/* static Symbol.hasInstance {
console.log(param);
console.log("我被用来检测类型了");
return true;
} */
static [Symbol.hasInstance](param) {
console.log(param);
console.log("我被用来检测类型了");
return true;
}
}
console.log({} instanceof Person);
// SymbolisConcatSpreadable 属性等于的是一个布尔值,表示该对象用于Array.prototype.concat()时,是否可以展开
const arr = [1, 2, 3];
const arr2 = [4, 5, 6];
arr2[Symbol.isConcatSpreadable] = false;
console.log(arr.concat(arr2));
其他内置属性
| 属性名称 | 描述 |
|---|---|
| Symbol.hasInstance | 当其他对象使用instanceof运算符,判断是否为该对象的实例时,会调用这个方法。 |
| Symbol.isConcatSpreadable | 这个内置的Symbol用于配置对象作为Array.prototype.concat()方法的参数时是否展开其数组元素。 |
| Symbol.species | 这个Symbol值用于访问构造函数中用于创建派生对象的函数。 |
| Symbol.match | 当一个字符串需要匹配正则表达式时,会调用这个方法。 |
| Symbol.replace | 当一个字符串需要替换匹配的字符时,会调用这个方法。 |
| Symbol.search | 当一个字符串需要查找匹配的字符时,会调用这个方法。 |
| Symbol.split | 当一个字符串需要分割为数组时,会调用这个方法。 |
| Symbol.iterator | 这个Symbol值用于访问对象的默认迭代器。 |
| Symbol.toPrimitive | 这个Symbol值用于将一个对象转换为原始类型的表示。 |
| Symbol.toStringTag | 这个Symbol值用于访问对象的默认字符串表示。 |
| Symbol.unscopables | 这个Symbol值包含一个对象的可作用域属性名集合。 |
1.11 迭代器
迭代器(Iterator)用于数据遍历。
它是一种接口,任何数据结构只要部署 Iterator 接口(就是对象里面的一个属性方法Symbol.Iterator),就可以实现遍历操作。
通过for...of 循环遍历命令进行迭代器的消费,原生具备 iterator 接口的数据如下:
- Array
- Arguments
- Set
- Map
- String
- TypedArray
- NodeList
// 声明一个数组
const tangShengShiTu = ["唐僧", "孙悟空", "猪八戒", "沙和尚"];
// 使用 for...in 遍历的是key
for (let v in tangShengShiTu) {
console.log(v); // 0,1,2,3
}
// 使用 for...of 遍历数组value
for (let v of tangShengShiTu) {
console.log(v); // "唐僧", "孙悟空", "猪八戒", "沙和尚"
}
工作原理
- 创建一个
指针对象,指向当前数据结构的起始位置 - 第一次调用对象的 next 方法,指针自动指向数据结构的第一个成员
- 接下来不断调用 next 方法,指针一直往后移动,直到指向最后一个成员
- 每调用 next 方法返回一个包含 value 和done 属性的对象,done = false 后面还有数据,true后面没有数据
// 声明一个数组
const a = ["1111", "2222", "3333", "4444"];
// 创建一个指针对象,指向当前数据结构的起始位置
let iterator =a[Symbol.iterator]();
// 第一次调用对象的 next 方法,指针自动指向数据结构的第一个成员
console.log(iterator.next()); // {value: '1111', done: false}
//接下来不断调用 next 方法,指针一直往后移动,直到指向最后一个成员
console.log(iterator.next()); // {value: '2222', done: false}
console.log(iterator.next()); // {value: '3333', done: false}
console.log(iterator.next()); // {value: '4444', done: false}
console.log(iterator.next()); // {value: '', done: true}
对象实现自定义迭代器
const fruits = {
name: "水果店",
stuList: ["A", "B", "C", "D"],
// 重写Symbol.iterator
[Symbol.iterator]() {
let index = 0;
// 写next函数
let next = () => {
if (index < this.stuList.length) {
const result = { value: this.stuList[index], done: false };
// 下标自增
index++;
// 返回结果
return result;
} else {
return { value: this.stuList[index], done: true };
}
};
return { next };
},
};
// 遍历fruits对象,就可以调用自定义的迭代器
for (let v of fruits) {
console.log(v); // "A", "B", "C", "D"
}
1.12 Generator函数
生成器函数是一种异步编程解决方案,语法行为与传统函数完全不同
定义生成器函数
- 需要再方法上面加
*(function * 方法名(){}) - 函数内执行语句必须与
yield搭配使用
yield作用:
(1)函数代码的分隔符,断开,回找,上下步有顺序
(2)接收下一个next传回来的参数
基本使用
// 定义生成器函数
function * gen() {
console.log(111);
yield "光辉岁月";// 函数代码的分隔符,yield 定义next的返回值
console.log(222);
yield "蓝莲花";
console.log(333);
yield "像风一样自由";
console.log(444);
}
gen();// 生成器函数普通调用不执行
let iterator = gen();
console.log(iterator.next()); // 111 {value: '光辉岁月', done: false}
console.log(iterator.next()); // 222 {value: '蓝莲花', done: false}
console.log(iterator.next()); // 333 {value: '像风一样自由', done: false}
console.log(iterator.next()); // 444 {value: 'undefined', done: true}
// next时done=true,for就没有值了,因为已经循环到末尾了
for(let o of iterator){
console.log("yield=",o);// 返回yield定义的值,并执行yield上方的代码
}
生成器函数参数
function * gen (arg) {
console.log(arg);
let one = yield 111;// 将第一次next的返回值传递给下一次
console.log(one); // 使用上一次的返回值变量
let two = yield 222;
console.log(two);
let three = yield 333;
console.log(three);
}
// 执行获取迭代器对象
let iterator = gen('AAA');
console.log(iterator.next()); // AAA
// next 方法可以传入实参
console.log(iterator.next('BBB'));
console.log(iterator.next('CCC'));
console.log(iterator.next('DDD'));
案例
// 异步编程 文件操作 网络操作 (ajax, request) 数据库操作
// 1s 后控制台输出 111 2s后输出 222 3s后输出 333
function one() {
setTimeout(() => {
console.log(111);
iterator.next();
}, 1000);
}
function two() {
setTimeout(() => {
console.log(222);
iterator.next();
}, 2000);
}
function three() {
setTimeout(() => {
console.log(333);
iterator.next();
}, 3000);
}
function* gen() {
yield one();
yield two();
yield three();
}
// 调用生成器函数
let iterator = gen();
iterator.next();
1.13 Promise 对象(异步)
是异步编程的一种解决方案,Promise 是一个对象,从它可以获取异步操作的消息。
状态的特点
Promise 异步操作有三种状态:
pending(进行中)、fulfilled(已成功)和rejected(已失败)。- 除了异步操作的结果,任何其他操作都无法改变这个状态。
Promise 对象只有:从 pending 变为 fulfilled 和从 pending 变为 rejected 的状态改变。
状态的缺点
- 无法取消 Promise ,一旦新建它就会立即执行,无法中途取消。
- 如果不设置回调函数,Promise 内部抛出的错误,不会反应到外部。
- 当处于 pending 状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
基本使用
// 实例化 Promise 对象
// 传入的方法有两个参数,参数1成功需要调用的方法。参数2失败需要调用的方法。调用一个后才会执行then方法
const p = new Promise(function (resolve, reject) {
setTimeout(() => {
let data = "成功";
// 成功调用resolve方法
resolve(data);
let err = "失败";
// 失败调用reject方法
reject(err);
}, 1000);
});
// 调用 promise 对象的 then 方法
// then 方法接收两个函数作为参数,参数1:是 Promise 执行成功时的回调,参数2是 Promise 执行失败时的回调,两个函数只会有一个被调用。
p.then(
function (value) {
console.log(value); // 成功
},
function (error) {
console.error(error); // 失败
}
);
// 可重复添加回调函数
const c = new Promise(function (resolve, reject) {
resolve(1);
}).then(function (value) { // 第一个then // 1
console.log(value);
return value * 2;
}).then(function (value) { // 第二个then // 2
console.log(value);
}).then(function (value) { // 第三个then // undefined
console.log(value);
return Promise.resolve('resolve');
}).then(function (value) { // 第四个then // resolve
console.log(value);
return Promise.reject('reject');
}).then(function (value) { // 第五个then //reject:reject
console.log('resolve:' + value);
}, function (err) {
console.log('reject:' + err);
});
Promise对象catch方法
const a = new Promise((resolve, reject) => {
setTimeout(() => {
// 设置 P 对象的状态为失败,并设置失败的值
reject("出错啦!");
}, 1000);
});
// p.then(value=> {
// console.log(value);
// }, reason=>{
// console.log(reason);
// });
a.catch((reason) => {
console.warn(reason); // 出错啦!
});
1.14 Map 与 Set
1.14.1 Map集合
键值对的存储方式,现了iterator 接口,所以可以使用[扩展运算符]和[for...of...] 进行遍历。
属性和方法
| 属性/方法 | 描述 |
|---|---|
| map.size | 返回map成员数 |
| map.get(key) | 返回对象的value |
| map.set(key,value) | 在第一部分初始化map时已经详细讲过了。添加一对值到map里。如果key已经存在,会覆盖以前值。 |
| map.has(key) | 返回一个布尔值,表明该key是否存在于map中 |
| map.delete(key) | 删除map中的一个成员(返回一个布尔值,表明是否删除成功) |
| map.clear() | 清除map中所有成员 |
| map.keys() | 返回键的遍历器 |
| map.values() | 返回值的遍历器 |
| map.entries() | 返回所有成员的遍历器 |
| map.forEach(function(value, key) {...}) | 遍历Map的所有成员 |
示例
// 声明 Map
let m = new Map();
// 添加元素
m.set("name", "成都大运会");
// console.log(m); // Map(1) {'name' => '成都大运会'}
// 也可以将方法存进去
m.set("change", function () {
console.log("我可以改变世界!!");
});
let key = {
school: "西南石油大学",
};
m.set(key, ["北京", "上海", "广州", "深圳"]);
// 遍历
for (let v of m) {
console.log(v);
}
1.14.2 Set集合
Set(集合)类似于数组,数据无法存入相同值,自带去重,实现了 iterator 接口,可以使用[扩展运算符]和[for...of...] 进行遍历
属性和方法
| 属性/方法 | 描述 |
|---|---|
| set.size | 返回set成员数 |
| set.add(value) | 添加一个成员到set中 |
| set.delete(value) | 删除set中的一个成员,返回一个布尔值,表明是否删除成功 |
| set.has(value) | 返回一个布尔值,表明该value是否存在于set中 |
| set.clear() | 清除set中所有成员 |
| set.forEach(function(value, index, set) {...}) | 遍历Set的所有成员 |
示例
// 声明一个 set
let s = new Set();
console.log(s); // Set(0) {size: 0}
let s2 = new Set(["昨天", "今天", "明天", "未来", "今天"]);
console.log(s2); // Set(4) {'昨天', '今天', '明天', '未来'}
// 元素的个数
console.log(s2.size);
// 添加新的元素
s2.add("过去");
console.log(s2); // Set(5) {'昨天', '今天', '明天', '未来', '过去'}
// 删除元素
s2.delete("昨天");
console.log(s2); // Set(4) {'今天', '明天', '未来', '过去'}
// 清空
s2.clear();
console.log(s2); // Set(0) {size: 0}
// 数组去重
let arr = [1, 2, 3, 4, 5, 4, 3, 2, 1];
let result = [...new Set(arr)];
console.log(result); // [1, 2, 3, 4, 5]
// 交集
// 集合论中,设A,B是两个集合,由所有属于集合A且属于集合B的元素所组成的集合,叫做集合A与集合B的交集(intersection)
let a = [1, 2, 3, 4, 5];
let b = [4, 5, 6, 7, 8];
let c = [...new Set(a)].filter(item=>new Set(b).has(item));
console.log(c); // [4, 5]
// 并集
let j1 = [4, 5, 6, 5, 6];
let j2 = [1, 2, 3, 4, 5, 4, 3, 2, 1];
let union = [...new Set([...j1, ...j2])];
console.log(union); // [1, 2, 3, 4, 5, 6]
// 差集
let c1 = [1, 2, 3, 4, 5, 4, 3, 2, 1];
let c2 = [4, 5, 6, 5, 6];
let diff = [...new Set(c1)].filter(item=>!(new Set(c2).has(item)));
console.log(diff); // [1, 2, 3]
1.15 class类
class (类)作为对象的模板被引入,可以通过 class 关键字定义类。class 的本质是 function。
特性
- class声明类
- constructor 定义构造函数初始化
- extends 继承父类
- super 调用父级构造方法
- static 定义静态方法和属性
- 父类方法可以重写
基本使用
// ES5
function Huawei(bank, price) {
this.bank = bank;
this.price = price;
}
// 在原型上添加方法
Huawei.prototype.call = function () {
console.log(this.price + "我可以打电话哦!");
};
let hW = new Huawei("3999", "华为荣耀");
hW.call();
console.log(hW);
// ES6
class XiaoMi {
// 静态属性
static name = '手机';
static change() {
console.log('我可以改变世界');
}
// 构造函数
constructor(bank, price) {
this.bank = bank;
this.price = price;
}
// 方法必须使用该语法,不能使用 ES5 的对象完整形式
call() {
console.log(this.price + "我为发烧而生");
}
}
let xM = new XiaoMi("699", "红米");
xM.call();
console.log(xM.name); // undefined,静态变量用实例化对象无法获取
console.log(XiaoMi.name); // 手机
类继承
通过extends的关键字进行父类继承,super关键字可以调用父类方法。
class Phone {
// 构造方法
constructor(brand, price) {
this.brand = brand;
this.price = price;
}
call() {
console.log("我可以打电话!");
}
}
class SmartPhone extends Phone {
// 构造方法
constructor(brand, price, color, size) {
// super可以调用父类,super()则是调用父类的构造方法
super(brand, price); // Phone.call(this, brand, price);
this.color = color;
this.size = size;
}
photo() {
console.log("我能拍照!");
}
playGame() {
console.log("我能玩游戏!");
}
}
let xiaoMi = new SmartPhone("小米", 699, "黑色", "5.5inch");
console.log(xiaoMi);
xiaoMi.call();// 我可以打电话!
xiaoMi.photo();// 我能拍照!
xiaoMi.playGame();// 我能玩游戏!
get和set方法
- getter 与 setter 必须同级出现
- 可自定义get和set方法,这样当被赋值或者是被读取值就会执行get或set方法
class Phone {
get price() {
console.log('价格属性被获取了');
return 'iloveyou';
}
set price(newVal) {
console.log('价格属性被修改了');
}
}
// 实例化对象
let s = new Phone();
console.log(s.price);// 打印,价格属性被获取了,返回的值iloveyou
s.price = 'free';// 打印,价格属性被修改了
1.16 数值扩展
-
Number.EPSILON 是 JavaScript 表示的最小精度
EPSILON 属性的值接近于 2.2204460492503130808472633361816E-16
function equal(a, b) { if (Math.abs(a - b) < Number.EPSILON) { return true; } else { return false; } } console.log(0.1 + 0.2); // 0.30000000000000004 console.log(0.1 + 0.2 === 0.3); // false console.log(equal(0.1 + 0.2, 0.3)); // true -
二进制和八进制
let b = 0b1010; console.log(b); // 10 let o = 0o777; console.log(o); // 511 let d = 100; console.log(d); // 100 let x = 0xff; console.log(x); // 255 -
Number.isNaN 检测一个数值是否为 NaN
console.log(Number.isNaN(123)); // false -
Number.parseInt Number.parseFloat字符串转整数
console.log(Number.parseInt("511111fuck")); // 511111 console.log(Number.parseFloat("3.1415926疯狂")); // 3.1415926 -
Number.isInteger() 判断一个数是否为整数
console.log(Number.isInteger(5)); // true console.log(Number.isInteger(2.5)); // false -
Math.trunc 将数字的小数部分抹掉
console.log(Math.trunc(3.5)); // 3 -
Math.sign 判断一个数到底为正数 负数 还是零
console.log(Math.sign(100)); // 1 console.log(Math.sign(0)); // 0 console.log(Math.sign(-20000)); // -1
1.17 对象方法扩展
// 1. Object.is 判断两个值是否完全相等
console.log(Object.is(120, 120)); // true
console.log(Object.is(NaN, NaN)); // true
console.log(NaN === NaN); // false
// 2. Object.assign 对象的合并
const config1 = {
host: 'localhost',
port: 3306,
name: 'root',
pass: 'root',
test: 'test'
};
const config2 = {
host: 'http://codeslive.top',
port: '33060',
name: 'xiaokang',
pass: 'iloveyou',
test2: 'test2'
}
console.log(Object.assign(config1, config2));
// 3. Object.setPrototypeOf 设置原型对象 Object.getPrototypeof
const school = {
name: '小康'
}
const cities = {
xiaoqu: ['beijing', 'shanghai', 'shenzhen']
}
Object.setPrototypeOf(school, cities);
console.log(Object.getPrototypeOf(school));
console.log(school);
1.18 模块化
模块化是指将一个大的程序文件,拆分成许多小的文件,然后将小文件组合起来。
模块化的优势有以下几点:
- 防止命名冲突
- 代码复用
- 高维护性
ES6之前的模块化规范有:
- CommonJS => NodeJS、Browserify
- AMD => requireJS
- CMD => seaJS
ES6 的模块化分为导出(export) @与导入(import)两个模块。
- export 命令用于规定模块的对外接口
- import 命令用于输入其他模块提供的功能,单例模式:多次重复执行同一句 import 语句,那么只会执行一次,而不会执行多次。import 同一模块,声明不同接口引用,会声明对应变量,但只执行一次 import 。
基础使用
// m1.js文件
// 分别暴露
export let school = "西南石油大学";
export function study() {
console.log("我可以学习到新的技能!!")
}
// m2.js文件
// 默认暴露
export default {
school: "西南石油大学",
change: function () {
console.log("我可以改变自己!");
}
}
/*-----export [test2.js]-----*/
let myName = "Jerry";
export { myName }
/*-----export [test.js]-----*/
let myName = "Tom";
export { myName as exportName }
// 引入 m1.js 模块内容
import * as m1 from "./m1.js";
import * as m2 from "./m2.js";
// 调用m1文件的方法
m1.study();
// 调用m2文件的默认暴露方法
m2.default.study();
// 引用赋值
// import { default as m3 } from "./src/js/m3.js";
// console.log(m3);
// 结构赋值形式
// import { school, study } from "./m1.js";
// console.log(school);
// study();
// 使用as 定义别名引用
// import { school as xueXiao, study as learn } from "./m1.js";
// console.log(xueXiao);
// learn();// 调用的是m1文件的study方法
// 简便形式 针对默认暴露
// import ezm from "./src/js/m1.js";
// ezm.study();
2. JS 2016(ES7)
2.1 判断数组是否包含特定元素
Includes 方法用来检测数组中是否包含某个元素,返回布尔类型值
const mingZhu = ["西游记", "红楼梦", "三国演义", "水浒传"];
console.log(mingZhu.includes("西游记")); // true
console.log(mingZhu.includes("石头记")); // false
const numbers = [1, 2, 3, 4, 5];
console.log(numbers.includes(3)); // true
console.log(numbers.includes(6)); // false
console.log(numbers.includes(1, 2)); // false,从索引 3 开始查找
2.2 指数操作符
在ES7中引入指数运算符[**],用来实现幂运算,功能与Math.pow 结果相同
2.2.1 语法
base ** exponent
// base: 底数,即要进行乘方运算的数值。
// exponent: 指数,表示要将底数乘方的次数。
2.2.2 示例
console.log(2 ** 10); // 1024
console.log(Math.pow(2, 10)); // 1024
3. JS 2017(ES8)
3.1 async函数
async函数是异步的一种方案,可以让异步的操作同步执行。
- async函数的返回值为 promise 对象
- promise对象的结果由 async函数执行的返回值决定
// async 函数
async function fn() {
// 返回一个字符串
// return "好炎热";
// 返回的结果不是一个 Promise 类型的对象,返回的结果就是成功 Promise 对象
// return;
// 抛出错误,返回的结果是一个失败的 Promise
// throw new Error("出错啦!");
// 返回的结果如果是一个 Promise 对象
return new Promise((resolve, reject) => {
// resolve("读取数据成功!");
reject("读取数据失败!");
});
}
const result = fn();
// console.log(result);
// 调用 then 方法
result.then(value => {
console.log(value);
}, reason => {
console.warn(reason); // 读取数据失败!
}
);
3.2 await表达式
- await 必须写在async函数中
- await 右侧的表达式一般为 promise 对象
- await 返回的是 promise 成功的值
- await 的 promise 失败了,就会抛出异常,需要通过 try...catch 捕获处理*
// 创建 Promise 对象
let p = new Promise((resolve, reject) => {
// resolve("请求成功!");
reject("请求失败!");
});
// await 要放在 async 函数中.
async function main() {
try {
let result = await p;
console.log(result); // 请求失败!
} catch (e) {
console.error(e);
}
}
// 调用函数
main();
3.3 async与await结合发送AJAX请求
异步按照顺序执行
// 发送 AJAX 请求,返回的结果是 Promise 对象
function sendAJAX(url) {
return new Promise((resolve, reject) => {
// 1、创建对象
const x = new XMLHttpRequest();
// 2、初始化
x.open("GET", url);
// 3、发送
x.send();
// 4、事件绑定
x.onreadystatechange = function () {
if (x.readyState === 4) {
if (x.status >= 200 && x.status < 300) {
// 请求成功
resolve(x.response);
} else {
// 请求失败
reject(x.status);
}
}
};
});
}
// Promise then 方法的测试
// sendAJAX("https://api.apiopen.top/api/getDynamic").then(value=>{
// console.log(value);
// },reason=>{
// });
// async 与 await 测试
async function main() {
// 发送 AJAX 请求
let result = await sendAJAX("https://api.apiopen.top/api/getDynamic");
// console.log(result);
let tianQi = await sendAJAX(
"https://www.tianqiapi.com/api/?version=v1&city=%E5%8C%97%E4%BA%AC&appid=23941491&appsecret=TXoD5e8P"
);
console.log(tianQi);
}
main();
3.4 对象方法扩展
- Obiect.values()方法返回一个给定对象的所有可枚举属性值的数组
- Obiect.entries()方法返回一个给定对象自身可遍历属性 [key,value] 的数组
// 声明对象
const school = {
name: 'xiaokang',
cities: ['beijing', 'shanghai', 'shenzhen'],
xueke: ['前端', 'Java', '大数据', '运维']
};
// 获取对象所有的键
console.log(Object.keys(school));
// 获取对象所有的值
console.log(Object.values(school));
const obj = { a: 1, b: 2 };
const values = Object.values(obj);
console.log(values); // 输出:[1, 2]
// entries
const obj = { a: 1, b: 2 };
const entries = Object.entries(obj);
console.log(entries); // 输出:[['a', 1], ['b', 2]]
console.log(Object.entries(school));
// entries,用来创建map
const m = new Map(Object.entries(school));
console.log(m.get('cities'));
// 对象属性描述对象
// 对象属性的描述对象,即获取name的值
// 主要用于拷贝时,拷贝一份与原来对象相同属性的对象
console.log(Object.getOwnPropertyDescriptors(school));
const obj = { a: 1, b: 2 };
const descriptors = Object.getOwnPropertyDescriptors(obj);
console.log(descriptors);
// 输出:
// {
// a: { value: 1, writable: true, enumerable: true, configurable: true },
// b: { value: 2, writable: true, enumerable: true, configurable: true }
// }
const obj = Object.create(null,{
name:{
value:'Java',
//属性特性
writable:true, // 是否可写
configurable:true, //是否可配置
enumerable:true, //是否可枚举
}
})
4. JS 2018(ES9)
4.1 扩展运算符与rest参数
Rest 参数与 spread 扩展运算符在 ES6 中已经引入,不过 ES6 中只针对于数组,在 ES9 中为对象提供了像数组一样的 rest 参数和扩展运算符。
// rest 参数
function connect({ host, port, ...user }) {
console.log(host); // 127.0.0.1
console.log(port); // 3306
console.log(user); // {username: 'root', password: 'root', type: 'master'}
}
connect({
host: "127.0.0.1",
port: 3306,
username: "root",
password: "root",
type: "master",
});
// 对象合并
const skillOne = { q: '天音波' }
const skillTwo = {w: '金钟罩'}
const skillThree = {e: '天雷破'}
const skillFour = {r: '猛龙摆尾'}
const mangseng = { ...skillOne, skillTwo, skillThree, skillFour };
console.log(mangseng);// {q: '天音波',skillTwo: { w: '金钟罩' },skillThree: { e: '天雷破' },skillFour: { r: '猛龙摆尾' }}
4.2 正则扩展
4.2.1 命名捕获分组
// 声明一个字符串
// let str = `<a href="https://codeslive.top">小康</a>`;
// // 提前 url 与 标签文本
// const reg = /<a href="(.*)">(.*)</a>/;
// // 执行
// const result = reg.exec(str);
// console.log(result);
// console.log(result[1]); // https://codeslive.top
// console.log(result[2]); // 小康
let str = `<a href="https://codeslive.top">小康</a>`;
// 分组命名
const reg = /<a href="(?<url>.*)">(?<text>.*)</a>/;
const result = reg.exec(str);
console.log(result.groups.url);// https://codeslive.top
console.log(result.groups.text);// 小康
4.2.2 正则表达式反向断言
// 声明字符串
let str = 'JS5211314你知道么555啦啦啦';
// 1.正向断言
const reg1 = /\d+(?=啦)/;// 匹配在啦之前的多个数字,不包含啦
const result1 = reg1.exec(str);
console.log(result1);
// 2.反向断言
const reg2 = /(?<=么)\d+/;// 匹配在么之后的多个数字,不包含么
const result2 = reg2.exec(str);
console.log(result2);
4.3 dotAll模式
//dot . 元字符 除换行符以外的任意单个字符
let str = `
<ul>
<li>
<a>肖生克的救赎</a>
<p>上映日期: 1994-09-10</p>
</li>
<li>
<a>阿甘正传</a>
<p>上映日期: 1994-07-06</p>
</li>
</ul>`;
//声明正则
// const reg = /<li>\s+<a>(.*?)</a>\s+<p>(.*?)</p>/;
const reg = /<li>.*?<a>(.*?)</a>.*?<p>(.*?)</p>/gs;
//执行匹配
// const result = reg.exec(str);
let result;
let data = [];
while (result = reg.exec(str)) {
data.push({ title: result[1], time: result[2] });
}
//输出结果
console.log(data);
/*
[
{ title: '肖生克的救赎', time: '上映日期: 1994-09-10' },
{ title: '阿甘正传', time: '上映日期: 1994-07-06' }
]
*/
5. JS 2019(ES10)
5.1 对象扩展方法Object.fromEntries
用来创建一个对象,参数是一个数组或者是map对象。
将二维数组转为对象,而ES8 中 Object.entries 方法是把对象转化为数组
// 二维数组转换成对象
const result = Object.fromEntries([
["name", "西南石油大学"],
["zhuanYe", "计算机科学与技术, 软件工程, 人工智能"],
]);
console.log(result); // {name: '西南石油大学', zhuanYe: '计算机科学与技术, 软件工程, 人工智能'}
// Map
const m = new Map();
m.set("name", "电子科大");
m.set("zhuanYe", "大数据");
const result1 = Object.fromEntries(m);
console.log(result1); // {name: '电子科大', zhuanYe: '大数据'}
// Object.entries ES8 对象转二维数组
const arr = Object.entries({
name: "红石榴21",
});
console.log(arr); // [["name","红石榴21"]]
5.2 字符串方法扩展-trimStart-trimEnd
trimStart : 清除字符串左侧的字符
trimEnd: 清除字符串右侧的字符
let str = ' asd '
console.log(str) //asd
console.log(str.trimStart()) //asd 清空头空格
console.log(str.trimEnd()) // asd 清空尾空格
5.3 数组方法扩展-flat与flatMap
flat: 将多维数组转化为低维数组
flatMap: 将map对象进行降维
const arr = [1, 2, 3, [4, 5, 6, [7, 8, 9]]]
//参数为深度,是一个数字,2表示2层
console.log(arr.flat(2)) //[1,2,3,4,5,6,7,8,9]
const arr3 = [1, 2, 3, 4];
const result = arr3.flatMap((item) => [item * 10]);
console.log(result); // [10, 20, 30, 40]
5.4 Symbol.prototype.description
用来获取Symbol的字符串描述
// 创建Symbol
let s = Symbol("莫得感情的鲨手");
console.log(s.description); // 莫得感情的鲨手
6. JS 2020(ES11)
6.1 私有属性
私有属性外部不可读,属性名前加#符号为私有属性
class Person {
// 公有属性
name;
// 私有属性
#age;
#weight;
// 构造方法
constructor(name, age, weight) {
this.name = name;
this.#age = age;
this.#weight = weight;
}
intro() {
console.log(this.name); // 尕车
console.log(this.#age); // 18
console.log(this.#weight); // 45kg
}
}
// 实例化
const girl = new Person("尕车", 18, "45kg");
console.log(girl.name);
// console.log(girl.#age); // error
// console.log(girl.#weight); // error
girl.intro();
6.2 Promise.allSettled方法
allSettled 和all 方法,主要用于批量处理异步任务。
//声明两个promise对象
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('商品数据-1')
}, 1000)
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('出错了!')
}, 1000)
})
//调用allsettled方法:返回的结果始终是一个成功的,并且异步任务的结果和状态都存在
const res = Promise.allSettled([p1, p2]);
console.log(res)
// Promise {<pending>}
// __proto__: Promise
// [[PromiseState]]: "resolve"
// [[PromiseResult]]: Array(2)
// 0: {status: 'fulfilled', value: '商品数据-1'}
// 1: {status: 'rejected', reason: '出错了!'}
//=========================================================
//调用all方法:返回的结果是按照p1、p2的状态来的,
//如果都成功,则成功,
//如果一个失败,则失败,失败的结果是失败的Promise的结果
const result = Promise.all([p1, p2])
console.log(result)
6.3 String.prototype.matchAll方法
返回一个包含所有匹配正则表达式的结果及分组捕获组的迭代器
let str = `<ul>
<li>
<a>肖生克的救赎</a>
<p>上映日期: 1994-09-10</p>
</li>
<li>
<a>阿甘正传</a>
<p>上映日期: 1994-07-06</p>
</li>
</ul>`;
//声明正则
const reg = /<li>.*?<a>(.*?)</a>.*?<p>(.*?)</p>/sg
//调用方法
const result = str.matchAll(reg); //返回的是一个可迭代对象
//展开可迭代对象 方法1
// for(let v of result){
// console.log(v);
// }
//展开可迭代对象 方法2
const arr = [...result];
console.log(arr);
6.4 可选链操作符 ?.
//相当于一个判断符,如果前面的有,就进入下一层级
function main(config) {
const dbHost = config?.db?.host //等价于 config && config.db && config.db.host
console.log(dbHost) //192.168.1.100
}
main({
db: {
host: '192.168.1.100',
username: 'root'
},
cache: {
host: '192.168.1.200',
username: 'admin'
}
})
6.5 动态import
当用到对应的文件时在进行加载
// hello.js
export function hello(){
alert('Hello');
}
// app.js
// import * as m1 from "./hello.js"; //静态传入
const btn = document.getElementById('btn');
btn.onclick = function(){
//使用之前并未引入,动态引入,返回的其实是一个Promise对象
// 使用的时候再进行传入,import函数,参数是路径
import('./hello.js').then(module => {
module.hello();
});
}
6.6 BigInt类型
// 大整形
// let n = 521n;
// console.log(n, typeof n); // 521n 'bigint'
// 函数
// let n = 123;
// console.log(BigInt(n)); // 123n
// console.log(BigInt(1.2)); // error
// 大数值运算
let max = Number.MAX_SAFE_INTEGER;
console.log(max); // 9007199254740991
console.log(max + 1); // 9007199254740992
console.log(max + 2); // 9007199254740992 当数字上线加多少值也不会变
console.log(BigInt(max)); // 9007199254740991n
console.log(BigInt(max) + BigInt(1)); // 9007199254740992n
console.log(BigInt(max) + BigInt(2)); // 9007199254740993n
6.7 绝对全局对象globalThis
globalThis是一个全局对象,它提供了全局可访问性,可以在任何地方访问。这意味着,不论在哪个环境中运行JavaScript(浏览器、Node.js、Web Workers等),globalThis始终指向这个环境的全局对象。
globalThis是为了解决不同环境中全局对象名称不统一的问题。在浏览器中,全局对象是window;在Node.js中,全局对象是global。而globalThis则提供了一个统一的方式,可以在任何JavaScript环境中访问全局对象。
console.log(globalThis) //window //适用于复杂环境下直接操作window
7. JS 2021(ES12)
node版本>=15.0.0
7.1 逻辑运算符和赋值表达式
&&=:逻辑与赋值表达式,将右侧的值赋给左侧的变量,但仅当左侧的变量在布尔上下文中为真时。||=:逻辑或赋值表达式,将右侧的值赋给左侧的变量,但仅当左侧的变量在布尔上下文中为假时。??=:空值合并赋值表达式,将右侧的值赋给左侧的变量,但仅当左侧的变量为 null 或 undefined 时。
let x = 5;
let y = 10;
// 逻辑与赋值表达式
x &&= y;
console.log(x); // Output: 10 (因为 x 为真,所以将 y 赋给 x)
let a = 0;
let b = 20;
// 逻辑或赋值表达式
a ||= b;
console.log(a); // Output: 20 (因为 a 为假,所以将 b 赋给 a)
let foo = null;
let bar = 'Hello';
// 空值合并赋值表达式
foo ??= bar;
console.log(foo); // Output: "Hello" (因为 foo 为 null,所以将 bar 赋给 foo)
7.2 String.prototype.replaceAll()替换字符串
返回一个全新的字符串,所有符合匹配规则的字符都将被替换掉
const str = '11-22-33-44';
const newStr = str.replaceAll('-', '+');
console.log(newStr); // 11+22+33+44
7.3 数字分隔符
数字分隔符是一种增强的数值表示法,可以在数字中使用下划线 _ 进行分隔,以提高数字的可读性。
const billion = 1_000_000_000;
const pi = 3.14_15_92_65;
console.log(billion); // Output: 1000000000
console.log(pi); // Output: 3.14159265