ES6-ES11新特性简介(笔记)

2 篇文章 0 订阅
1 篇文章 0 订阅

ES6 新特性

let声明的变量及声明特性

1、变量不能重复声明

2、块级作用域(es5三种作用域:全局、函数、eval)

3、不存在变量提升

4、不影响作用域链

const声明常量以及特点

1、一定要赋初始值

2、一般常量使用大写(潜规则)

3、常量的值不能修改

4、块级作用域

5、对于数组和对象的元素修改,不算做对常量的修改,不会报错

变量的解构赋值

ES6允许按照一定模式从数组和对象中提取值,对变量进行赋值,这被称为解构赋值。

1、数组的解构

const F4 =[小沈阳","刘能","赵四","宋小宝"];
let [xiao,liu, zhao,song] = F4;
console.log(xiao);	//小沈阳
console.log(liu);	//刘能
console.log(zhao);	//赵四
console.log(song);	//宋小宝

2、对象的解构

const zhao = {
	name: "赵本山",
    age: "不详",
	xiaopin: function(){
		console.log("我可以演小品");
	}
};
let {name, age, xiaopin} = zhao;
console.log(name);	//赵本山
console.log(age);	//不详
console.log(xiaopin);	//function
xiaopin();	//我可以演小品

let {xioapin} = zhao;
xiaopin();	//我可以演小品

模板字符串

ES6引入新的声明字符串的方式:``

1、声明

let str = `我也是一个字符串!`
console.log(str, typeof str);

2、内容中可以直接出现换行符

let str = `<ul>
				<li>1</li>
				<li>2</li>
				<li>3</li>
			</ul>`;

3、变量拼接

let name ="同学";
let out =`${name},你好!`;
console.log(out);	//同学,你好!

简化对象写法

ES6允许在大括号里面,直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁

let name = "王";
let change = function() {
    console.log("哈喽哈喽!!");
}

const school = {
    name,
    change,
    method(){
        console.log("你在吗!!");
    }
}
console.log(school);	//{name: '王', change: ƒ, method: ƒ}

箭头函数

ES6允许使用「箭头」(=>)定义函数。

let fn = function(){
    
}
let fn2 = (a,b) =>{
	return a + b;
}
//调用函数
let result = fn2(1, 2);
console.log(result);	//3

1、this是静态的。this始终指向函数声明时所在作用域下的 this的值。

function getName(){
	console.log(this.name);
}
let getName2 = () => {
	console.log(this.name);
}
//设置 window对象的name属性
window.name ='王';
const school = {
	name: "USC"
}

//直接调用
getName();	//王
getName2();	//王

// call 方法调用
getName.call(school);	//USC
getName2.call(school);	//王

2、不能作为构造函数实例化对象

let Person = (name,age) => {
	this.name = name;
	this.age = age;
}
let person = new Person("wang", 21);
console.log(person);	//Uncaught TypeError: Person is not a constructor

3、不能使用arguments变量

let fn = () => {
	console.log(arguments);
}
fn(1,2,3);	//Uncaught ReferenceError: arguments is not defined

4、箭头函数简写

(1)省略小括号,当形参有且只有一个的时候。

let add = n => {
    return n + n;
}
console.log(add(9));	//18

(2)省略小括号,当形参有且只有一个的时候,此时return必须省略,而且语句的执行结果就是函数的返回值。

//let pow = (n) =>{
let pow = n =>{
	return n * n;
};
console.log(pow(9));	//81

//let pow = (n) => return n * n;//错误写法,return要省略
//let pow = (n) => n * n;
let pow = n => n * n;
console.log(pow(8));	//64

箭头函数适合与 this 无关的回调,定时器,数组的方法回调

箭头函数不适合与this有关的回调,事件回调,对象的方法(可以用,但不适合)

参数默认值

1、形参初始值具有默认值的参数,一般位置要靠后(潜规则)

function connect({host="127.0.0.1", username, password, port}){
	console.log(host)	//atguigu.com
	console.log(username)	//root
    console.log(password)	//root
    console.log(port)	//3306
}
connect({
	host: 'atguigu.com',
    username: "root",
    password: "root",
    port: 3306,
})
rest参数

ES6 引入rest参数,用于获取函数的实参,用来代替arguments

//ES5 获取实参的方式
function date() {
    console.log(arguments,tyoeof arguments);	//输出的是伪数组,是一个对象
}
date("张三", "李四", "王五")

function date(...args) {
    console.log(args);	//['张三', '李四', '王五']
}
date("张三", "李四", "王五")

//rest 参数必须要放到最后
function fn(a, b, ...args){
    console.log(a)	//1
    console.log(b)	//2
    console.log(args)	//(4) [3, 4, 5, 6]
}
fn(1,2,3,4,5,6)

扩展运算符

『…』扩展运算符能将 数组 转换为逗号分隔的 参数序列

声明一个数组 …

const arr = ['张三', '李四', '王五'];

function result() {
    console.log(arguments);	
}
result(arr);//Arguments [Array(3)] 
result(...arr);//Arguments(3)

应用:

// 1. 数组的合并
const arr1 = ["周", "吴"];
const arr2 = ["郑", "王"];
const result = [...arr1, ...arr2];
console.log(result)	//["周", "吴", "郑", "王"]

// 2. 数组的克隆
const arr3 = ['2','3','4'];
const arr4 = [...arr3]; //浅拷贝
console.log(arr4);	//["2", "3", "4"]

// 3. 将伪数组转为真正的数组
let divs = document.getElementsByTagName("div");
let divArr = [...divs];
console.log(divArr);	//[div, div, div, div]
//arguments也能转,但是有rest参数存在就没必要了

Symbol的介绍与创建

ES6引入了一种新的原始数据类型symbol,表示独一无二的值。它是JavaScript语言的第七种数据类型,是一种类似于字符串的数据类型。
Symbol特点:

  1. Symbol的值是唯一的,用来解决命名冲突的问题
  2. Symbol值不能与其他数据进行运算(四则运算、字符串拼接或比较 等等)
  3. Symbol定义的对象属性不能使用for…in循环遍历,但是可以使用Reflect.ownKeys 来获取对象的所有键名
//创建Symbol
let s = Symbol() ;
console.log(s, typeof s);
let s2 = Symbol('尚硅谷');
let s3 = Symbol('尚硅谷');
console.log(s2 === s3);	//false (Symbol像是身份证不重复,他的值像是名字可以重复)
                
// Symbol.for创建
let s4 = Symbol.for('尚硅谷');
let s5 = Symbol.for('尚硅谷');
console.log(s4 === s5); //true

//不能与其他数据进行运算
//let result = s + 100;
//let result = s > 100;
//let result = s + '100';
//let result = s + s;	//Cannot convert a Symbol value to a number

Symbol.for和Symbol()区别:

和 Symbol() 不同的是,用 Symbol.for() 方法创建的的 symbol 会被放入一个全局 symbol 注册表中。
Symbol.for() 并不是每次都会创建一个新的 symbol,它会首先检查给定的 key 是否已经在注册表中了。
假如是,则会直接返回上次存储的那个。否则,它会再新建一个。

Symbol.for("foo"); // 创建一个 symbol 并放入 symbol 注册表中,键为 "foo"
Symbol.for("foo"); // 从 symbol 注册表中读取键为"foo"的 symbol

Symbol.for("bar") === Symbol.for("bar"); // true,证明了上面说的
Symbol("bar") === Symbol("bar"); // false,Symbol() 函数每次都会返回新的一个 symbol

var sym = Symbol.for("mario");
sym.toString();
// "Symbol(mario)",mario 既是该 symbol 在 symbol 注册表中的键名,又是该 symbol 自身的描述字符串

Symbol创建对象属性

//向对象中添加方法 up down
let game = {
    up: function(){},
    down: function(){},
    name: "俄罗斯方块"
}

//声明一个对象
let methods = {
	up: Symbol(),	//方法声明成symbol类型
    down: Symbol(),
};
game[methods.up] = function(){	//将method里面的up方法添加到game
	console.log("我可以改变形状!");
};
game[methods.down] = function(){
	console.log("我可以快速下降!!");
};
console.log(game);
game[methods.up]();	//我可以改变形状!
game[methods.down]();	//我可以快速下降!!

//方法二
let youxi = {
	name: "狼人杀",
	[Symbol('say')]: function(){
		console.log('我可以发言');
	},
	[Symbol('zibao')]: function(){
		console.log('我可以自爆');
	}
}
console.log(youxi)
youxi[Symbol('say')]();

Symbol内置值

除了定义自己使用的Symbol值以外,ES6还提供了11个内置的Symbol值,指向语言内部使用的方法。

内置属性描述
Symbol.haslnstance当其他对象使用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创建衍生对象时,会使用该属性
class Person{
	static [symbol.hasInstance](param){
		console.log(param);	//对象o
		console.log("我被用来检测类型了");
        return true;
	}
}
let o = {};
console.log(o instanceof Person);	//true

const arr = [1,2,3];
const arr2 =[4,5,6];
arr2[Symbol.isConcatSpreadable] = false;
console.log(arr.concat(arr2));	//[1,2,3,[4,5,6]]  arr2作为整体不展开

迭代器

迭代器(lterator)是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署lterator接口,就可以完成遍历操作。

  1. ES6创造了一种新的遍历命令for…of循环,lterator接口主要供 for…of消费。

  2. 原生具备iterator接口的数据(可用for of遍历):

    Array

    Arguments

    Set

    Map

    String

    TypedArray

    NodeList

工作原理:

​ a) 创建一个指针对象指向当前数据结构的起始位置

