ES6:ECMAScript6
let 关键字用来声明变量,使用 let 声明的变量有以下几个特点:
let a;
let b,c,d;
let e = 100;
let f = 521,g= 'iloveyou',h = [];
1.变量不能重复声明
let star = '离歌笑';
let star = '李逍遥';
2.块级作用域 全局,函数,eval
//if else while for
{
let girl = '赵灵儿';
}
console.log(girl);
3.不存在变量提升
console.log(song);
let song = '仙剑奇侠传';
4.不影响作用域链
{
let school = '仙一';
function fn(){
console.log(school);
}
fn();
}
需求:点击div更换背景颜色
Title
const
关键字用来声明常量
,const 声明有以下特点:
(常量的含义是指向的对象不能修改
,但是可以改变对象内部的属性
)
1.一定要赋初始值
const A;
2.一般变量使用大写(潜规则)
const a = 100;
3.常量的值不能修改
SCHOOL = 'LIGEXIAO';
4.块级作用域
{
const PLAYER = 'UZI';
}
console.log(PLAYER);
5.对于数组和对象的元素修改,不算做对常量的修改,不会报错
const TEAM = ['UZI','MXLG','Ming','Letme'];
TEAM.push('LGX');
console.log(TEAM);
6.不允许重复声明
const FRUIT = "apple"
const FRUIT = "apple" // 报错,不可重复声明
ES6 允许按照一定模式从数组和对象中提取值,对变量进行赋值,这被称为解构赋值。
使用场景:频繁使用对象方法、数组元素,就可以使用解构赋值形式;
1.数组的结构
const F4 = ['李逍遥','林月如','赵灵儿','刘晋元'];
let[li,lin,zhao,liu] = F4;
console.log(li);
console.log(lin);
console.log(zhao);
console.log(liu);
2.对象的解构
const li = {
name:'离歌笑',
age:'18',
sing:function(){
console.log('六月的雨');
}
}
let{name,age,sing} = li;
console.log(name);
console.log(age);
console.log(sing);
sing();
注意:
- 在let{name,age,sing} = li的{ } 中,里面的变量名需要和对象中的属性名相同
- 可以通过
let {sing} = li
只获取里面的sing
方法,之后也是通过sing()
调用
使用一对反引号 ` ` 声明的字符串,特性如下:
1.声明
let str = `一曲离歌笑江湖`;
console.log(str,typeof str);//一曲离歌笑江湖 string
2.里面可以直接使用换行
let str = `
- 离歌笑
- 李逍遥
- 赵灵儿
`;
console.log(str);
3.变量拼接(替换/插入)
使用
${变量名}
定位插入的元素位置
let name = '离歌笑';
let out = `一曲${name}江湖`;
console.log(out);//一曲离歌笑江湖
ES6允许在大括号里面,直接写入变量和函数,作为对象的属性和方法,这样的书写更加简洁
let name = '离歌笑';
let sing = function(){
console.log('一曲离歌啸江湖');
}
原来:
const cos = {
name:name,
sing:sing,
ligexiao:function(){
console.log('一曲离歌啸江湖');
}
}
ES6:
const cos = {
name,
sing,
ligexiao(){
console.log('行如止水,心无旁骛');
}
}
ES6允许使用箭头
=>
定义函数
函数声明:
// let fn = function() {
// ...
// }
let fn = (a,b) => {
return a + b
}
// 调用函数
console.log(fn(2,3)) // 5
1.this是静态的,this始终指向
函数声明时所在作用域下的this的值
function getName(){
console.log(this.name);
}
let getName2 = ()=>{
console.log(this.name);
}
window.name = '离歌笑';
const school = {
name :'LIGEXIAO',
}
//直接调用
getName();//离歌笑
getName2();//离歌笑
//call方法调用
getName.call(school);//LIGEXIAO
getName2.call(school);//离歌笑
2.不能作为构造函数实例化对象
let Person =(name,age)=>{
this.name = name;
this.age = age;
}
let me = new Person('ligexiao','30');
console.log(me);//Uncaught TypeError: Person is not a constructor
3.不能使用arguments
变量
let fn = () =>{
console.log(arguments);//Uncaught ReferenceError: arguments is not defined
}
fn(1,2,3);
4.箭头函数的简写
(1) 省略小括号,当形参有且只有一个的时候可以省略小括号。
// let add = (n) => {
// console.log(n + n)
// }
// add(3) // 6
// 简写:
let add = n => {
console.log(n + n)
}
add(3) // 6
(2) 省略花括号 { },仅当函数语句只有一条语句
时。此时,'return' 也需要省略,结果即是返回值
let pow = n => n * n
console.log(pow(8)) // 64
8.箭头函数练习
箭头函数适合与this无关的回调、定时器、数组的方法回调
箭头函数不适合与this有关的回调,事件回调,对象的方法
ES6允许给函数参数赋值初始值
特性:
function add(a,b,c=12){
return a+b+c;
}
let result = add (1,2)
console.log(result) // 15
如果上面代码没有给
形参c
赋初始值,则执行add (1,2)
时,形参c
没有对应的参数,默认为NaN
,所以add (1,2)
的执行结果为NaN
2.与解构赋值结合
function ap({host='127.0.0.1', username, password, port}){
console.log(host,username,password,port) //
}
ap({
host: 'localhost',
username:'admin',
password:'000000',
port:3000
})
// 执行结果:localhost admin 000000 3000
ES6引入
rest参数
,用于获取函数的实参,用来代替arguments
rest参数:以
...
为前缀,例如下面的...args
原来的arguments
function date(){
console.log(arguments);
}
date('离歌笑','李逍遥','赵灵儿');//Arguments(3) ['离歌笑', '李逍遥', '赵灵儿', callee: ƒ, Symbol(Symbol.iterator): ƒ]
现在的rest参数
function date(...arg){
console.log(arg);
}
date('离歌笑','李逍遥','赵灵儿');//['离歌笑', '李逍遥', '赵灵儿']
rest参数必须要放到参数最后
function fn(a,b,...arg){
console.log(a);
console.log(b);
console.log(...arg);
}
fn(1,2,3,4,5,6,7);//1
// 2
//3 4 5 6 7
扩展运算符
...
,能将数组
转换为逗号分隔的参数序列
const tfboys=['易烊千玺','王源','王俊凯']
function show(){
console.log(arguments)
}
show(tfboys) // 一个参数,数组:['易烊千玺', '王源', '王俊凯']
show(...tfboys) //0: "易烊千玺" 1: "王源" 2: "王俊凯"
应用:
1.数组的合并
const arr1 = ['李逍遥','离歌笑'];
const arr2 = ['林月如','赵灵儿'];
// const arr = arr1.concat(arr2);//['李逍遥', '离歌笑', '林月如', '赵灵儿']
const arr = [...arr1,...arr2];
console.log(arr);//['李逍遥', '离歌笑', '林月如', '赵灵儿']
2.数组的克隆
const arr3 = ['李逍遥', '离歌笑', '林月如', '赵灵儿'];
const arr4 = [...arr3];//['李逍遥', '离歌笑', '林月如', '赵灵儿']
console.log(arr4);//['李逍遥', '离歌笑', '林月如', '赵灵儿']
如果数组里面有
引用类型
的数据,则整个为浅拷贝
;否则,就是完全拷贝
const divs = document.querySelectorAll("div");
const divArr = [...divs];
console.log(divArr);// [div, div, div]
直接使用 Symbol()
创建新的 symbol 类型,并用一个可选的字符串作为其描述。
Symbol([description])
description (可选) 字符串类型。对symbol的描述,可用于调试但不是访问symbol本身。请注意,即使传入两个相同的字符串,得到的 symbol 也不相等。
const symbol1 = Symbol();
const symbol2 = Symbol(42);
Symbol()与Symbol.for()的区别
Symbol() :调用相同的symbol多次,会生成多个symbol
Symbol.for():调用相同的symbol多次,仍只会执行第一次的symbol
Symbol.for(key)
方法会根据给定的键 key
,来从运行时的 symbol 注册表中找到对应的 symbol,如果找到了,则返回它,否则,新建一个与该键关联的 symbol,并放入全局 symbol 注册表中。
key:一个字符串,作为 symbol 注册表中与某 symbol 关联的键(可重复调用)
Symbol.for访问的是一个全局的submbol表,如果有了就访问相应对象,没有就重新创建
Symbol.keyFor()方法:
此方法会获取对应Symbol值的键。
全局定义拿得到symbol的值,普通定义拿不到
let cms = Symbol.for('lgx');//全局定义拿得到symbol的值
console.log(Symbol.keyFor(cms));//lgx
let lxy = Symbol('lxy');//普通定义拿不到
console.log(Symbol.keyFor(lxy));//undefined
原来:(内容相同使用[]读取内容只能读取到第一个)
let user1 = '离歌笑';
let user2 = '离歌笑';
let grade = {
[user1]:{js:100,css:89},
[user2]:{js:50,css:26}
};
console.log(grade);
现在
// let user1 = '离歌笑';//{js: 100, css: 89}
// let user2 = '离歌笑';
let user1 = {
name:'离歌笑',
key:Symbol(),
}
let user2 = {
name:'离歌笑',
key:Symbol(),
}
let grade = {
[user1.key]:{js:100,css:89},
[user2.key]:{js:50,css:26}
};
console.log(grade[user1.key]);//{js: 100, css: 89}
Symbol取值和赋值都要加[]
对象,属性如果不想公布到外部可以用symbol
由于任何两个 symbol 都是不相等的,在 JavaScript 里可以很方便地用来模拟私有属性。symbol` 不会出现在 Object.keys() 的结果中,因此除非你明确地 export 一个 symbol,或者用 Object.getOwnPropertySymbols() 函数获取,否则其他代码无法访问这个属性。
Object.keys()返回属性key,但不包括不可枚举的属性
Reflect.ownKeys()返回所有属性key
let symbol = Symbol("一曲离歌笑江湖");
let lgx = {
name:'李逍遥',
[symbol]:'离歌笑',
}
// for (const key in lgx)//普通遍历遍历不了symbol的值
// {
// console.log(key);
// }
// for(const key of Object.getOwnPropertySymbols(lgx)){//只能遍历到symbol类型
// console.log(key);
// }
// for(const key of Reflect.ownKeys(lgx))//返回所有属性key
// {
// console.log(key);
// }
let site = Symbol('一曲离歌啸江湖');
class User{
constructor(name){
this.name = name;
this[site] = '离歌笑';
}
getName(){
return `${this[site]} ${this.name}`;
}
}
let lxy = new User('绿巨人');
// console.log(lxy.getName());
// for(let key in lxy)
// {
// console.log(key);
// }
ES6
引入了一种新的原始数据类型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(s2===s3);//false
//Symbol.for 创建
let s4 = Symbol.for("离歌笑");
let s5 = Symbol.for("离歌笑");
console.log(s4===s5);//true
2.不能与其他数据进行运算(不可运算、比较)
let result = s+100;
let result = s>100;
let result = s+s;//Uncaught TypeError: Cannot convert a Symbol value to a number
3.数据类型的种类
字符串(String)、数字(Number)、布尔(Boolean)、数组(Array)、对象(Object)、空(Null)、未定义(Undefined),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);//{name: '俄罗斯方块', up: ƒ, down: ƒ, Symbol(): ƒ, Symbol(): ƒ}
console.log(game[methods.down]());//我可以快速下降!!!
2.给对象添加方法方式二:
let youxi = {
name:'离歌笑',
[Symbol('lgx')]:function(){
console.log('一曲离歌笑江湖');
},
[Symbol('lxy')]:function(){
console.log('行如止水,心无旁骛');
}
}
console.log(youxi);//{name: '离歌笑', Symbol(lgx): ƒ, Symbol(lxy): ƒ}
想读取Symbol方法的内容
let lgx = Symbol('lgx');
let lxy = Symbol('lxy');
let youxi = {
name:'离歌笑',
lgx:function(){
console.log('一曲离歌笑江湖');
},
lxy:function(){
console.log('行如止水,心无旁骛');
}
}
youxi.lxy()//行如止水,心无旁骛
symbol 内置属性
1.Symbol.hasInstance(自己控制类型检测)
//自己控制类型检测
class Person{
static [Symbol.hasInstance](param){
console.log(param);
console.log('我被用来检测类型了');
return false;
}
}
let o = {};
console.log(o instanceof Person);
2.Symbol.isConcatSpreadable(该属性决定了当前对象作为concat的参数时是否可以展开)
const arr = [1,2,3];
const arr2 = [4,5,6];
arr2[Symbol.isConcatSpreadable]=false;
console.log(arr.concat(arr2));
迭代器( lterator)是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署lterator接口,就可以完成遍历操作。
ES6创造了一种新的遍历命令for…of循环,lterator接口主要供 for…of消费
原生具备iterator接口的数据(可用for of遍历)
for ... of
和 for ... in
for(let v in xiyou){
console.log(v);//0 1 2 3
}
//使用for...of遍历数组
for(let v of xiyou){
console.log(v);//李逍遥 赵灵儿 林月如 刘晋元
}
迭代器原理
- 创建一个
指针对象
,指向数据结构的起始位置- 第一次调用
next()
方法,指针自动指向数据结构第一个
成员- 接下来不断调用
next()
,指针一直往后移动,直到指向最后一个
成员- 每次调用
next()
返回一个包含value
和done
属性的对象
const xiyou = ['李逍遥','赵灵儿','林月如','刘晋元'];
//使用for...of遍历数组
// for(let v of xiyou){
// console.log(v);//李逍遥 赵灵儿 林月如 刘晋元
// for in保存的是键名,for of保存的是键值
// }
let iterator = xiyou[Symbol.iterator]();
//调用对象的iterator方法,done: true,指针指向最后一个,结束
console.log(iterator.next());//{value: '李逍遥', done: false}
console.log(iterator.next());//{value: '赵灵儿', done: false}
console.log(iterator.next());//{value: '林月如', done: false}
console.log(iterator.next());//{value: '刘晋元', done: false}
console.log(iterator.next());//{value: undefined, done: true}
done
的值为true
的时候表示循环完成了- 需要自定义遍历数组的时候,要想到迭代器
实践练习
17.迭代器自定义遍历对象
生成器函数是ES6提供的一种异步编程解决方案,语法行为与传统函数完全不同,是一种特殊的函数
一个generator看上去像一个函数,但可以返回多次。
generator和函数不同的是,generator由function * 定义(注意多出的*号),并且,除了return语句,还可以用yield返回多次。
回调地狱
setTimeout(()=>{
console.log('1秒');
setTimeout(()=>{
console.log('2秒');
setTimeout(()=>{
console.log('3秒');
setTimeout(()=>{
console.log('4秒');
setTimeout(()=>{
console.log('5秒');
},5000)
},4000)
},3000)
},2000)
},1000)
function * generator (){ //函数名和function中间有一个 *
yield '耳朵' //yield是函数代码的分隔符
yield '尾巴'
yield '真奇怪'
}
let iterator = generator()
console.log(iteretor.next())
//{value:'耳朵',done:false} next() // 执行第一段,并且返回yield后面的值
console.log(iteretor.next()) //{value:'尾巴',done:false}
console.log(iteretor.next()) //{value:'真奇怪',done:false}
function * gen(){
console.log(111);
yield '一只没有耳朵';
console.log(222);
yield '一只没有眼睛';
console.log(333);
yield '真奇怪';
console.log(444);
}
let iterator = gen();
// iterator.next();//111
// iterator.next();//222
// iterator.next();//333
// iterator.next();//444
// console.log(iterator.next());
// console.log(iterator.next());
// console.log(iterator.next());
// console.log(iterator.next());
//遍历
for(let v of iterator)
{
console.log(v);111 一只没有耳朵 222 一只没有眼睛 333 真奇怪444
}
1. 生成器函数的参数传递
第二次调next方法传入的实参将作为第一个yield语句的整体返回结果
当前next方法传入的实参将作为 上一个yield语句的整体返回结果
function * gen(args){
console.log(args) //AAA
let one = yield 111 //111 (将 yield 111 返回的值赋给one)
console.log(one) //BBB
let two = yield 222 //222
console.log(two) //CCC
let three = yield 333 //333
console.log(three) //DDD
}
let iterator = gen('AAA')
console.log(iterator.next())
console.log(iterator.next('BBB')) //next中传入的BBB将作为yield 111的返回结果
console.log(iterator.next('CCC')) //next中传入的CCC将作为yield 222的返回结果
console.log(iterator.next('DDD')) //next中传入的DDD将作为yield 333的返回结果
2. 实例1:用生成器函数的方式解决回调地狱问题
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() //111
yield two() //222
yield three() /333
}
let iterator = gen()
iterator.next()
3.实例2:模拟异步获取数据
异步编程:文件操作 网络操作(ajax,request) 数据库操作 定时器
//模拟获取 用户数据 订单数据 商品数据
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
是ES6引入的异步编程
的新解决方案。语法上 Promise是一个构造函数,用来封装
异步操作并可以获取其成功
或失败
的结果。
const p = new Promise((resolve, reject) => {
setTimeout(()=>{
let data='数据库数据'
// resolve(data)
reject(data)
})
})
p.then(function (value){ // 成功则执行第一个回调函数
console.log(value)
},function (reason){ // 失败则执行第二个
console.error(reason)
})
Promise读取文件
//1.引入fs模块
const fs = require('fs');
fs.readFile('./resource/content.txt',function(err,data){
if(err)throw err;
console.log(data);
})
const p = new Promise(function(resolve,reject){
require('fs').readFile('./resource/content.txt',function(err,data){
if(err) reject(err);
resolve(data);
})
})
p.then(function(value){
console.log(value.toString())
},function(reason){
console.error('error真成功');
})
Promise封装Ajax请求
//接口地址:https://api.apiopen.top/getJoke
const p = new Promise(function(resolve,reject){
//1.创建对象
const xhr = new XMLHttpRequest();
//2.初始化
xhr.open('GET', 'https://api.apiopen.top/geoke');
//3.发送
xhr.send();
//4.绑定事件,处理响应结果
xhr.onreadystatechange = function(){
//判断
if(xhr.readyState === 4)
{
//判断响应状态码 200-299
if(xhr.status >= 200 && xhr.status < 300)
{
//表示成功
resolve(xhr.response);
}
else{
//表示失败
reject(xhr.status);
}
}
}
})
p.then((value)=>{
console.log(value);
},
(reason)=>{
console.error(reason);
})
Promise.then()
方法
const p =new Promise((resolve, reject) =>{
setTimeout(() => {
resolve('用户数据')
})
});
//then()函数返回的实际也是一个Promise对象
//1.当回调后,返回的是非Promise类型的属性时,状态为fulfilled,then()函数的返回值为对象的成功值,如reutnr 123,返回的Promise对象值为123,如果没有返回值,是undefined
//2.当回调后,返回的是Promise类型的对象时,then()函数的返回值为这个Promise对象的状态值
//3.当回调后,如果抛出的异常,则then()函数的返回值状态也是rejected
let result = p.then(value => {
console.log(value)
//1.非Promise类型的属性
// return 123
//2.是Promise对象
// return new Promise((resolve, reject) => {
// resolve('ok');
// reject('error');//rejected(失败)
// })
//3.抛出错误
// throw new Error('出错啦!');
// throw '出错啦!!!';
},reason => {
console.log(reason)
})
console.log(result)
链式回调
p.then(value=>{}).then(value=>{})
案例 Promise读取多个文件
//引入fs模块
const fs = require('fs');
//回调地狱
// fs.readFile('./resource/草.txt',(err,data1)=>{
// fs.readFile('./resource/无题.txt',(err,data2)=>{
// fs.readFile('./resource/题雁塔.txt',(err,data3)=>{
// let result = `${data1}
// ${data2}
// ${data3} `;
// console.log(result.toString());
// })
// })
// })
const p = new Promise((reslove,reject)=>{
fs.readFile('./resource/草.txt',(err,data)=>{
reslove(data);
})
})
p.then(value=>{
return new Promise((reslove,reject)=>{
fs.readFile('./resource/无题.txt',(err,data)=>{
reslove([value,data]);
})
})
}).then(value=>{
return new Promise((reslove,reject)=>{
fs.readFile('./resource/题雁塔.txt',(err,data)=>{
//压入
value.push(data);
reslove(value);
})
})
}).then(value=>{
console.log(value.join('\r\n'));
})
Promise.catch()
方法
const p = new Promise((resolve, reject) => {
setTimeout(()=>{
reject('出错啦')
},1000)
})
p.catch(reason => {
console.log(reason)
})
ES6提供了新的数据结构set(集合)。它类似于数组,但成员的值都是唯一的,集合实现了iterator接口,所以可以使用「扩展运算符』和「 for…of…』进行遍历
集合的属性和方法:
.size
返回集合的元素个数.add()
增加一个新元素,返回当前集合.delete()
删除元素,返回boolean值.has()
检测集合中是否包含某个元素,返回boolean值
let s = new Set();
let s2 = new Set(['A','B','C','D'])
//元素个数
console.log(s2.size)
//添加新的元素E
s2.add('E')
//删除元素A
s2.delete('A')
//检测是否有 C
console.log(s2.has('C'))
//清空
s2.clear()
console.log(s2)
应用:
let arr = [1,2,3,4,5,4,3,2,1];
//1.数组去重
// let result = [...new Set(arr)];
// console.log(result);//[1, 2, 3, 4, 5]
//2.交集
let arr2 = [4,5,6,5,6];
let s2 = new Set(arr2);//4 5 6
// let result = [...new Set(arr)].filter(item=>{
// if(s2.has(item))
// {
// return true;
// }
// else{
// return false;
// }
// })
let result = [...new Set(arr)].filter(item=>s2.has(item))
console.log(result);//[4, 5]
//3.并集
let union = [...new Set([...arr,...arr2])];
console.log(union);//[1, 2, 3, 4, 5, 6]
//4.差集
let diff = [...new Set(arr)].filter(item=>!(s2.has(item)))
console.log(diff);// [1, 2, 3]
ES6提供了
Map数据结构
。它类似于对象,也是键值对的集合
。但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。Map
也实现了iterator
接口,所以可以使用『扩展运算符』和「for…of…』进行遍历。
Map的属性和方法:
.size
获取Map的键值对数量(最外层).set(key,value)
添加键值对.delete(key)
删除键为key的键值对.get(key)
获取键为key的值for...of
遍历里面的每一个键值对
let m = new Map();
//添加元素
m.set('name','离歌笑');
m.set('lgx',function(){
console.log('我可以改变世界');
})
let key = {
school:'xianyi'
}
m.set(key,['杭州','长安','仙灵']);
//size
console.log(m.size);
//删除键为name的键值对,会返回修改后的Map集合
// m.delete(key);
m.delete('name');
//获取
console.log(m.get('lgx'));
console.log(m.get(key));
//清空
// m.clear();
console.log(m);
//遍历里面的每一个键值对
for(let v of m)
{
console.log(v);
}
ES6提供了更接近传统语言的写法,引入了
Class
(类)这个概念,作为对象的模板。通过class关键字,可以定义类。基本上,ES6的class可以看作只是一个语法糖,它的绝大部分功能,ES5都可以做到,新的class写法只是让对象原型
的写法更加清晰、更像面向对象编程的语法而已。
//ES5的构造函数
function Phone(brand,price){
this.brand = brand;
this.price = price;
}
Phone.prototype.call = function(){
console.log('我可以打电话');
}
//实例化对象
let Huawei = new Phone('华为','2000');
console.log(Huawei);
Huawei.call();
//ES6的构造函数 Class
class iPhone{
//构造方法,名字不能修改
constructor(brand,price){
this.brand = brand;
this.price = price;
}
//方法必须使用该语法,不能使用ES5的对象完整形式
call(){
console.log('我可以打电话');
}
}
let onePlus = new iPhone("1+",1999);
onePlus.call();
console.log(onePlus);
结果:
ES5静态成员
function Phone(){}
Phone.iname='手机';//静态成员,不能被实例化对象调用
Phone.change= function(){
console.log("我可以改变世界,但是先要改变自己");
}
Phone.prototype.size = '5.5inch';
let nokia = new Phone();
console.log(Phone.iname);//手机
Phone.change();//我可以改变世界,但是先要改变自己
console.log(nokia.iname);//undefined
console.log(nokia.size);//5.5inch
ES6静态成员
class Phone{
// 声明静态成员变量
static name = '手机';
static change(){
console.log("我可以改变世界,但是先要改变自己");
}
}
let nokia = new Phone();
console.log(nokia.name);//undefined
console.log(Phone.name);//手机
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,price);
this.color = color;
this.size = size;
}
SmartPhone.prototype = new Phone();
//如果利用对象的形式修改了原型对象,别忘了利用constructor指回原来的原型对象
SmartPhone.constructor = SmartPhone;
SmartPhone.prototype.photo = function(){
console.log('我可以拍照');
}
SmartPhone.prototype.playGame = function(){
console.log('我可以玩游戏');
}
let chuizi = new SmartPhone('chuizi',2499,'黑色','5.5inch');
console.log(chuizi);
结果:
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('我可以玩游戏');
}
}
let xiaomi = new SmartPhone('小米',1999,'黑色','4.7inch');
console.log(xiaomi);
xiaomi.call();
xiaomi.photo();
xiaomi.playGame();
结果:
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(){
console.log('我可以视频通话');
}
}
let xiaomi = new SmartPhone('小米',1999,'黑色','4.7inch');
console.log(xiaomi);
xiaomi.call();
xiaomi.photo();
xiaomi.playGame();
结果:
class Phone{
get price(){
console.log('价格属性被读取了');
return '10000yuan';
}
set price(newVal){
console.log('价格属性被修改了');
}
}
//实例化对象
let s = new Phone();
console.log(s.price);//10000yuan
s.price = "free";
结果:
// Number.EPSILON是 JavaScript的最小精度,属性的值接近于 2.22044...E-16
function equal(a,b){
if(Math.abs(a-b)
结果:
//1.Object.is 判断两个值是否完全相等
console.log(Object.is(120,120));//=== //true
console.log(Object.is(isNaN,isNaN));//=== //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://xianyi.com',
port:'33060',
name:'xianyi.com',
pass:'lixiaoyao',
}
console.log(Object.assign(config1,config2));//{host: 'http://xianyi.com', port: '33060', name: 'xianyi.com', pass: 'lixiaoyao', test: 'test'}
//3.Object.setPrototypeOf 设置原型对象 Object.getPrototypeof
const school = {
name:'离歌笑'
}
const cities = {
renming:['李逍遥','赵灵儿','林月如']
}
Object.setPrototypeOf(school,cities);
console.log(Object.getPrototypeOf(school));//{renming: Array(3)}
console.log(school);//{name: '离歌笑'}
模块化是指将一个
大的程序文件
,拆分成许多小的文件
,然后将小文件组合起来。
1. 模块化的好处:
- 防止命名冲突
- 代码复用
- 高维护性
- 模块化规范产品
2. ES6之前的模块化规范有:
- CommonJS ====> NodeJS、Browserify
- AMD ====> requireJS
- CMD ====> seaJS
3. 语法:
- 模块功能主要有两个命令构成:
export
和import
export
命令用于规定模块的对外接口import
命令用于输入其他模块提供的功能
16.1.1.分别暴露
// 下面js代码放在./js/m1.js文件中
//分别暴露
export let school = '离歌笑';
export function teach(){
console.log('一曲离歌笑江湖');
}
结果:
16.1.2. 统一暴露
let school = '清华大学';
function findjob(){
console.log('找工作吧');
}
//统一暴露
export {school, findjob}
16.1.3. 默认暴露(多变量暴露)
//默认暴露 export default
export default {
school:'清华大学',
change:function(){
console.log('可以改变人的一生!')
}
}
16.2.1. 通用导入方式
import * as m1 from "./js/m1.js"
import * as m2 from "./js/m2.js"
import * as m3 from "./js/m3.js"
16.2.2. 解构赋值方式
import {school,teach} from "./js/m1.js";
import {school as s ,findJob} from "./js/m2.js";
import {default as m3} from "./js/m3.js";
console.log(school,teach);
console.log(s,findJob);
console.log(m3);
结果:
16.2.3. 简便形式(只针对默认暴露)
import m3 from "./js/m3.js";
console.log(m3);//{school: '清华大学', change: ƒ}
// 下面js代码放在./js/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);
结果:
Babel 概述:Babel 是一个 JavaScript 编译器;Babel 能够将新的ES规范语法转换成ES5的语法;因为不是所有的浏览器都支持最新的 ES 规范,所以,一般项目中都需要使用 Babel 进行转换;步骤:使用 Babel 转换 JS 代码 —— 打包成一个文件 —— 使用时引入即可;
步骤
第一步:安装工具babel-cli(命令行工具) babel-preset-env(ES转换工具) browserify(打包工具, 项目中使用的是webpack);
第二步:初始化项目
npm init -y第三步:安装npm i babel-cli babel-preset-env browserify -D第四步:使用 babel 转换npx babel js(js目录) -d dist/js (转化后的js目录) --presets=babel-preset-env第五步:打包npx browserify dist/js/app.js -o dist/bundle.js第六步:在使用时引入 bundle.js< script src = "./js/bundle.js" type = "module" >< /script>
//分别暴露
export let school = '离歌笑';
export function teach(){
console.log('一曲离歌笑江湖');
}
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.teach = teach;
//分别暴露
var school = exports.school = '离歌笑';
function teach() {
console.log('一曲离歌笑江湖');
}
第一步:安装jquery:
npm i jquery
第二步:在app.js使用jquery
//修改背景颜色为粉色
import $ from 'jquery';//const $ = require("jquery");
$('body').css("background","pink");
第三步:重新转换和打包
npx babel js(js目录) -d dist/js (转化后的js目录) --presets=babel-preset-env
npx browserify dist/js/app.js -o dist/bundle.js
概述:Includes 方法用来检测数组中是否包含某个元素,返回布尔类型值;判断数组中是否包含某元素,语法: arr.includes( 元素值 ) ;
const renming = ['李逍遥','赵灵儿','林月如','刘晋元'];
console.log(renming.includes('李逍遥'));//true
console.log(renming.includes('离歌笑'));//false
概述:在 ES7 中引入指数运算符「 ** 」,用来实现幂运算,功能与 Math.pow 结果相同;幂运算的简化写法,例如: 2 的 10 次方: 2**10 ;
//**(指数操作符)
console.log(2**10);//1024
console.log(Math.pow(2,10));//1024
概述:async 和 await 两种语法结合可以让异步代码看起来像同步代码一样;简化异步函数的写法;
概述:1. async 函数的返回值为 promise 对象;2. promise 对象的结果由 async 函数执行的返回值决定;
1.返回的结果不是一个Promise类型的对象,返回的结果就是成功的Promise对象
2.抛出错误,返回的结果是一个失败的Promise
3.返回的结果如果是一个Promise对象,结果成功就是成功,失败就是失败
// async函数
async function fn(){
//返回一个字符串
// return '离歌笑';//fulfilled
//返回的结果不是一个Promise类型的对象,返回的结果就是成功的Promise对象
// return;
//抛出错误,返回的结果是一个失败的Promise
// throw new Error('出错啦!');
//返回的结果如果是一个Promise对象
return new Promise((resolve,reject)=>{
resolve('成功的数据');//fulfilled
// reject('失败的数据');//rejected
})
}
const result = fn();
// console.log(result);
//调用then方法
result.then(value=>{
console.log(value);
},(reason)=>{
console.warn(reason);
})
概述:1. await 必须写在 async 函数中;2. await 右侧的表达式一般为 promise 对象;3. await 返回的是 promise 成功的值;4. await 的 promise 失败了 , 就会抛出异常 , 需要通过 try...catch 捕获处理;
//创建Promise对象
const p = new Promise((resolve,reject)=>{
// resolve('成功啦哦哦');
reject('失败的原因很复杂');
})
//await 要放在async函数中
async function main(){
try{
const result = await p;
console.log(result);
}
catch(e){
console.log(e);//失败的原因很复杂
}
}
//调用函数
main();
const fs = require('fs');
function readCao(){
return new Promise((reslove,reject)=>{
fs.readFile('./resource/草.txt',(err,data)=>{
if(err){reject(err);}
reslove(data);
})
})
}
function readWuTi(){
return new Promise((reslove,reject)=>{
fs.readFile('./resource/无题.txt',(err,data)=>{
if(err){reject(err);}
reslove(data);
})
})
}
function readTiYanTa(){
return new Promise((reslove,reject)=>{
fs.readFile('./resource/题雁塔.txt',(err,data)=>{
if(err){reject(err);}
reslove(data);
})
})
}
async function main(){
//文章1
try{
let cao = await readCao();
console.log(cao.toString());
}
catch(e){
console.log(e);
}
//文章2
try{
let wuti = await readWuTi();
console.log(wuti.toString());
}
catch(e){
console.log(e);
}
//文章3
try{
let tiyanta = await readTiYanTa();
console.log(tiyanta.toString());
}
catch(e){
console.log(e);
}
}
main();
结果:
//发送Ajax请求,返回的结果是Pomise对象
function sendAJAX(url) {
return new Promise((resolve,reject)=>{
//1.创建对象
const xhr = new XMLHttpRequest();
//2.初始化
xhr.open('GET',url);
//3.发送
xhr.send();
//4.事件绑定
xhr.onreadystatechange = ()=>{
if(xhr.readyState === 4)
{
if(xhr.status>=200 && xhr.status<300)
{
//成功
resolve(xhr.response);
}
else{
//失败
reject(xhr.status);
}
}
}
})
}
//Promise then方法测试
// sendAJAX('https://api.apiopen.top/getJoke').then((value)=>{
// console.log(value);
// },(reason)=>{
// console.log(reason);
// })
//使用async与await
async function main(){
//发送AJAX请求
let result = await sendAJAX('https://api.apiopen.top/getJoke');
console.log(result);
}
main();
Object.values、Object.entries和
Object.getOwnPropertyDescriptors:
1. Object.values() 方法:返回一个给定对象的 所有可枚举属性值 的数组;2. Object.entries() 方法:返回一个给定对象自身可遍历属性 [key,value] 的数组; (对象变数组)3. Object.getOwnPropertyDescriptors() 该方法:返回指定对象所有自身属性的描述对象;
//声明对象
const school = {
name:'离歌笑',
cities:['杭州','长安','汴梁'],
zhiye:['daxia','taifu','gongzhu']
}
//获取对象所有的键
console.log(Object.keys(school));//['name', 'cities', 'zhiye']
//获取对象所有的值
console.log(Object.values(school));//['离歌笑', Array(3), Array(3)]0: "离歌笑"1: (3) ['杭州', '长安', '汴梁']2: (3) ['daxia', 'taifu', 'gongzhu']length: 3[[Prototype]]: Array(0)
//entries
console.log(Object.entries(school));//[Array(2), Array(2), Array(2)]
//创建Map
const m = new Map(Object.entries(school));
console.log(m.get('cities'));//['杭州', '长安', '汴梁']
//对象属性的描述对象
console.log(Object.getOwnPropertyDescriptors(school));//{name: {…}, cities: {…}, zhiye: {…}}
const obj = Object.create(null,{
name:{
//设置值
value:'离歌笑',
writable:true,//值是否可以重写。true|false 默认为false
configurable:true,//目标属性是否可以被删除或是否可以再次修改特特性 true|false 默认为false
enumerable:true,//目标属性是否可以被枚举。true|false 默认为false
}
})
结果:
概述:Rest 参数与 spread 扩展运算符在 ES6 中已经引入,不过 ES6 中只针对于数组,在 ES9 中为对象提供了 像数组一样的 rest 参数和扩展运算符;
// Rest参数与spread扩展运算符
// Rest 参数与 spread 扩展运算符在 ES6 中已经引入,
// 不过 ES6 中只针对于数组,在 ES9 中为对象提供了像
// 数组一样的 rest 参数和扩展运算符
function connect({name,age,...user}){
console.log(name);
console.log(age);
console.log(user);
}
connect({
name:'离歌笑',
age:20,
price:5000,
wuli:10000000
})
const skillOne = {
x:'仙风云体术'
}
const skillTwo = {
z:'醉仙望月步',
a:'爱无限'
}
const skillThree = {
q:'七诀剑气'
}
const skillFour = {
y:'御剑术'
}
const lixiaoyao = {...skillOne,...skillTwo,...skillThree,...skillFour};//对象的合并
console.log(lixiaoyao);//{x: '仙风云体术', z: '醉仙望月步', q: '七诀剑气', y: '御剑术'}
结果:
概述:ES9 允许命名捕获组使用符号『 ? 』 , 这样获取捕获结果可读性更强;
//声明一个字符串
let str = '离歌笑';
//提取url 与[标签文本]
const reg = /(.*)<\/a>/
//执行
const result = reg.exec(str);
console.log(result[1]);//http://baidu.com
console.log(result[2]);//离歌笑
let str1 = '离歌笑';
const reg1 = /(?.*)<\/a>/;
const result1 = reg.exec(str1);
// console.log(result1);
console.log(result1.groups.url);//http://baidu.com
console.log(result1.groups.text);//离歌笑
概述:ES9 支持反向断言,通过对匹配结果前面的内容进行判断,对匹配进行筛选;
//声明字符串
let str = 'JS5201314你知道么555啦啦啦';
//正向断言
const reg = /\d+(?=啦)/;
const result = reg.exec(str);
//反向断言
const reg1 = /(?<=么)\d+/;
const result1 = reg1.exec(str);
console.log(result1);
概述:正则表达式中点 . 匹配除回车外的任何单字符,标记『 s 』改变这种行为,允许行终止符出现;
//dot . 元字符 除换行符以外的任意单个字符
let str = `
`;
//声明正则
// const reg = /\s+(.*?)<\/a>\s+(.*?)<\/p/;
const reg = /
.*?(.*?)<\/a>.*?(.*?)<\/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);
结果:
概述:将二维数组或者 map 转换成对象;之前学的 Object.entries 是将对象转换成二维数组;
// Object.fromEntries:将二维数组或者map转换成对象
// 之前学的Object.entries是将对象转换成二维数组
// 此方法接收的是一个二维数组,或者是一个map集合
// 二维数组
const result = Object.fromEntries([
['name','离歌笑'],
['city','长安,余杭,仙灵']
]);
console.log(result);//{name: '离歌笑', city: '长安,余杭,仙灵'}
//Map
const m = new Map();
m.set('name','ligexiao')
console.log(m);//Map(1) {'name' => 'ligexiao'}
const result1 = Object.fromEntries(m);
console.log(result1.name);//ligexiao
console.log(result1);//{name: 'ligexiao'}
//Object.entries ES8
const arr = Object.entries({
name:'绿儿'
});
console.log(arr);
结果:
概述:去掉字符串前后的空白字符;
//trim
let str = ' ligexiao ';
console.log(str);// ligexiao
console.log(str.trim());//ligexiao
console.log(str.trimStart());//ligexiao
console.log(str.trimEnd());// ligexiao
结果:
概述:将多维数组转换成低维数组;
//flat 平
//将多维数组转化为低维数组
// const arr = [1,2,3,[4,5,6]];// [1, 2, 3, 4, 5, 6]
// const arr = [1,2,3,4,[5,6,7,[8,9,0]]];// [1, 2, 3, 4, 5, 6, 7, Array(3)] Array(3):[8, 9, 0]
const arr = [1,2,3,4,[5,6,7,[8,9,0]]];
//参数为深度,是一个数字
console.log(arr.flat(2));// [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
//flatMap 将map得出的多维数组转化为低维数组
const arr1 = [1,2,3,4];
const result0 = arr1.map(item=>item * 10);//[10, 20, 30, 40]
const result1 = arr1.map(item=>[item*10]);//Array(1), Array(1), Array(1), Array(1)] -> [10][20][30][40]
const result2 = arr1.flatMap(item=>item * 10);//[10, 20, 30, 40]
console.log(result0);
console.log(result1);
console.log(result2);
结果:
概述:获取 Symbol 的描述字符串;
//创建Symbol
let s = Symbol('离歌笑');
console.log(s.description);//离歌笑
概述:用来得到正则批量匹配的结果;
let str = `
`;
//声明正则
const reg = /.*?(.*?)<\/a>.*?(.*?)<\/p>/sg
//调用方法
const result = str.matchAll(reg);
for(let v of result)
{
console.log(v);
}
// const arr = [...result];
// console.log(arr);
结果:
概述:私有属性外部不可访问直接; (可以在内部使用,不能在外部使用)
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','40kg');
console.log(girl);
console.log(girl.name);
console.log(girl.#age);
console.log(girl.#weight);
girl.intro();
概述:获取多个 promise 执行的结果集;
//声明两个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);
结果:
调用allSettled方法
调用all方法
概述:?.如果存在则往下走,省略对对象是否传入的层层判断;
//?.
function main(config)
{
const dbHost = config && config.db && config.db.host;
console.log(dbHost);//192.168.0.1
const cacheHost = config?.cache?.host;
console.log(cacheHost);//192.168.0.2
}
main({
db:{
host:'192.168.0.1',
username:'root'
},
cache:{
host:'192.168.0.2',
username:'admin',
}
})
概述:
动态导入模块,什么时候使用时候导入;
html页面:
app.js:
//静态import
import * as m1 from './hello.js';
const btn = document.getElementById('btn');
btn.onclick = function(){
// m1.hello2();
//动态import
import('./hello.js').then(module=>{
module.hello();
})
}
hello.js:
export function hello(){
alert('贝贝 晶晶 欢欢 迎迎 妮妮');
}
export function hello2(){
alert('贝贝 晶晶 欢欢 迎迎 妮妮2');
}
概述:更大的整数;
//大整形
let n = 521n;
console.log(n,typeof(n));//521n 'bigint'
//函数:普通整形转大整形
let x = 123;
console.log(BigInt(n));//521n
// console.log(BigInt(1.2)); //出错了,BigInt不能用浮点数计算
//用于更大数值的运算
let max = Number.MAX_SAFE_INTEGER;
console.log(max);//9007199254740991
console.log(max+1);//9007199254740992
console.log(max+2);//9007199254740992 出错了max+1为最大计算
console.log(BigInt(max));//9007199254740991n
console.log(BigInt(max)+BigInt(1));//9007199254740992n
console.log(BigInt(max)+BigInt(2));//9007199254740993n
结果:
概述:始终指向全局对象 window ;
console.log(globalThis);
结果: