一、let和const
1.1 let
1.1.1 声明变量
let a;
let b, c, d;
let e = 1;
let f = 10, g = 'hello', h = [];
1.1.2 变量不能重复声明
let star = "罗志祥";
let star = "小猪";
报错
var可以重复声明变量
var star = "罗志祥";
var star = "小猪";
1.1.3 块级作用域
-
全局
-
函数
-
eval(严格模式)
{
let girl = "周扬青";
}
console.log(girl);
报错
var 没有块级作用域
{
var girl = "周扬青";
}
console.log(girl);
1.1.4 不存在变量提升
console.log(song);
let song = "两只老虎";
报错
var 存在变量提升
console.log(song);
var song = "两只老虎";
// 相当于
// var song;
// console.log(song);
1.1.5 不影响作用域链
{
let school = "尚硅谷";
function fn() {
console.log(school);
}
fn();
}
1.2 const
1.2.1 定义常量(常量:值不能修改)
const PI = 3.14;
console.log(PI);
1.2.2 必须赋初始值
const PI;
报错
1.2.3 一般常量使用大写(潜规则)
const PI = 3.14;
// 小写也不会报错
const pi = 3.14;
1.2.4 常量的值不能修改
const PI = 3.14;
PI = 3.1415926;
报错
1.2.5 块级作用域
{
const PI = 3.14;
}
console.log(PI);
报错
1.2.6 可对数组和对象的元素修改
const arr = ['a', 'b', 'c'];
arr.push("d");
console.log(arr); //arr指向的地址没发生改变
const obj = {
name: "小明",
age: 18
}
obj.name = "小红";
console.log(obj);
二、变量的结构赋值
ES6 允许按照一定模式从数组和对象中提取值,对变量进行赋值,这被称为解构赋值。
2.1 数组的解构
const F4 = ["小沈阳", "刘能", "赵四", "宋小宝"];
let [xiao, liu, zhao, song] = F4;
console.log(xiao);
console.log(liu);
console.log(zhao);
console.log(song);
2.2 对象的解构
const zhao = {
name: "赵本山",
age: 60,
xiaopin: function () {
console.log("演小品");
}
}
let { name, age, xiaopin } = zhao;
console.log(name);
console.log(age);
console.log(xiaopin);
xiaopin();
按需求解构
let { xiaopin } = zhao;
xiaopin();
三、模板字符串
ES6 引入新的声明字符串的方式 ````;ES5:单引号(’ ')、双引号(" ")。
3.1 声明
let str = `我是字符串`;
console.log(str, typeof str);
3.2 特性
3.2.1 内容中可以直接出现换行符
let str = `<ul>
<li>javascript</li>
<li>java</li>
<li>go</li>
</ul>`;
不会报错
单引号或双引号换行要使用+拼接,否则换行就会报错
let str = '<ul>
<li>javascript</li>
<li>java</li>
<li>go</li>
</ul>';
报错
let str = '<ul>' +
'<li>javascript</li>' +
'<li>java</li>' +
'<li>go</li>' +
'</ul>';
+ 连接不会报错
3.2.2 变量拼接
let star = "刘亦菲";
let love = `${star}是明星`;
console.log(love);
四、对象的简化写法
ES6 允许在大括号里边,直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁。
let name = "旺财";
let food = function () {
console.log("我喜欢吃骨头");
}
const dog = {
// 之前的写法
// name: name,
// food: food,
// run: function () {
// console.log("我跑得快");
// }
// ES6 的写法
name,
food,
run() {
console.log("我跑得快");
}
}
console.log(dog);
五、箭头函数
ES6 允许使用 箭头 (=>) 定义函数。
// 普通函数
// let fn = function (a, b) {
// return a + b;
// }
// let result = fn(10, 20);
// console.log(result);
// 箭头函数
let fn = (a, b) => {
return a + b;
}
let result = fn(10, 20);
console.log(result);
5.1 this 静态特点
this 是静态的,this 始终指向函数声明时所在作用域下的 this 的值。
function getName1() {
console.log(this.name);
}
let getName2 = () => {
console.log(this.name);
}
// 设置 window 对象的 name 属性
window.name = "Hello";
// 直接调用
getName1();
getName2();
function getName1() {
console.log(this.name);
}
let getName2 = () => {
console.log(this.name);
}
// 设置 window 对象的 name 属性
window.name = "Hello";
const obj = {
name: "你好"
}
// call 方法调用
getName1.call(obj);
getName2.call(obj);
5.2 不能作为构造实例化对象
let Person = (name, age) => {
this.name = name;
this.age = age;
}
let me = new Person("张三", 20);
console.log(me);
报错
5.3 不能使用 arguments 变量
let fn = () => {
console.log(arguments);
}
fn(1, 2, 3);
5.4 箭头函数的简写
5.4.1 省略小括号,当形参有且只有一个时
let add = n => {
return n + n;
}
console.log(add(2));
5.4.2 省略花括号,当代码体只有一条语句时,此时return也必须省略
let pow = x => x * x;
console.log(pow(9));
5.5 应用场景
箭头函数适合与 this 无关的回调。定时器、数组的方法回调等。
箭头函数不适合与 this 有关的回调。事件回调,对象的方法等。
六、函数参数的默认值
ES6 允许给函数参数赋初始值。
形参初始值,具有默认值的参数,一般位置要靠后
function fun(a, b, c) {
return a + b + c;
}
let result = fun(1, 2);
console.log(result);lt);
function fun(a, b, c = 5) {
return a + b + c;
}
let result = fun(1, 2);
console.log(result);
与解构赋值结合使用
function connect({ host = "127.0.0.1", port, username, password }) {
console.log(host);
console.log(port);
console.log(username);
console.log(password);
}
connect({
host: "localhost",
port: 8080,
username: "root",
password: "root"
})
七、rest 参数
ES6 引入rest 参数,用于获取函数的实参,用来代替 arguments。
ES5 获取实参的方式
// ES5 获取实参的方式
function date() {
console.log(arguments);
}
date("hello", "world", "!"); //获取到的是对象
ES6 获取实参的方式
function date(...args) {
console.log(args);
}
date("hello", "world", "!"); //获取到的是数组,可以使用数组的API方法,如filter,some,every,map等
rest 参数必须要放到参数最后
function fun(a, b, ...args) {
console.log(a);
console.log(b);
console.log(...args);
}
七、扩展运算符
...
扩展运算符能将数组转换为逗号分隔的参数序列。
7.1 使用
const tfboys = ["易烊千玺", "王源", "王俊凯"];
function chunwan() {
console.log(arguments);
}
chunwan(tfboys);
一个参数
chunwan(...tfboys);
三个参数
7.2 应用
7.2.1 数组的合并
const arr1 = ['a', 'b', 'c'];
const arr2 = ['d', 'e', 'f'];
// ES5 的写法
// const arr = arr1.concat(arr2);
// console.log(arr);
// ES6
const arr = [...arr1, ...arr2];
console.log(arr);
7.2.2 数组的克隆
const arr1 = ['a', 'b', 'c'];
const arr2 = [...arr1];
console.log(arr2);
7.2.3 将伪数组转为真正的数组
const divs = document.querySelectorAll("div");
console.log(divs); //obj
const divArr = [...divs];
console.log(divArr); //转化为数组
八、Symbol
8.1 Symbol基本使用
ES6 引入了一种新的原始数据类型 Symbol,表示独一无二的值。它是 JavaScript 语言的第七种数据类型,是一种类似于字符串的数据类型。
Symbol 特点
-
Sybmol 的值是唯一的,用来解决命名冲突的问题
-
Symbol 的值不能与其他数据进行运算
-
Symbol 定义的对象属性不能使用 for…in 循环遍历,但是可以使用 Reflect.ownKeys来获取对象的所有键名
// 创建 Symbol
let s1 = Symbol();
console.log(s1, typeof s1);
let s2 = Symbol("张三");
let s3 = Symbol("张三");
console.log(s2);
console.log(s2 === s3); //false
let s4 = Symbol.for("李四");
let s5 = Symbol.for("李四");
console.log(s4 === s5); //true
// 不能与其他数据进行运算(以下是错误写法)
// let result1 = s + 100;
// let result2 = s > 100;
// let result3 = s + '100';
// let result4 = s + s;
js的数据类型(7种)
USONB:you are so niubility(你很牛逼)
U:undefined
S:string symbol
O:object
N:null number
B:boolean
8.2 对象添加 Symbol 类型的属性
let game = {
name: "俄罗斯方块",
up: function () {
console.log("向上");
},
down: function () {
console.log("向下");
}
}
// 声明一个对象
let methods = {
up: Symbol(),
down: Symbol()
};
game[methods.up] = function () {
console.log("我可以向上");
};
game[methods.down] = function () {
console.log("我可以向下");
}
console.log(game);
let youxi = {
name: "王者荣耀",
[Symbol('ptgj')]: function () {
console.log("普通攻击");
},
[Symbol('fdz')]: function () {
console.log("放大招");
}
}
console.log(youxi);
8.3 Symbol 的内置属性
除了定义自己使用的 Symbol 值以外,ES6 还提供了 11 个内置的 Symbol 值,指向语言内部使用的方法。
属性 | 说明 |
---|---|
Symbol.hasInstance | 当其他对象使用 instanceof 运算符,判断是否为该对象的实例时,会调用这个方法。 |
Symbol.isConcatSpreadable | 对象的 Symbol.isConcatSpreadable 属性等于的是一个布尔值,表示该对象用于 Array.prototype.concat()时,是否可以展开。 |
Symbol.unscopables | 该对象指定了使用 with 关键字时,哪些属性会被 with 环境排除。 |
Symbol.match | 当执行 str.match(myObject) 时,如果该属性存在,会调用它,返回改方法的返回值。 |
Symbol.replace | 当对象被 str.replace(myObject) 方法调用时,会返回改方法的返回值。 |
Symbol.search | 当改对象被 str.search(myObject) 方法调用时,会返回该方法的返回值。 |
Symbol.split | 当该对象被 str.split(myObject) 方法调用时,会返回改方法的返回值。 |
Symbol.iterator | 对象进行 for…of 循环时,会调用 Symbol.iterator 方法,返回该对象额默认遍历器。 |
Symbol.toPrimitive | 该对象被转为原始类型的值时,会调用这个方法,返回改对象对应的原始类型值。 |
Symbol.toStringTag | 在该对象上面调用 toString 方法时,返回该方法的返回值。 |
Symbol.species | 创建衍生对象时,会使用该属性。 |
九、迭代器
迭代器(iterator)是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 iterator 接口,就可以完成遍历操作。
(1)ES6 创造了一种新的遍历命令 for…of 循环,iterator 接口主要供 for…of 消费
(2)原生具备 iterator 接口的数据(可用 for…of 遍历)
-
Array
-
Arguments
-
Set
-
Map
-
String
-
TypedArray
-
NodeList
(3)工作原理
-
创建一个指针对象,指向当前数据结构的起始位置
-
第一次调用对象的 next 方法,指针自动指向数据结构的第一个成员
-
接下来不断调用 next 方法,指针往后移动,直到指向最后一个成员
-
每调用 next 方法返回一个包含 value 和 done 属性的对象
const arr = ['唐僧', '孙悟空', '猪八戒', '沙悟净'];
for (let v of arr) {
console.log(v);
}
console.log("=========");
for (let v in arr) {
console.log(v);
}
console.log(arr);
let iterator = arr[Symbol.iterator]();
// 调用对象的 next 方法
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
迭代器的应用
需要自定义遍历数据的时候,要想到迭代器。
const banji = {
name: "一班",
stus: [
"小明",
"小强",
"小花",
"小红"
],
[Symbol.iterator]() {
// 索引变量
let index = 0;
let _this = this;
return {
next: function () {
if (index < _this.stus.length) {
const result = { value: _this.stus[index], done: false };
// 下标自增
index++;
// 返回结果
return result;
} else {
return { value: undefined, done: true };
}
}
}
}
}
for (let v of banji) {
console.log(v);
}
十、生成器
生成器函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同。
10.1 生成器函数声明与调用
function* gen() {
console.log("hello generoter");
// yield 可理解为函数代码的分隔符
yield '一直没有耳朵';
yield '一只没有尾巴';
yield '真奇怪';
}
let iterator = gen();
console.log(iterator);
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
// 遍历
for (let v of gen()) {
console.log(v);
}
10.2 生成函数的参数传递
function* gen(arg) {
console.log(arg);
let one = yield 111;
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);
// next 方法可以传入实参
console.log(iterator.next("BBB"));
console.log(iterator.next("CCC"));
console.log(iterator.next("DDD"));
console.log(iterator.next("EEE"));
10.3 案例
function getUsers() {
setTimeout(() => {
let data = '用户数据';
iterator.next(data);
}, 1000)
}
function getOrders() {
setTimeout(() => {
let data = '订单数据';
iterator.next(data);
}, 1000)
}
function getGoods() {
setTimeout(() => {
let data = '商品数据';
iterator.next(data);
}, 1000)
}
function* gen() {
let users = yield getUsers();
console.log(users);
let orders = yield getOrders();
console.log(orders);
let goods = yield getGoods();
console.log(goods);
}
// 调用生成器函数
let iterator = gen();
iterator.next();
十一、Promise
Promise 是 ES6 引入的异步编程的新解决方案。语法上 Promise 是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果。
-
Promise 构造函数:Promise(excutor){}
-
Promise.prototype.then 方法
-
Promise.prototype.catch 方法
11.1 基本使用
const p = new Promise(function (resolve, reject) {
setTimeout(function () {
let data = '数据库中的用户数据'
resolve(data);
// let err = '数据读取失败';
// reject(err);
}, 1000)
});
// 调用 Promise 对象的 then 方法
p.then(function (value) {
console.log(value);
}, function (reason) {
console.error(reason);
})
const p = new Promise(function (resolve, reject) {
setTimeout(function () {
// let data = '数据库中的用户数据'
// resolve(data);
let err = '数据读取失败';
reject(err);
}, 1000)
});
// 调用 Promise 对象的 then 方法
p.then(function (value) {
console.log(value);
}, function (reason) {
console.error(reason);
})
11.2 封装读取文件
// 引入 fs 模块
const fs = require('fs');
// 调用方法读取文件
// fs.readFile('./resources/hello1.txt', (err, data) => {
// // 失败
// if (err) throw err;
// // 成功
// console.log(data.toString());
// });
// 使用 Promise 封装
const p = new Promise(function (resolve, reject) {
fs.readFile('./resources/hello2.md', (err, data) => {
// 失败
if (err) reject(err);
// 成功
resolve(data);
});
});
p.then(
function (value) {
console.log(value.toString());
},
function (reason) {
console.log('读取失败');
}
);
11.3 Promise 封装 AJAX 请求
// 接口地址:https://api.apiopen.top/api/sentences get
// // 1. 创建对象
// const xhr = new XMLHttpRequest();
// // 2. 初始化
// xhr.open("GET", "https://api.apiopen.top/api/sentences");
// // 3. 发送
// xhr.send();
// // 4. 绑定事件,处理响应结果
// xhr.onreadystatechange = function () {
// // 判断
// if (xhr.readyState === 4) {
// // 判断响应状态码 200-299
// if (xhr.status >= 200 && xhr.status <= 299) {
// // 表示成功
// console.log(xhr.response);
// } else {
// console.error(xhr.status);
// }
// }
// }
// 封装
const p = new Promise((resolve, reject) => {
// 1. 创建对象
const xhr = new XMLHttpRequest();
// 2. 初始化
xhr.open("GET", "https://api.apiopen.top/api/sentences");
// 3. 发送
xhr.send();
// 4. 绑定事件,处理响应结果
xhr.onreadystatechange = function () {
// 判断
if (xhr.readyState === 4) {
// 判断响应状态码 200-299
if (xhr.status >= 200 && xhr.status <= 299) {
// 表示成功
resolve(xhr.response);
} else {
reject(xhr.status);
}
}
}
})
// 指定回调
p.then(function (value) {
console.log(value);
}, function (reason) {
console.error(reason);
})
11.3 Promise.prototype…then 方法
const p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('用户数据');
// reject('出错啦!');
}, 1000)
})
// 调用 then 方法
// p.then(value => {
// console.log(value);
// }, reason => {
// console.warn(reason);
// })
// 调用 then 方法,then 方法的返回结果是 Promise 对象,对象状态由回调函数的执行结果决定
// 如果回调函数中返回的结果是 非 Promise 类型的属性 状态为成功
// const result = p.then(value => {
// // console.log(value);
// // 1. 非 Promise 类型的属性
// // return 'hello'; //[[PromiseResult]]: undefined
// // 2. 是 Promise 对象
// // return new Promise((resolve, reject) => {
// // resolve("ok");
// // });
// // 3. 抛出错误
// // throw new Error('出错啦');
// throw "出错啦";
// }, reason => {
// console.warn(reason);
// })
// 链式调用
p.then(value => {
}).then(value => {
}, reason => {
})
11.4 案例(链式调用封装多个异步的任务)
const fs = require('fs');
// fs.readFile('./resources/hello1.txt', (err, data1) => {
// fs.readFile('./resources/hello2.md', (err, data2) => {
// fs.readFile('./resources/hello3.txt', (err, data3) => {
// let result = data1 + '\r\n' + data2 + '\r\n' + data3;
// console.log(result);
// });
// });
// });
// 使用 Promise 实现
const p = new Promise((resolve, reject) => {
fs.readFile('./resources/hello1.txt', (err, data) => {
resolve(data);
});
});
p.then((value) => {
return new Promise((resolve, reject) => {
fs.readFile('./resources/hello2.md', (err, data) => {
resolve([value, data]);
});
});
})
.then((value, reason) => {
return new Promise((resolve, reject) => {
fs.readFile('./resources/hello3.txt', (err, data) => {
// 压入
value.push(data);
resolve(value);
});
});
})
.then((value) => {
console.log(value.join('\r\n'));
});
11.4catch
const p = new Promise((resolve, reject) => {
setTimeout(() => {
// 设置 p 对象的状态为失败,并设置失败的值
reject("出错啦")
}, 1000)
});
// p.then(function (value) { }, function (reason) {
// console.error(reason);
// })
p.catch(reason => {
console.warn(reason);
})
十二、集合与 API
12.1 Set
ES6 提供了新的数据结构
Set
(集合)。类似于数组,但成员的值都是唯一的,集合实现了iterator
接口,所以可以使用 扩展运算符 和for...of
进行遍历,集合的属性和方法:
-
size
返回集合的元素个数 -
add
增加一个新元素,返回当前集合 -
delete
删除元素,返回boolean
值 -
has
检测集合中是否包含某个元素,返回boolean
值
// 声明一个 set
let s = new Set();
console.log(s, typeof s);
let s = new Set(['西游记', '水浒传', '红楼梦', '三国', '西游记']);
// 自动去重
console.log(s);
// 元素个数
console.log(s.size);
// 添加元素
s.add("封神榜");
console.log(s);
// 删除
s.delete("水浒传");
console.log(s);
// 检测
console.log(s.has('水浒传'));
console.log(s.has("三国"));
// 清空
// s.clear();
// console.log(s);
for (let v of s) {
console.log(v);
}
12.2 Set案例
let arr1 = [1, 2, 3, 4, 5, 4, 2, 1];
// 1. 数组去重
// let result = [...new Set(arr1)];
// console.log(result);
// 2. 交集
let arr2 = [4, 5, 6, 4, 5];
// let result = [...new Set(arr1)].filter(item => {
// let s = new Set(arr2);
// if (s.has(item)) {
// return true;
// } else {
// return false;
// }
// });
// 简写
// let result = [...new Set(arr1)].filter(item => new Set(arr2).has(item));
// console.log(result);
// 3. 并集
// let union = [...new Set([...arr1, ...arr2])];
// console.log(union);
// 4. 差集
let diff = [...new Set(arr1)].filter(item => !(new Set(arr2).has(item)));
console.log(diff);
12.3 Map
ES6 提供了
Map
数据结构。它类似于对象,也是键值对的集合。但是”键“的范围不限于字符串,各种类型的值(包括对象)都可以当作键。Map
也实现了interator
接口,所以可以使用 扩展运算符 和for...of
进行遍历。Map的属性和方法:
-
size
返回Map
的元素个数 -
set
增加一个新元素,返回当前Map
-
get
返回键名对象的键值 -
has
检测Map
中是否包含某个元素,返回boolean
值 -
clear
清空集合,返回undefined
// 声明 Map
let m = new Map();
// console.log(m, typeof m);
// 添加元素
m.set('name', '张三');
m.set('change', function () {
console.log("改变一下");
});
let key = {
school: '清华',
};
m.set(key, ['北京', '上海', '深圳']);
console.log(m);
// size
console.log(m.size);
// 删除
m.delete('name');
console.log(m);
// 获取
console.log(m.get('change'));
console.log(m.get(key));
// 遍历
for (let v of m) {
console.log(v);
}
// 清空
m.clear();
console.log(m);
十二、class
ES6 提供了更接近传统语言的写法,引入了
Class
(类)这个概念,作为对象的模板。通过class
关键字,可以定义类。基本上,ES6的class
可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的class
写法只是让对象原型的写法更加清晰、更像面对对象编程的语法而已。
知识点
-
class
声明类 -
constructor
定义构造函数初始化 -
extends
继承类 -
super
调用父级的构造方法 -
static
定义静态方法和属性 -
父类方法可以重写
12.1 class介绍与体验
// ES5 构造函数实例化对象
// 手机
function Phone(brand, price) {
this.brand = brand;
this.price = price;
}
// 添加方法
Phone.prototype.call = function () {
console.log("打电话");
}
// 实例化对象
let Huawei = new Phone("华为", 5999);
Huawei.call();
console.log(Huawei);
// ES6 class 实例化对象
class Shouji {
// 构造方法 名字不能修改
constructor(brand, price) {
this.brand = brand;
this.price = price;
}
// 方法必须使用该语法,不能使用 ES5 的对象完整形式
call() {
console.log("我可以打电话");
}
}
// 实例化
let OPPO = new Shouji("OPPO", 4999);
OPPO.call();
console.log(OPPO);
12.2 静态成员
// 静态成员
// function Phone() {
// }
// // 静态属性
// // 属于函数对象,不属于实例属性
// Phone.name = "手机";
// Phone.netPlay = function () {
// console.log("我能上网");
// }
// Phone.prototype.size = '5.5inch';
// let vivo = new Phone();
// console.log(vivo.name); // undefined
// // vivo.netPlay(); //报错
// console.log(vivo.size);
class Phone {
// 静态属性
static name = '手机';
static netPlay() {
console.log("我能上网");
}
}
let onePlus = new Phone();
console.log(onePlus.name);
console.log(Phone.name);
12.3 继承
// ES5 构造函数继承
// 手机
// function Phone(brand, price) {
// this.brand = brand;
// this.price = price;
// }
// Phone.prototype.call = function () {
// console.log("我可以打电话");
// }
// // 智能手机
// function SmartPhone(brand, price, color, size) {
// Phone.call(this, brand, size);
// this.color = color;
// this.size = size;
// }
// // 设置子级构造函数原型
// SmartPhone.prototype = new Phone;
// SmartPhone.prototype.constructor = SmartPhone; //可不写
// // 声明子类的方法
// SmartPhone.prototype.photo = function () {
// console.log("我可以拍照");
// }
// SmartPhone.prototype.play = function () {
// console.log("我可以打游戏");
// }
// const chuizi = new SmartPhone("锤子", 2499, "黑色", "5.5inch");
// console.log(chuizi);
// ES6 class 继承
class Phone {
// 构造方法
constructor(brand, price) {
this.brand = brand;
this.price = price;
}
// 父类的成员属性
call() {
console.log("我可以打电话");
}
}
class SmartPhone extends Phone {
// 构造方法
constructor(brand, price, color, size) {
super(brand, price); //Phone.call(this,brand,price);
this.color = color;
this.size = size;
}
photo() {
console.log("我可以拍照");
}
playGame() {
console.log("玩游戏");
}
// 子类对父类方法的重写
call() {
// super(); //报错
console.log("我可以视频通话");
}
}
const xiaomi = new SmartPhone('小米', 999, '黑色', '4.7inch');
console.log(xiaomi);
xiaomi.call(); // 调用的是子类的call方法,如果子类没有该方法,调用父级的该方法
xiaomi.photo();
xiaomi.playGame();
12.4 getter 和 setter
class Phone {
get price() {
console.log("价格被读取了");
return '999';
}
set price(newVal) {
console.log("价格被修改了");
}
}
// 实例化对象
let s = new Phone();
console.log(s.price);
s.price = 'free';
十三、数值扩展
13.1 Number.EPSILON
Number.EPSILON 是 JavaScript 表示的最小精度
console.log(0.1 + 0.2 === 0.3); // false
function equal(a, b) {
if (Math.abs(a - b) < Number.EPSILON) {
return true;
} else {
return false;
}
}
console.log(equal(0.1 + 0.2, 0.3));
13.2 进制
// 二进制
let b = 0b1010;
console.log(b);
// 八进制
let o = 0o777;
console.log(o);
// 十进制
let d = 100;
console.log(d);
// 十六进制
let x = 0xff;
console.log(x);
13.3 Number.isFinite
Number.isFinite 检测一个数值是否为有限数
console.log(Number.isFinite(100));
console.log(Number.isFinite(100 / 0));
console.log(Number.isFinite(Infinity));
13.4 Number.isNaN
Number.isNaN 检测一个数值是否为 NaN
console.log(Number.isNaN(123)); // false
13.5 Number.parseInt 和 Number.parseFloat
Number.parseInt Number.parseFloat 字符串转整数
console.log(Number.parseInt('2022haha'));
console.log(Number.parseFloat('3.1415926嘿嘿'));
13.6 Number.isInteger
Number.isInteger 判断一个数是否为整数
console.log(Number.isInteger(5));
console.log(Number.isInteger(5.12));
13.7 Math.trunc
将数字的小数部分抹掉
console.log(Math.trunc(3.5));
13.8 Math.sign
判断一个数是 正数(1) 负数(-1) 还是零(0)
console.log(Math.sign(100));
console.log(Math.sign(0));
console.log(Math.sign(-10));
十四、对象方法扩展
14.1 Object.is
Object.is 判断两个值是否完全相等
console.log(Object.is(10, 10)); // 类似于 ===
console.log(Object.is(NaN, NaN));
console.log(NaN === NaN);
14.2 Object.assign
对象的合并
const config1 = {
host: 'localhost',
port: 3306,
name: 'root',
password: 'root',
test: 'test'
}
const config2 = {
host: '127.0.0.1',
port: 3307,
name: 'admin',
password: 123456,
demo: 'demo'
}
console.log(Object.assign(config1, config2));
14.3 Object.setPrototypeOf 和 Object.getPrototypeOf
Object.setPrototypeOf 设置原型对象 Object.getPrototypeOf 获取原型
const school = {
name: '尚硅谷'
}
const cities = {
xiaoqu: ['北京', '上海', '深圳']
}
Object.setPrototypeOf(school, cities); //设置原型对象
console.log(school);
console.log(Object.getPrototypeOf(school)); //获取原型
十五、模块化
模块化是将一个大的程序文件,拆分成许多小的文件,然后将小文件组合起来。
15.1 优点:
-
防止命名冲突
-
代码复用
-
高维护性
15.2 模块化规范产品
ES6 之前的模块化规范有:
-
CommonJS => NodeJS、Browserify
-
AMD => requireJS
-
CMD => seaJS
15.3 ES6 模块化语法
模块功能由两个命令构成:
export
和import
-
export 命令用于规定模块的对外接口
-
import 命令用于输入其他模块提供的功能
m1.js
// 分别暴露
export let name = '张三';
export function fn() {
console.log('我是好人');
}
m2.js
// 统一暴露
let name = '李四';
function fn() {
console.log('我是好人');
}
export { name, fn };
m3.js
// 默认暴露
export default {
name: '王麻子',
haoren: function () {
console.log('我也是好人');
},
};
<script type="module">
// 1. 通用导入方式
// 引入 m1 模块内容
// import * as m1 from "./resources/m1.js";
// 引入 m2 模块内容
// import * as m2 from "./resources/m2.js";
// 引入 m3 模块内容
// import * as m3 from "./resources/m3.js";
// console.log(m1);
// console.log(m2);
// console.log(m3);
// m3.default.haoren();
// 2. 解构赋值形式
// import { name, fn } from "./resources/m1.js"
// console.log(name);
// console.log(fn);
// import { name as lisi, fn as haoren } from "./resources/m2.js"
// console.log(lisi);
// console.log(haoren);
// import { default as m3 } from "./resources/m3.js"
// console.log(m3);
// 简写形式,针对默认暴露
// import m3 from "./resources/m3.js"
// console.log(m3);
</script>
app.js
// 入口文件
import * as m1 from './m1.js';
import * as m2 from './m2.js';
import * as m3 from './m3.js';
console.log(m1);
console.log(m2);
console.log(m3);
<script src="./resources/app.js" type="module"></script>
十六、babel
Babel 是一个 JavaScript 编译器,能够将 ES6 新的语法转换为浏览器能识别的 ES5 的语法
16.1 安装工具
-
babel-cli babel命令行工具
-
babel-preset-env 预设包,能够把新的 ES 特性转换为 ES5
-
browserify 打包工具,项目中一般使用 webpack
cnpm init --yes
// 安装工具
cnpm i babel-cli babel-preset-env browserify -D
// 语法转换
npx babel js -d dist/js --presets=babel-preset-env
// 打包
npx browserify dist/js/app.js -o dist/bundle.js
16.2 引入 npm 包
cnpm i jquery
// 修改背景为粉色
import $ from 'jquery';
$('body').css('background', 'pink');
十七、ES7 新特性
17.1 Array.prototype.includes
Includes
方法用来检测数组中是否包含某个元素,返回布尔类型值
// includes indexOf
const mingzhu = ['西游记', '水浒传', '红楼梦', '三国'];
// 判断
console.log(mingzhu.includes('西游记'));
console.log(mingzhu.includes('金瓶梅'));
17.2 指数操作符
在 ES7 中引入指数运算符
**
,用来实现幂运算,功能与Math.pow
结果相同
// ** 幂运算
console.log(2 ** 10)
console.log(Math.pow(2, 10));;
十八、ES8 新特性
18.1 async 和 await
async 和 await 两种语法结合可以让异步代码像同步代码一样
18.1.1 async 函数
-
async 函数的返回值为 promise 对象
-
promise 对象的结果由 async 函数执行的返回值决定
async function fun() {
// console.log("hello world");
// 返回字符串
// return 'hello world';
// 返回的结果不是一个 Promise 类型的对象,返回的结果就是成功的 Promise 对象
// return;
// 抛出错误,返回的结果是一个失败的 Promise
// throw new Error('出错啦!');
// 返回的结果是 Promise 对象
return new Promise((resolve, reject) => {
resolve('成功的数据');
// reject('失败的错误');
})
}
const result = fun();
console.log(result);
// 调用 then 方法
result.then(value => {
console.log(value);
}, reason => {
console.warn(reason);
})
18.1.2 await 表达式
-
await 必须写在 async 函数中
-
await 右侧的表达式一般为 promise 对象
-
await 返回的是 promise 成功的值
-
await 的 promise 失败了,就会抛出异常,需要通过 try…catch 捕获处理
// 创建 Promise 对象
const p = new Promise((resolve, reject) => {
// resolve('成功的值');
reject('失败啦!');
})
// await 要放在 async 函数中
async function main() {
try {
let result = await p;
console.log(result);
} catch (error) {
console.log(error);
}
}
// 调用 main 函数
main();
18.1.3 async与await结合读取文件内容
// 引入 fs 模块
const fs = require('fs');
// 读取内容
function readHello1() {
return new Promise((resolve, reject) => {
fs.readFile('./hello1.txt', (err, data) => {
// 失败
if (err) reject(err);
// 成功
resolve(data);
});
});
}
function readHello2() {
return new Promise((resolve, reject) => {
fs.readFile('./hello2.md', (err, data) => {
// 失败
if (err) reject(err);
// 成功
resolve(data);
});
});
}
function readHello3() {
return new Promise((resolve, reject) => {
fs.readFile('./hello3.txt', (err, data) => {
// 失败
if (err) reject(err);
// 成功
resolve(data);
});
});
}
// 声明一个 async 函数
async function main() {
let hello1 = await readHello1();
let hello2 = await readHello2();
let hello3 = await readHello3();
console.log(hello1.toString());
console.log(hello2.toString());
console.log(hello3.toString());
}
main();
18.1.4 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)
}
}
}
})
}
// 测试
// const result = sendAjax("https://api.apiopen.top/api/getImages");
// console.log(result);
// Promise then 方法测试
// sendAjax("https://api.apiopen.top/api/getImages").then(value => {
// console.log(value);
// }, reason => { })
// async 与 await 测试
async function main() {
let result = await sendAjax("https://api.apiopen.top/api/getImages");
console.log(result);
}
main()
18.2 ES8 对象方法扩展
const school = {
name: '尚硅谷',
cities: ['北京', '上海', '深圳'],
xueke: ['前端', '后端', '大数据', '运维']
};
// 获取所有对象的键
console.log(Object.keys(school));
// 获取所有对象的值
console.log(Object.values(school));
// entries
console.log(Object.entries(school));
// 创建 Map
const m = new Map(Object.entries(school));
console.log(m.get('cities'));
// 对象属性的描述对象
console.log(Object.getOwnPropertyDescriptors(school));
const obj = Object.create(null, {
name: {
// 设置值
value: '尚硅谷',
// 属性特性
writable: true,
configurable: true,
enumerable: true
}
})
十九、ES9
19.1 rest参数
Rest参数与 spresd 扩展运算符在 ES6 中已经引入,不过 ES6 中只针对于数组,在 ES9 中为对象提供了想数组一样的 rest 参数和扩展运算符
function content({ host, port, username, password }) {
console.log(host);
console.log(port);
console.log(username);
console.log(password);
}
content({
host: '127.0.0.1',
port: '8080',
username: 'admin',
password: '123456'
})
function content({ host, port, ...user }) {
console.log(host);
console.log(port);
console.log(user);
}
content({
host: '127.0.0.1',
port: '8080',
username: 'admin',
password: '123456',
type: 'master'
})
19.2 扩展运算符
const skillOne = {
q: '天音波'
}
const skillTwo = {
w: '金钟罩'
}
const skillThree = {
e: '天雷破'
}
const skillFour = {
r: '猛龙摆尾'
}
const mangseng = { ...skillOne, ...skillTwo, ...skillThree, ...skillFour }
console.log(mangseng);
19.3 正则扩展-命名捕获分组
// 声明一个字符串
let str = '<a href="http://www.atguigu.com">尚硅谷</a>';
// 提取 url 与 标签文本
const reg = /<a href="(.*)">(.*)<\/a>/;
// 执行
const result = reg.exec(str);
console.log(result);
console.log(result[1]);
console.log(result[2]);
let str = '<a href="http://www.atguigu.com">尚硅谷</a>';
const reg = /<a href="(?<url>.*)">(?<text>.*)<\/a>/;
const result = reg.exec(str);
console.log(result);
19.4 正则扩展-反向断言
let str = 'js123456哈哈哈666嘿嘿嘿';
// 正向断言
// const reg = /\d+(?=嘿)/;
// const result = reg.exec(str);
// console.log(result);
// 反向断言
const reg = /(?<=哈)\d+/;
const result = reg.exec(str);
console.log(result);
19.5 正则扩展-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 result = reg.exec(str);
// console.log(result);
const reg = /<li>.*?<a>(.*?)<\/a>.*?<p>(.*?)<\/p>/gs;
let result;
let data = [];
while (result = reg.exec(str)) {
data.push({ title: result[1], time: result[2] });
}
console.log(data);
二十、ES10
20.1 对象扩展方法 Object.fromEntries
// 二维数组
const result = Object.fromEntries([
['name', '尚硅谷'],
['xueke', '测试,前端,后端,大数据。人工智能']
]);
console.log(result);
// Map
const m = new Map();
m.set('name', '张三');
const result2 = Object.fromEntries(m);
console.log(result2);
// Object.entries ES8
const arr = Object.entries({
name: '李四'
})
console.log(arr);
20.2 字符串方法扩展 trimStart 与 trimEnd
let str = ' HelloWorld '
console.log(str);
console.log(str.trim());
console.log(str.trimStart());
console.log(str.trimEnd());
20.3 数组方法扩展flat与flatMap
// flat 平
// 将多维数组转换为低维数组
const arr = [1, 2, 3, [4, 5, 6]]
console.log(arr);
console.log(arr.flat());
const arr2 = [1, 2, 3, [4, 5, 6, [7, 8, 9]]]
console.log(arr2.flat());
// 参数为深度,默认为 1
console.log(arr2.flat(2));
// flatMap
const arr3 = [1, 2, 3];
const result = arr3.map(item => item * 10);
console.log(result);
const arr4 = [1, 2, 3];
const result2 = arr3.map(item => [item * 10]);
console.log(result2);
const arr5 = [1, 2, 3];
const result3 = arr3.flatMap(item => [item * 10]);
console.log(result3);
20.4 Symbol.prototype.description
// 创建 Symbol
let s = Symbol('Hello World')
console.log(s.description);
二十一、ES11
21.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);
console.log(this.#weight);
}
}
const girl = new Person('晓红', 18, '45kg');
console.log(girl);
console.log(girl.name);
console.log(girl.age);
console.log(girl.weight);
girl.intro();
// console.log(girl.#age);
// console.log(girl.#weight);
21.2 Promise.allSettled方法
// 声明两个 promise 对象
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('商品数据 - 1')
}, 1000)
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
// resolve('商品数据 - 2')
reject('出错啦')
}, 1000)
})
// 调用 allsettled 方法
const result = Promise.allSettled([p1, p2])
console.log(result);
const res = Promise.all([p1, p2])
console.log(res);
21.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>/gs;
// 调用方法
const result = str.matchAll(reg);
// for (let v of result) {
// console.log(v);
// }
const arr = [...result];
console.log(arr);
21.4 可选链操作符
function main(config) {
const dbhost1 = config && config.db && config.db.host
console.log(dbhost1);
const dbhost2 = config?.db?.host
console.log(dbhost2);
}
main({
db: {
host: '192.168.1.100',
username: 'root'
},
caches: {
host: '192.168.1.200',
username: 'admin'
}
})
21.5 动态 import
html
<button id="btn">点击</button>
<script src="./resources/ES11app.js" type="module"></script>
ES11app.js
// import * as h1 from './ES11hello.js'
const btn = document.getElementById('btn');
btn.onclick = function () {
import('./ES11hello.js').then((module) => {
// console.log(module);
module.hello();
});
};
ES11hello.js
export function hello() {
alert('Hello');
}
21.6 BigInt 类型
// 大整形
let n1 = 521n;
console.log(n1, typeof (n1));
// 函数
let n2 = 123;
console.log(BigInt(n2));
// console.log(BigInt(1.2)); //报错,不是整数
// 大数值运算
let max = Number.MAX_SAFE_INTEGER;
console.log(max);
console.log(max + 1);
console.log(max + 2);
console.log(BigInt(max) + BigInt(1));
console.log(BigInt(max) + BigInt(2));
21.7 绝对全局对象 globalThis
console.log(globalThis);