​ b) 第一次调用对象的 next方法,指针自动指向数据结构的第一个成员

​ c) 接下来不断调用next方法,指针一直往后移动,直到指向最后一个成员

​ d) 每调用next方法返回一个包含value 和 done属性的对象

//声明一个数组
const arr = ['周','吴','郑','王'];

//使用for...of遍历数组
for(let v of arr){
	console.log(v);
}
let iterator = arr[Symbol.iterator]();

//调用对象的next方法, 每调一次next返回新的值然后往后移动
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} 

注:需要自定义遍历数据的时候,要想到迭代器。

//举例:使用for...of...遍历对象里的数组
const banji = {
    name: "二班",
    stus: [
        '小王',
        '小明',
        '小宁',
        '小张',
    ],
    [Symbol.iterator](){
        //索引变量
        let index = 0;
        //保存该作用域的this(banji)
        let that = this;
        return {
            next: function() {
                    if(that.stus.length > index){
                    const result = {value: that.stus[index], done: false};
                    index ++;
                    return result;
                }else{
                    return {value: undefined, done: true};
                }               
            },
        };
    },
}

for(let v of banji){
    console.log(v);
}
//小王
//小明
//小宁
//小张

生成器

生成器函数是ES6提供的一种异步编程解决方案,语法行为与传统函数完全不同

生成器其实就是一个特殊的函数

作用:异步编程(以前用纯回调函数)

function * gen(){
	console.log(111);
    yield '一只没有要朵';
    console.log(222);
    yield '一只没有尾部';
    console.log(333);
    yield '真奇怪';	//yield为函数代码的分隔符,gen函数被其分成四块区域
    console.log(444);
}
//执行获取迭代器对象
let iterator = gen();
iterator.next();	//111
iterator.next();	//222
iterator.next();	//333
iterator.next();	//444

//遍历
for(let v of gen()){
	console.log(v);
}
//111
//一只没有要朵
//222
//一只没有尾部
//333
//真奇怪
//444

生成器函数参数

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'));
//AAA
//{value: 111, done: false}
//BBB
//{value: 222, done: false}
//CCC
//{value: 333, done: false}
//DDD
//{value: undefined, done: true}
生成器函数实例
//异步编程文件操作网络操作(ajax,request)数据库操作
//1s后控制台输出 111 2s后输出 222 3s后输出 333

//“回调地狱”演示
setTimeout(()=>{
    console.log(111);
    setTimeout(()=>{
        console.log(222);
        setTimeout(()=>{
            console.log(333);
        },3000)
    },2000)
},1000)

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();

Promise

Promise是ES6引入的异步编程的新解决方案。语法上 Promise是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果。

  1. Promise构造函数: Promise (excutor){}
  2. Promise.prototype.then方法
  3. Promise.prototype.catch方法
//实例化 Promise 对象
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);
});
//通过resole和reject改变实例状态,调用resolve则Promise状态为成功便执行then方法第一个回调,调用reject状态为失败,则执行第二个回调
Promise读取文件
//1. 引入 fs 模块
const fs = require('fs');

//2. 调用方法读取文件
// fs.readFile('./resources/test.md', (err, data) => {
//     //如果失败,则抛出错误
//     if(err) throw err;
//     //如果没有出错,则输出内容
//     console.log(data.toString());
// });

//3. 使用 Promise 封装
const p = new Promise(function(resolve, reject){
    fs.readFile('./resources/test1.md', (err, data) => {
        //如果失败,则抛出错误
        if(err) reject(err);
        //如果没有出错,则输出内容
        resolve(data);
    });
})

p.then(function(value){
    console.log(value.toString());
}, function(reason){
    console.error(reason);
})
Promise封装AJAX
// const x = new XMLHttpRequest();
// x.open('GET', 'https://api.uomg.com/api/rand.qinghua?format=text');
// x.send();
// x.onreadystatechange = function() {
//     if(x.readyState === 4) {
//         if(x.status >= 200 && x.status < 300) {
//             console.log(x.response);
//         }else {
//             console.error(x.status);
//         }
//     }
// }


//使用 Promise 封装
const p = new Promise((resolve, reject) => {
    const x = new XMLHttpRequest();
    x.open('GET', 'https://api.uomg.com/api/rand.qinghua?format=text');
    x.send();
    x.onreadystatechange = function() {
        if(x.readyState === 4) {
            if(x.status >= 200 && x.status < 300) {
                //成功执行resolve
                resolve(x.response);
            }else {
                //失败执行reject
                reject(x.status); //5种状态 0 1 2 3 4
            }
        }
    }
})

//指定成功或失败的回调
p.then(function(value) {
    console.log(value);
}, function(reason) {
    console.error(reason);
})
Promise-then方法
//创建promise对象
const p = new Promise((resolve, reject)=>{
    setTimeout(()=>{
        //resolve('用户数据');
        reject('出错啦');
    },1000)
});
//调用then方法then方法的逐回结果是 Promise 对象,对象状态由回调函数的执行结果决定
//1.如果回调函数中返回的结果是非promise类型的属性,状态为成功,返回值为对象的成功的值,没有返回值默认为undefined

const result = p.then(value => {
    console.log(value);
    //1.非 promise类型的属性
    // return 'iloveyou';
    //2.是 promise对象
    //return new Promise( (resolve,reject) => {
    //  // resolve( 'ok');
    //  reject( 'error ' );
    // });
    //3.抛出错误
    // throw new Error('出错啦!");
    // throw '出错啦!';
},reason=>{
    console.warn(reason);
})

//链式调用 可杜绝“回调地狱”
p.then(value=>{

}).then(value=>{

});

console.log(result);
Promise实践-读取多个文件
const fs = require('fs');

// fs.readFile('./resources/test.md', (err, data1) => {
//     fs.readFile('./resources/test2.md', (err, data2) => {
//         fs.readFile('./resources/test3.md', (err, data3) => {
//             let result = data1 + '\r\n' + data2 +'\r\n'+ data3;
//             console.log(result);
//         });
//     });
// });

//使用 Promise 实现
const p =new Promise((resolve, reject) => {
    fs.readFile('./resources/test.md', (err, data) => {
        resolve(data);
    });
});

p.then( (value)=> {
    return new Promise( (resolve, reject)=>{
        fs.readFile('./resources/test2.md', (err, data) => {
            resolve([value, data]);
        });
    });
}).then( (value)=> {
    return new Promise( (resolve, reject)=>{
        fs.readFile('./resources/test3.md', (err, data) => {
            //将最后一个压入前两个
            value.push(data);
            resolve(value);
        });
    });
}).then( (value)=> {
    console.log(value.join('\r\n'));
})
Promise-catch方法
const p = new Promise((resolve, reject)=>{
	setTimeout(()=>{
		//设置p 对象的状态为失败,并设置失败的值
        reject("出错啦! ");
	},1000)
});
// p.thep(function(value){}, function(reason){
// 		console.error( reason);
// });
p.catch(function(reason){
	console.warn(reason);
});
Set

ES6提供了新的数据结构Set(集合)。它类似于数组,但成员的值都是唯一的,集合实现了iterator接口,所以可以使用 扩展运算符for…of… 进行遍历,

集合的属性和方法:

  1. size 返回集合的元素个数
  2. add 增加一个新元素,返回当前集合
  3. delete 删除元素,返回boolean值
  4. has 检测集合中是否包含某个元素,返回boolean值
let s = new Set();
let s2 = new Set(['zhou','wu','zhen','wang','zhou']);

//元素个数
//console.log(s2.size);	//4
//添加新的元素
//s2.add('zhang');	//Set(5) {'zhou', 'wu', 'zhen', 'wang', 'zhang'}
//删除元素
//s2.delete('wu');	//true
//console.log(s2.has('zhen'));	//true
//s2.clear();
//console.log(s2);	//Set(0) {size: 0}

for (let v of s2) {
    console.log(v);
}
//zhou
//wu
//zhen
//wang
Set集合实践
let arr = [1,2,3,4,5,4,3,2,1];

//1. 数组去重
let result = [...new Set(arr)];
console.log(result);	//(5) [1, 2, 3, 4, 5]

//2. 交集
let arr2 = [4,5,6,5,6];

let result = [...new Set(arr)].filter(item => {
	let s2 = new Set(arr2);// 4 5 6
	if(s2.has(item)){
		return true;
    }else{
		return false;
	}
});
//写法2
//let result = [...new Set(arr)].filter(item => new Set(arr2).has(item));
console.log(result);	//(2) [4, 5]

//3. 并集
let union = [...new Set([...arr, ...arr2])]
console.log(union);	//(6) [1, 2, 3, 4, 5, 6]

//4. 差集
let diff = [...new Set(arr)].filter(item => !new Set(arr2).has(item));
console.log(diff);	//(3) [1, 2, 3]

Map

ES6提供了 Map数据结构。它类似于对象,也是键值对的集合。但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。Map也实现了iterator接口,所以可以使用 扩展运算符for…of… 进行遍历。

Map的属性和方法:

  1. size 返回Map的元素个数
  2. set 增加一个新元素,返回当前Map
  3. get 返回键名对象的键值
  4. has 检测Map中是否包含某个元素,返回boolean值
  5. clear 清空集合,返回undefined
//声明Map
let m = new Map();

//添加元素
m.set('name','王同学');
m.set('change', function(){
	console.log("你好!!");
});
let key = {
	school: 'USC',
};
m.set(key, ['张三','李四','王五']);
//size
console.log(m.size);	//3

//删除
//m.delete('name');

//获取
//console.log(m.get('change'));	//ƒ (){console.log("你好!!");}
//console.log(m.get(key));	//(3) ['张三', '李四', '王五']

//清空
//m.clear();

//遍历
for(let v of m){
    console.log(v);
    //(2) ['name', '王同学']
	//(2) ['change', ƒ]
	//(2) [{…}, Array(3)]
}

console.log(m);	//Map(3) {'name' => '王同学', 'change' => ƒ, {…} => Array(3)}

class类

ES6提供了更接近传统语言的写法,引入了 Class(类〉这个概念,作为对象的模板。通过class关键字,可以定义类。基本上,ES6的class可以看作只是一个语法糖,它的绝大部分功能,ES5都可以做到,新的 class 写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。

知识点:

  1. class声明类

  2. constructor定义构造函数初始化

  3. extends继承父类

  4. super调用父级构造方法

  5. static定义静态方法和属性

  6. 父类方法可以重写

//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);	//Phone {brand: '华为', price: 5999}

//class写法:
class Phone{
    //构造方法,名字写法固定
    constructor(brand, price) {
        this.brand = brand;
		this.price = price;
    }
    
    //方法必须使用该语法,不能使用 ES5 的对象完整形式
    call(){
        console.log("我可以打电话!!");
    }
}

let onePlus = new Phone('一加', 1999);
onePlus.call();	//我可以打电话!!
console.log(onePlus);

类的静态成员
class Phone{
//静态属性
	static name ='手机';
    static change(){
		console.log("我可以改变世界");
	}
}
let nokia = new Phone();	
console.log(nokia.name);	//undefined
console.log(Phone.name);	//手机

//static标注的属性和方法它属于类而不属于实例对象 
类继承
//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, price);
    this.color = color;
    this.size = size;
}
//设置子级构造函数的原型并修正constructor
smartPhone.prototype = new Phone();
smartPhone.prototype.constructor = smartPhone;
smartPhone.prototype.playGame = function() {
    console.log("我可以玩游戏");
}

const iphone = new smartPhone('苹果', 5999, '黑色', '6.2inch')
console.log(iphone);


//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;
    }
    playGame() {
        console.log("我可以玩游戏");
    }
}
const iphone = new smartPhone('苹果', 5999, '黑色', '6.2inch');
console.log(iphone);
子类对父类方法重写
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;
    }
    playGame() {
        console.log("我可以玩游戏");
    }
    call(){	//子类重写父类中call方法
        console.log("我可以进行视频通话");
    }
}
const iphone = new smartPhone('苹果', 5999, '黑色', '6.2inch')
console.log(iphone);
iphone.call();	//我可以进行视频通话
getter和setter
class Phone {
    get price() {
        console.log("价格属性被读取了");
        return 'price方法返回值';
    }
    
    set price(newVal) {
        console.log("价格属性被修改了");
    }
}
let s = new Phone();
console.log(s.price);
s.price = 'free' //price返回值被修改

只有getter定义只读属性

// 只有getter定义只读属性
class foo {
    constructor(name) {
        this.name = name;
    }

    get name() {
        console.log(`getter函数`);
        return this.name;
    }
}
//Cannot set property name of #<foo> which has only a getter
 let p3 = new foo("李四");

当一个属性只有getter没有setter的时候,我们是无法进行赋值操作的(第一次初始化也不行),这一点需要注意
当没有getter和setter时,就可以正常读写属性

数值扩展

  1. 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(equal(0.1 + 0.2, 0.3));	//true
  1. 二进制和八进制
let b = 6b1010;
let o = 0o777;
let d = 100;
let x= 0xff;
console.log(x);
  1. Number .isFinite检测一个数值是否为有限数
console.log(Number.isFinite(100));	//true
console.log(Number.isFinite(100/0));	//false
console.log(Number.isFinite(Infinity));	//false
  1. Number.isNaN检测一个数值是否为NaN
console.log(Number.isNaN(123));	//false
  1. Number.parseInt Number.parseFloat字符串转整数
console.log(Number.parseInt('5211314love'));	//5211314
console.log(Number.parseFloat('3.1415926神奇'));	//3.1415926
  1. Number.isInteger判断一个数是否为整数
console.log(Number.isInteger(5));	//true
console.log(Number.isInteger(2.5));	//false
  1. Math.trunc将数字的小数部分抹掉
console.log(Math.trunc(3.5));	//3
  1. Math.sign判断一个数到底为正数负数还是零
console.log(Math.sign(100));	//1
console.log(Math.sign(3));	//1
console.log(Math.sign(0));	//0
console.log(Math.sign(-20000));	//-1

对象方法的扩展

1.Object.is 判断两个值是否完全相等

console.log(Object.is(120,120));	//true
console.log(0bject.is(NaN,NaN));	//true
console.log(NaN === NaN);	//false

2.Object.assign对象的合并

const config1 = {
    host: 'localhost',
    port: '3306',
    username: 'root',
    password: 'test',
    test1: 'test1',
}
const config2 = {
    host: 'wlhnet.cn',
    port: '80',
    username: 'wlh',
    password: 'wlh',
    test2: 'test2',
}
console.log(Object.assign(config1, config2));
//{host: 'wlhnet.cn', port: '80', username: 'wlh', password: 'wlh', test1: 'test1', test2: 'test2',}

//有重复项则后一个覆盖前一个,没有则合并

3.Object.setPrototypeOf 设置原型对象Object.getPrototypeOf

const school = {
	name: "USC"
}
const cities = {
	city: ['北京','上海','深圳']
}
Object.setPrototypeOf(school, cities);	//	把cities放到school原型里
console.log(Object.getPrototypeOf(school));	//获取school的原型
console.log(school);

模块化

模块化是指将一个大的程序文件,拆分成许多小的文件,然后将小文件组合起来。

模块化的优势有以下几点:

  1. 防止命名冲突

  2. 代码复用

  3. 高维护性

ES6之前的模块化规范有:

  1. CommonJS => NodeJS、Browserify

  2. AMD => requireJs

  3. CMD => seaJS

ES6模块化语法

模块功能主要由两个命令构成:export和import。

  1. export命令用于规定模块的对外接口

  2. import命令用于输入其他模块提供的功能

通用导入方式:
<!--index.html-->
<script>
	//引入 module1.js 模块内容
	import * as m1 from "./src/js/module1.js";
	//路径要正确,此时 module1.js 的数据都存在变量 m1 里
    console.log(m1);
    
    //引入module2.js,统一暴露
    import * as m2 from "./src/js/module2.js";
    console.log(m2);
    
    //引入module3.js,默认暴露
    import * as m3 from "./src/js/module3.js";
	m3.default.class();
</script>

分别暴露:

//module1.js

export let school = 'USC';

export function class() {
    sonsole.log("我是xx班的");
}

统一暴露:

//module2.js
let school = 'USC';

function class() {
    console.log("我是xx班的");
}

export {school, class};

默认暴露:

//module3.js
export default {
    school: 'USC',
    class: function() {
        console.log("我是xx班的");
    }
}
解构赋值形式:
<!--index.html-->
<script>
	//解构赋值形式引入 module1.js 模块内容
	import {school, class} from "./src/js/module1.js";
    console.log(school, class);
    
    //解构赋值形式引入module2.js,统一暴露
    import {school as usc, class} from "./src/js/module2.js";
    //重名可使用 as 将 school 存入另一变量
    console.log(usc, class);
    
    //解构赋值形式引入module3.js,默认暴露
    import {default as m3} from "./src/js/module3.js";
    //不能直接放 default,必须用 as 存到一个变量
	console.log(m3);
</script>

简便形式,针对默认暴露

<script>
	import m3 from "./src/js/module1.js";
    console.log(m3);
</script>
ES6模块化方式2
<!--index.html-->
<script>
    console.log(m1);
    console.log(m2);
	m3.default.class();
</script>
<script src="./src/js/app.js" type="module"></script>
//入口文件 app.js

//模块移入
import * as m1 from "./module1.js";
import * as m2 from "./module2.js";
import * as m3 from "./module3.js";
babel对ES6模块化代码转换

1.安装工具 babel-cli babel-preset-env browserify(webpack)

(1)初始化npm init --yes

(2)npm i babel-cli babel-preset-env browserify -D

(3)局部安装需加npx npx babel src/js -d dist/js --preset-babel-preset-env

(4)打包 npx browserify dist/js/app.js -o dist/bunble.js

(5)打包完在html页面引入 bunble.js 文件

(6)更改代码需在原文件更改,改完重新转换打包(3)(4)命令。

模块化引入NPM包
import 变量名 from '模块名';

import $ from 'jquery';

ES7 新特性

Array.prototype.includes

lncludes 方法用来检测数组中是否包含某个元素,返回布尔类型值

// includes
const sdmz = ["西游记", "红楼梦", "三国演义", "水浒传"];
//判断
//console.log(sdmz.includes('西游记'));	//true
//console.log(sdmz.includes('金瓶梅'));	//false

指数操作符

在ES7中引入指数运算符**,用来实现幂运算,功能与Math.pow结果相同

// **
console.log(2 ** 10);	//1024
console.log(Math.pow(2, 10));	//1024

ES8 新特性

async 和 await

async和 await两种语法结合可以让异步代码像同步代码一样。

async 函数

  1. async函数的返回值为promise对象。
  2. promise对象的结果由async函数执行的返回值决定。
//async 函数(在函数声明前加 async 就变成了async函数)
async function fn() {
  	//return '王同学';  //1. 即使返回的是字符串,返回的结果也是promise对象
    
    //return ;	//2. 返回的结果不是一个promise类型对象,返回的结果就是成功promise对象
    
    //throw new Error('出错啦!!');	//3. 抛出错误,返回的结果是一个失败的Promise
	
    return new Promise((resolve, reject) => {
        //resolve('成功的数据');	//如果返回的结果为成功promise则函数返回成功的值
        //resolve('失败');	//如果返回的结果为失败promise则函返回失败的值
    });
}
const result = fn();
//console.log(result);	//Promise {<resolved>: '王同学'}

console.log(result); //Promise {<resolved>[[PromiseResult]]:"成功的数据"}

await 表达式

  1. await必须写在 async函数中。
  2. await右侧的表达式一般为promise 对象。
  3. await返回的是promise成功的值。
  4. await的 promise失败了,就会抛出异常,需要通过 trv…catch捕获处理。
const p = new Promise((resolve, reject) => {
    //resolve('用户数据');
    reject('失败啦!!')
});

async function main() {
    try{
        let result = await p;
        console.log(result);
    } catch(e) {
        console.log(e);
    }
}

await与async结合读取文件

const fs = require('fs');

function readTest() {
    return new Promise( (resolve, reject) => {
        fs.readFile('./Promise/resources/test1.md', (err,data) => {
            if (err) reject(err);
            resolve(data);
        });
    });
}

function readTest2() {
    return new Promise( (resolve, reject) => {
        fs.readFile('./Promise/resources/test2.md', (err,data) => {
            if (err) reject(err);
            resolve(data);
        });
    });
}

function readTest3() {
    return new Promise( (resolve, reject) => {
        fs.readFile('./Promise/resources/test3.md', (err,data) => {
            if (err) reject(err);
            resolve(data);
        });
    });
}

async function main() {
    try{
        let test = await readTest();
        let test2 = await readTest2();
        let test3 = await readTest3();

        console.log(test.toString());
        console.log(test2.toString());
        console.log(test3.toString());
    }catch (e) {
        console.log(e);
    }

}
main();

await与async封装AJAX

function sendAJAX(url) {
    return new Promise( (resolve, reject) => {
        const xhr = new XMLHttpRequest();
        xhr.open('GET', url);
        xhr.send();
        xhr.onreadystatechange = function () {
            if ( xhr.readyState === 4 ){
                if(xhr.status >= 200 && xhr.status < 300) {
                    resolve(xhr.response);
                } else {
                    reject(xhr.status);
                }
            }
        };
    });
}

async function main() {
    try{
        let result = await sendAJAX('https://api.uomg.com/api/rand.qinghua?format=text');
        console.log(result);
    }catch (e) {
        console.log(e);
    }
}
main();

Object.values() 和 Object.entries()

  1. Object.values()方法返回一个给定对象的所有可枚举属性值的数组。
  2. Object.entries()方法返回一个给定对象自身可遍历属性 [key,value] 的数组。
const school = {
    name: "USC",
    classes: ['一班','二班','三班'],
    course: ['前端','java','大数据','测试'],  
};

//获取对象所有的键
console.log(Object.keys(school));
//获取对象所有的值
console.log(Object.values(school));

//entries
console.log(Object.entries(school));
//[['name', 'USC'], ['classes', Array(3)], ['course', Array(4)]]


//创建 Map
const m = new Map(Object.entries(school));
console.log(m.get('cities'));//['前端', 'java', '大数据', '测试']

Object.getOwnPropertyDescriptors()

该方法返回指定对象所有自身属性的描述对象

//接上面代码
console.log(Object.getOwnPropertyDescriptors(school));
//打印出来是一个对象,也有键值,键跟传入对象的键一样,值也是一个对象(包含value及属性特性)
//跟用Object.create创建的对象类似
const obj = Object.create(null, {
    name: {
        //设置值
        value: 'USC',
        //属性特性
        writable: true,	//是否可写
		configurable: true,	//是否可删除
        enumerable: true	//是否可枚举
    }
});

ES9 新特性

扩展运算符与rest参数

对象展开:

Rest 参数与spread扩展运算符在 ES6中已经引入,不过 ES6中只针对于数组,

在ES9中为对象提供了像数组一样的rest参数和扩展运算符

//function connect({host, port, username, password}) {
function connect({host, port, ...users}) {
    console.log(host);
    console.log(port);
    //console.log(username);
    //console.log(password);
    console.log(users);	//es9
}

connect({
    host: '127.0.0.1',
    port: '3306',
    username: 'root',	//之后更多参数将存到users变量中
    password: 'root',
});
//127.0.0.1
//3306
//{username: 'root', password: 'root'}

const person1 = {
    name1: '周',
    other: '123'
}
const person2 = {
    name2: '吴',
}
const person3 = {
    name3: '郑',
}
const person4 = {
    name4: '王',
}
const class1 = {...person1, ...person2, ...person3, ...person4};
console.log(class1);//{name1: '周',vother: '123', name2: '吴', name3: '郑', name4: '王'}

正则扩展

命名捕获分组

对分组匹配的结果进行命名方便对结果进行处理

let str = '<a href="http://www.wlhnet.cn">王同学</a>';

//提取 url 与 标签文本
const reg = /<a href="(.*)">(.*)<\/a>/;
const result = reg.exec(str);
console.log(result[0]);	//<a href="http://www.wlhnet.cn">王同学</a>
console.log(result[1]);	//http://www.wlhnet.cn
//groups为undefined

const reg2 = /<a href="(?<url>.*)">(?<text>.*)<\/a>/;
const result2 = reg2.exec(str);
console.log(result2);
//此时groups有值
console.log(result2.groups.url);	//http://www.wlhnet.cn
console.log(result2.groups.text);	//王同学
正则断言
let str = 'WLH22311你是54654这样啊';

//正向断言
const reg = /\d+(?=这)/;
console.log(reg.exec(str));
//['54654', index: 10, input: 'WLH22311你是54654这样啊', groups: undefined]

//反向断言
const reg2 = /(?<=是)\d+/;
console.log(reg2.exec(str));
//['54654', index: 10, input: 'WLH22311你是54654这样啊', groups: undefined]
dotAll模式

dot 有 . 的意思 .在正则中指元字符 (除换行符之外的任意单个字符)。

针对一些html内容,在进行分析和提取数据分析的时候作用非常明显。

//提取字符中电影名称以及对应上映时间存到一个对象里
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>/ ;//需匹配换行
//console.log(reg.exec(str));

const reg2 = /<li>.*?<a>(.* ?)<\/a>.*?<p>(.*?)<\/p>/s;//单个匹配
//console.log(reg2.exec(str));

const reg3 = /<li>.*?<a>(.*?)<\/a>.*?<p>(.*?)<\/p>/gs;//全局匹配
let result;
let data = [];
while(result = reg3.exec(str)){
    console.log(result);
    data.push({title: result[1], time: result[2]});
}
console.log(data);
//[
//  { title: '肖申克的救赎', time: '上映时间:1994-09-10' },
//  { title: '阿甘正传', time: '上映时间:1994-07-06' }
//]

ES10 新特性

Object.fromEntries()

该方法用来创建一个对象 ,方法的参数接收一个二维数组或map

//二维数组
const result = Object.fromEntries([
    ['name', '王同学'],
    ['skills', 'java, js, mysql, css,vue']
]);
console.log(result);	//{name: '王同学', skills: 'java, js, mysql, css,vue'}

//map
const m = new Map();
m.set('name','王同学');
const result2 = Object.fromEntries(m)	//二维数组换为对象
console.log(result2);	//{name: '王同学'}

//对象转为二维数组
const arr = Object.entries({
	name: '王同学',
});
console.log(arr);	//[['name', '王同学'], ]

//Object.fromEntries() 与 Object.entries()可看作逆运算

字符串方法扩展

String.prototype.trimStart()
String.prototype.trimEnd()

指定清除字符串左侧或右侧空白

let str = '   iloveyou   '

console.log(str);
console.log(str.trimStart());
console.log(str.trimEnd());

数组方法扩展

Array.prototype.flat

将多维数组转为低维数组,flat默认值为1(深度为1 ),flat(2)表示转为1维数组,深度为2 。

const arr = [1,2,3,4,[5,6]];
console.log(arr.flat());	//(6) [1, 2, 3, 4, 5, 6]

const arr2 = [1,2,3,4,[5,6,[7,8,9]]];
//参数为深度是一个数字
console.log(arr2.flat(1));	//(7) [1, 2, 3, 4, 5, 6, [7, 8, 9]]
console.log(arr2.flat(2));	//(9) [1, 2, 3, 4, 5, 6, 7, 8, 9]
Array.prototype.flatMap

把Map的结果维度降低。

const arr = [1,2,3,4];
const result = arr.map(item => [item * 10]);
console.log(result);	//(4) [[10], [20], [30], [40]]

const result2 = arr.flatMap(item => [item * 10]);
console.log(result2);	//(4) [10, 20, 30, 40]

Symbol的扩展

Symbol.prototype.description

该属性用来获取Symbol字符串描述

let s = Symbol('王同学');
console.log(s.description);	//王同学

ES11 新特性

私有属性

在面向对象的语法中是一个非常重要的特性,对属性的一种封装,外部无法直接对它进行操作。

class Person {
    name; 
    //私有属性 #标识
    #age; 
    #weight;
    
    constructor(name, age, weight){
        this.name = name;
        this.#age = age;
        this.#weight = weight;
    }
}

const girl = new Person('小红', 18, '43kg');
console.log(girl.name);	//	小红
console.log(gir1.#age);	//Private field '#age' must be declared in an enclosing class
console.log(girl.#weight);

//可以在类的内部定义一个方法去访问
class Person2 {
    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 girl2 = new Person2('小花', 20, '44kg');
girl2.intro();
//小花
//20
//44kg

Promise.allSettled()

该方法接收一个Promise数组,返回的结果也是一个Promise对象,不过返回的结果永远是成功的状态,成功的值是里面每一个Promise他们的状态和结果。

//声明两个promise对象
const p1 = new Promise( (resolve, reject) => {
	setTimeout(()=>{
		resolve('商品数据- 1');
    },1000)
});

const p2 = new Promise( (resolve, reject) => {
	setTimeout(()=>{
		//resolve('商品数据- 2');
        reject('出错啦')
    },1000)
});

const result = Promise.allSettled([p1, p2]);
console.log(result);	//result的值总为成功, 他的值为一个数组,数组中两个对象分别为p1与p2的状态与状态值

const result2 = Promise.all([p1, p2]);	//Promise.all只有当全部成功才会返回成功
console.log(result2);	//p1,p2有一个返回失败则result2失败,result2失败的值为里面返回失败的那个状态的值

他们都用来做批量异步任务的场景,据情况而使用
如果每个异步任务都想知道结果则用Promise.allSettled()
如果每个异步任务都要求成功才能继续往下执行则用Promise.all()

字符串扩展

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);
console.log(result);	//RegExpStringIterator{}

//上面result返回的结果是一个可迭代对象,可用for...of遍历,也可用扩展运算符...展开
for (let v of result) {
    //console.log(v);
    const data = {title: v[1], time: v[2]}
    console.log(data);
    //{title: '肖申克的救赎', time: '上映时间:1994-09-10'}
 	//{title: '阿甘正传', time: '上映时间:1994-07-06'}
}

const arr2 = [...result];
console.log(arr);	//[Array(3), Array(3)]

可选链操作符

?. 当在应对对象类型的参数时,且对象的深度比较深(层级高),有该操作符可以不用再做层级判断。

function main(config) {
    const dbHost = config && config.db && config.db.host;//main未传参数将报错
    console.log(dbHost);	//192.168.1.100
    
    const dbHost2 = config?.db?.host;//未传参数只会返回undefined,不报错,免去层层做判断的烦恼
    console.log(dbHost2);	//192.168.1.100
};

main({
    db: {
        host: '192.168.1.100',
        username: 'root'
    },
    cache: {
        host: '19.168.1.200',
        username: 'admin'
    },
});

动态import

ES6模块化是一个静态模块系统(在写import语句时往往是在入口文件,或者某一模块文件里面写大量import语句,导入很多模块。不能实现按需加载(懒加载)即用时加载,效率会有影响)

动态import加载,html:

<script src=="./js/app.js" type="module"></script>

app.js:

//import * as m1 from "./hello.js";

const btn = document..getElementById("btn");

btn.onclick = function() {
    import('./hello.js').then(module => {
        module.hello();
    });
}

hello.js:

export function hello() {
    alert('Hello');
}

BigInt类型

大整数,主要用来进行更大数值运算

let n = 520n;
console.log(n, typeof(n));

let n = 123;
console.log(BigInt(n));	//123n //只能传整数

//大数值运算
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
//BigInt只能与BigInt进行运算
console.log(BigInt(max) + BigInt(1));		//9007199254740992n
console.log(BigInt(max) + BigInt(2));	//9007199254740993n

绝对全局对象(globalThis)

始终指向全局对象,无论执行环境是什么。如果想对全局对象进行操作,可以忽略环境用globalThis,因为它始终指向全局对象的。

console.log(globalThis);
  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ES6-ES12是JavaScript的不同版本,每个版本都引入了新的特性和改进。以下是一些ES6到ES12的新特性的示例: ES6(2015年): 1. 箭头函数:简化了函数的语法。 2. 模板字面量:使用反引号(`)来创建多行字符串和插入变量。 3. 解构赋值:从对象或数组中提取值并赋给变量。 4. let和const:引入块级作用域的变量声明方式。 5. Promise:处理异步操作的更强大的方式。 ES7(2016年): 1. Array.prototype.includes():判断数组是否包含某个元素。 2. 指数操作符:使用双星号(**)进行指数运算。 ES8(2017年): 1. async/await:更简洁地处理异步操作。 2. Object.values()和Object.entries():从对象中提取值或键值对。 ES9(2018年): 1. Rest/Spread属性:通过...语法来处理函数参数和对象字面量。 2. Promise.prototype.finally():在Promise结束时执行操作。 ES10(2019年): 1. Array.prototype.flat()和Array.prototype.flatMap():用于处理嵌套数组的方法。 2. Object.fromEntries():将键值对列表转换为对象。 ES11(2020年): 1. 可选链操作符(Optional chaining):简化了访问深层嵌套属性的方式。 2. Nullish coalescing操作符:提供了一种默认值的设定方式。 ES12(2021年): 1. Promise.any():在多个Promise中返回最快解决的结果。 2. Logical Assignment Operators:提供了逻辑运算符与赋值的结合方式。 当然,以上仅是一些主要的新特性ES6-ES12还有其他许多有用的功能和语法改进。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值