ES6语法新特性
ES介绍
ES全称 EcmaScript,是脚本语言的规范,而平时经常编写的JavaScript,是EcmaScript的一种实现,所以ES新特性其实指的就是JavaScript的新特性
为什么要学习新特性
1.语法简洁,功能丰富
2.框架开发应用
3.前端开发职位要求
ECMA是什么?
ECMA (European Computer Manufacturers Association)中文名称为欧洲计算机制造商协会,这个组织的目标是评估、开发和认可电信和计算机标准。1994年后该组织改名为Ecma国际。
什么是ECMAScript?
ECMAScript是由Ecma国际通过ECMA-262标准化的脚本程序设计语言。
为什么要学习ES6?
- ES6的版本变动内容最多,具有里程碑意义
- ES6加入许多新的语法特性,编程实现更简单、高效
- ES6是前端发展趋势,就业必备技能
let声明常量以及特点
变量不能重复声明
let a = 'su';
let a = 'li';
//Uncaught SyntaxError: Identifier 'a' has already been declared
如果是换做var
就可以
var a = 'su';
var a = 'li';
块儿级作用域,全局,函数,eval
//if ,else, while, for里面也一样
{
let boy = '苏槿年';
}
console.log(boy);
//Uncaught ReferenceError: boy is not defined
//没有块级作用域,相当于注册在全局中
{
var boy = '苏槿年';
}
console.log(boy);
//苏槿年
不存在变量提升
console.log(a);
let a = '苏槿年';
//Uncaught ReferenceError: Cannot access 'a' before initialization
console.log(a);
var a = '苏槿年';
//undefined
//相当于在这之前就声明
//var a ;
//console.log(a);
不影响作用域链
{
let a = '苏槿年';
function fn(){
console.log(a);
}
fn();
}
//苏槿年
const声明常量以及特点
//声明常量(格式)
const a = '123';
console.log(a);
//123
一定要赋初始值
const A;
//Uncaught SyntaxError: Missing initializer in const declaration
一般常量使用大写(潜规则)
const A = 123;
//小写也不会报错
常量的值不能修改
BOY = 'SUJINNIAN';
块儿级作用域
{
const b = '123';
}
console.log(b);
//const.html:14 Uncaught ReferenceError: b is not defined
对于数组和对象的元素修改,不算做对常量的修改,不会报错
const team = ['A','B','C','D'];
team.push('E');
const team = ['A','B','C','D'];
team = 'E';
//const.html:18 Uncaught TypeError: Assignment to constant variable.
变量结构赋值
数组的结构
const team = ['A','B','C','D'];
let [a,b,c,d] = team;
console.log(a);
console.log(b);
console.log(c);
console.log(d);
//A
//B
//C
//D
对象的结构
const su ={
name:'苏槿年',
age:18,
sex:function(){
console.log("性别:男");
}
};
let {name,age,sex} = su;
console.log(name);
console.log(age);
console.log(sex);
/*
苏槿年
18
ƒ (){
console.log("性别:男");
}
*/
const su ={
name:'苏槿年',
age:18,
sex:function(){
console.log("性别:男");
}
};
let {sex} = su;
sex();
//性别:男
//可以单独将sex拧出来,方便操作
模板字符串
引入新的声明字符串的方式 ` ` , ' ', " "
声明
let str =`我也是一个字符串哦!`;
console.log(str, typeof str);
//我也是一个字符串哦! string
内容中可以直接出现换行符
let str =`<ul>
<li>沈腾</li>
<li>玛丽</li>
<li>魏翔</li>
<li>艾伦</li>
</ul>`;
//不会报错
变量拼接
let lovest ="学习";
let out = `${lovest}本就是逆水行舟!!`;
console.log(out);
//学习本就是逆水行舟
对象的简化写法
let name = '苏槿年';
let change = function () {
console.log('欢迎来到我的博客!!');
}
const blog = {
name,
change,
}
console.log(blog);
let name = '苏槿年';
let change = function () {
console.log('欢迎来到我的博客!!');
}
const blog = {
name,
change,
improve(){
console.log("这里可以学到前端基础!!")
}
}
console.log(blog);
箭头函数
ES6允许使用「箭头」(=>)定义函数。
let fn = (a,b) =>{
return a+b;
}
//调用函数
let result = fn(1,2);
console.log(result);
//3
this是静态的. this始终指向函数声明时所在作用域下的 this的值
function getName() {
console.log(this.name);//指向windows
}
let getName2 = () => {
console.log(this.name);//指向windows
}
//设置windows对象的name属性
window.name = '苏槿年';
const school = {
name: "sujinnian"
}
//直接调用
getName();
getName2();
//苏槿年
//苏槿年
call方法调用
function getName() {
console.log(this.name);//指向windows
}
let getName2 = () => {
console.log(this.name);//指向windows
}
//设置windows对象的name属性
window.name = '苏槿年';
const school = {
name: "sujinnian"
}
//call方法调用
getName.call(school);
getName2.call(school);
//sujinnian
//苏槿年
不能作为构造实例化对象
let Person = (name, age) => {
this.name = name;
this.age = age;
}
let me = new Person('xiao' ,30);
console.log(me);
//Uncaught TypeError: Person is not a constructor
不能使用arguments变量
let fn = () => {
console.log(arguments);
}
fn(1, 2, 3);
//Uncaught ReferenceError: arguments is not defined
箭头函数的简写
省略小括号,当形参有且只有一个的时候
let add = n => {
return n + n;
}
console.log(add(9));
//18
省略花括号,当代码体只有一条语句的时候;此时return必须省略
而且语句的执行结果就是函数的返回值
let pow = n=> n*n;
console.log(pow(8));
//64
实例:点击div后两秒变成粉色
<head>
<style>
div {
width: 200px;
height: 200px;
background-color: blue;
}
</style>
</head>
<body>
<div id="ad"></div>
<script>
//传统的解决方法
//获取元素
let ad = document.getElementById('ad');
//绑定事件
ad.addEventListener("click",function(){
//保存this的值
let _this = this;
//定时器
setTimeout(function(){
_this.style.background = 'pink';
},2000);
})
</script>
</body>
也可以通过箭头函数方法实现
<head>
<style>
div {
width: 200px;
height: 200px;
background-color: blue;
}
</style>
</head>
<body>
<div id="ad"></div>
<script>
//获取元素
let ad = document.getElementById('ad');
//绑定事件
ad.addEventListener("click",function(){
//定时器
setTimeout(() => {
this.style.background = 'pink';
},2000);
})
</script>
</body>
箭头函数适合与this 无关的回调.定时器,数组的方法回调
箭头函数不适合(能用)与this 有关的回调,事件回调,对象方法
函数参数赋值初始值
形参初始值,具有默认值的参数,一般位置要靠后
function add(a, c, b = 10) {
return a + b + c;
}
let result = add(1, 2);
console.log(result);
//13
function add(a, c = 10, b) {
return a + b + c;
}
let result = add(1, 2);
console.log(result);
//NaN
与解构赋值结合
function connect({ host = "127.0.0.1", username, password, port }) {
console.log(host)
console.log(username)
console.log(password)
console.log(port)
}
connect({
host: 'sujinnian',//如果没有定义就会显示127.0.0.1
username: 'root',
password: 'root',
port: 5500
})
//sujinnian
//root
//root
//5500
rest参数
ES6 引入 rest参数,用于获取函数的实参,用来代替arguments
//ES5获取实参的方式
function date() {
console.log(arguments);
}
date('苏','槿','年');
//返回的是对象
function date(...args) {
console.log(args);
}
date('苏','槿','年');
//返回的是数组
rest参数必须要放到参数最后
function fn(a, b, ...args) {
console.log(a);
console.log(b); console.log(args);
}
fn(1, 2, 3, 4,5,6);
扩展运算符
『...』扩展运算符能将『数组』转换为逗号分隔的『参数序列』
//声明一个数组
const name = ['苏','槿','年'];
//声明一个函数
function blog(){
console.log(arguments);
}
blog(name);
//声明一个数组
const name = ['苏','槿','年'];
//声明一个函数
function blog(){
console.log(arguments);
}
blog(...name);
可以用于数组合并
const a = ['好','好'];
const b = ['学','习'];
const student = [...a,...b]
console.log(student)
数组的克隆
const a = ['好','好','学','习'];
const b = [..a];
const student = [b]
将伪数组转为真正的数组
<body>
<div></div>
<div></div>
<div></div>
<script>
const divs = document.querySelectorAll( "div" );
const divArr = [...divs];
console.log(divArr);
</script>
Symbol基本使用
ES6引入了一种新的原始数据类型 Symbol,表示独一无二的值。它是JavaScript语言的第七种数据类型,是一种类似于字符事的数据类型。
- Symbol特点
- Symbol的值是唯一的,用来解决命名冲突的问题
- Symbol值不能与其他数据进行运算
- Symbol定义的对象属性不能使用for...in循环遍历,但是可以使用Reflect.ownKeys来获取对象的所有键名
let c = Symbol.for('苏槿年');
let d = Symbol.for('苏槿年');
console.log(c === d)
//true
Symbol创建对象属性
let game = {
name: "端游",
[Symbol('英雄联盟')]: function () {
console.log("召唤师峡谷")
},
[Symbol('CSGO')]: function () {
console.log("B点有人!!");
}
}
console.log(game)
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 | 创建衍生对象时,会使用该属性 |
迭代器
迭代器(lterator)是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署lterator接口,就可以完成遍历操作。
-
ES6创造了一种新的遍历命令for...of循环,lterator接口主要供for...of消费
-
原生具备iterator接口的数据(可用for of 遍历)
- Array
- Arguments
- Set
- Map
- String
- TypedArray
- NodeList
-
工作原理
- 创建一个指针对象,指向当前数据结构的起始位置
- 第一次调用对象的next方法,指针自动指向数据结构的第一个成员
- 接下来不断调用next方法,指针一直往后移动,直到指向最后一个成员
- 每调用next方法返回一个包含value和 done属性的对象
注:需要自定义遍历数据的时候,要想到迭代器。
迭代器自定义遍历对象
const blog = {
name:"博客园",
stu:[
'苏',
'槿',
'年'
],
[Symbol.iterator](){
let index = 0;
let _this = this;
return{
next:function(){
if(index < _this.stu.length){
const result = { value: _this.stu[index],done:false};
index++;
return result;
}else{
return{value:undefined,done:true};
}
}
}
}
}
for (let v of blog){
console.log(v)
}
//苏
//槿
//年
生成器
生成器定义
生成器函数是ES6提供的一种异步编程解决方案,语法行为与传统函数完全不同
生成器其实就是一个特殊的函数,异步编程,纯回调函数
function* gen() {
console.log("hello generator")//没有执行
}
let iterator = gen();
console.log(iterator);
function* gen() {
console.log("hello generator")
}
let iterator = gen();
iterator.next();
//hello generator
function* gen() {
yield '苏';
yield '槿';
yield '年';
}
let iterator = gen();
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
生成器函数参数
next中的参数将作为yield整体语句的返回结果使用
function* gen(arg) {
console.log(arg);
let one = yield '苏';
console.log(one);
let two = yield '槿';
console.log(two);
let three = yield '年';
console.log(three);
}
let iterator = gen('AAA');//整体传参
console.log(iterator.next());
console.log(iterator.next('BBB'));//next传参
console.log(iterator.next('CCC'));
console.log(iterator.next('DDD'));
生成器实例
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();
}, 1080)
}
function two() {
setTimeout(() => {
console.log(222);
iterator.next();
}, 1080)
}
function three() {
setTimeout(() => {
console.log(333);
iterator.next();
}, 1080)
}
function* gen() {
yield one();
yield two();
yield three();
}
//调用生成器
let iterator = gen();
iterator.next();
Promise
Promise是ES6引入的异步编程的新解决方案。语法上 Promise是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果。
- Promise构造函数:Promise (excutor) {}
- Promise.prototype.then方法
- Promise.prototype.catch方法
发送AJAX请求
const p = new Promise((resolve,reject) => {
//创建对象
const xhr = new XMLHttpRequest();
//初始化
xhr.open("GET", "https://api.apiopen.top/getJoke");
//发送
xhr.send();
//绑定事件,处理响应结果
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(function(value){
console.log(value);
},function(reason){
console.error(reason);
});
Promise.prototype.then方法
const p = new Promise(function(resolve,reject){
setTimeout(function(){
let data = '数据库中的用户数据';
//resolve
resolve(data);
},1000);
});
//调用 promise 对象 then 方法
//then方法的逐回结果是 Promise对象,对象状态由回调函数的执行结果决定
//如果回调函数中返回的结果是非promise类型的属性
p.then(function(value){
console.log(value);
},function(reason){
// console.error(reason)
})
Promise-catch方法
const p = new Promise((resolve, reject) => {
setTimeout(() => {
//设置p对象的状态为失败,并设置失败的值
reject("出错啦!");
}, 1000)
});
// p.then(function (value) { }, function (reason) {
// console.error(reason);
// });
p.catch(function(reason){
console.warn(reason);
});
Set
ES6提供了新的数据结构set(集合)。它类似于数组,但成员的值都是唯一的,集合实现了iterator 接口,所以可以使用扩展运算符和 for ...of... 进行遍历,集合的属性和方法:
//声明一个set
let s = new Set();
let s2 = new Set(['2', '5', '6', '2', '1']);
//去重
console.log(s2);
//元素个数
//console.log(s2.size);
//添加新的元素
//s2.add('3');
//删除元素
// s2.delete('坏事儿');
//检测
// console.log(s2.has('6'));
//清空
// s2.clear();
Set集合实践
求数组的,交集,并集,补集
let arr = [1, 2, 3, 4, 5, 4, 3, 2, 1];
//1.数组去重
// let result = [ ...new Set(arr)];
// console.log(result);
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;
// }
// });
// let result = [...new Set(arr)].filter(item => new Set(arr2).has(item));
// console.log(result);
//并集
let union = [ ...new Set([ ...arr, ...arr2])];
console.log(union);
//补集
let diff = [...new Set(arr)].filter(item => !(new Set(arr2).has(item)));
console.log(diff);
Map的介绍与API
ES6提供了Map数据结构。它类似于对象,也是键值对的集合。但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。Map也实现了iterator接口,所以可以使用 扩展运算符 和 for ...of... 进行遍历。
Map的属性和方法:
- size 返回Map的元素个数
- set 增加一个新元素,返回当前Map
- get 返回键名对象的键值
- has 检测Map中是否包含某个元素,返回boolean值
- clear 清空集合,返回undefined
//声明Map
let m = new Map();
//添加元素
m.set('name', '苏槿年');
m.set('change', function () {
console.log("欢迎观看本篇文章!!");
});
let key = {
school: 'sujinnian'
};
m.set(key, ['北京', '上海', '深圳']);
//size
//console.log(m.size);
//删除
// m.delete('name');
//获取
//console.log(m.get( 'change' ));
//console.log(m.get(key));
//清空
// m.clear();
//遍历
for (let v of m) {
console.log(v);
}
console.log(m)
class类
ES6提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。基本上,ES6的class可以看作只是一个语法糖,它的绝大部分功能,ES5都可以做到,新的 class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。
知识点:
- class 声明类
- constructor 定义构造函数初始化
- extends 继承父类
- super 调用父级构造方法
- static 定义静态方法和属性
- 父类方法可以重写
class Phone {
//构造方法 名字不能修改
constructor(brand, price) {
this.brand = brand;
this.price = price;
}
//方法必须使用该语法,不能使用ES5的对象完整形式
call() {
console.log("我可以打电话!!");
}
}
let onePlus = new Phone( "1+",1999);
console.log(onePlus);
静态成员
class Phone {
//静态属性
//static标注的属性和方法,属于类,而不属于实例对象
static name = '手机';
static change() {
console.log("我可以改变世界");
}
}
let nokia = new Phone();
console.log(nokia.name);
console.log(Phone.name);
构造函数继承
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;
}
//设置子级构造函数的原型
SmartPhone.prototype = new Phone;
SmartPhone.prototype.constructor = SmartPhone;
//声明子类的方法
SmartPhone.prototype.photo = function () {
console.log("我可以拍照")
}
SmartPhone.prototype.playGame = function () {
console.log("我可以玩游戏");
}
const chuizi = new SmartPhone('锤子', 2499, '黑色', '5.5inch ');
console.log(chuizi);
ES6时的继承方法
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() {
consolle.log("拍照");
}
playGame() {
console.log("玩游戏");
}
}
const xiaomi = new SmartPhone('小米', 799, '黑色', '4.7inch');
console.log(xiaomi);
子类对父类方法的重写
子类不可以直接去调用父类的同名方法
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() {
consolle.log("拍照");
}
playGame() {
console.log("玩游戏");
}
call(){
console.log('视频通话')
}
}
const xiaomi = new SmartPhone('小米', 799, '黑色', '4.7inch');
xiaomi.call();//调用子类的call方法
getter和setter
class Phone {
get price() {
console.log("价格属性被读取了"); return 'iloveyou ';
}
set price(newVal) {
console.log('价格属性被修改了');
}
}
//实例化对象
let s = new Phone();
s.price = 'free' ;
数值扩展
Number.EPSILON 是JavaScript 表示的最小精度
EPSILON属性的值接近于 2.2204460492503130808472633361816E-16
function equal(a, b) {
if (Math.abs(a - b) < Number.EPSILON) {
return true;
} else {
return false;
}
}
console.log(0.1 + 0.2 === 0.3); //false
console.log(equal(0.1 + 0.2,0.3))//true
Number.isFinite检测一个数值是否为有限数
console.log(Number.isFinite(100));//true
console.log(Number.isFinite(100/0));//false
Number.isNaN检测一个数值是否为NaN
console. log(Number.isNaN(123));//false
Number.parseInt Number.parseFloat字符串转整数
console.log(Number.parseInt( '2345abcdef ' ));//2345
console.log(Number.parseFloat( '3.1415926神奇'));//3.1415926
Number.isInteger判断一个数是否为整数
console.log(Number.isInteger(5));//true
console.log (Number.isInteger(2.5));//false
Math.trunc 将数字的小数部分抹掉
console.log(Math.trunc(3.5));//3
Math.sign判断一个数到底为正数,负数,还是零
console.log(Math.sign(100))//1
console.log(Math.sign(0));//0
console.log(Math.sign(-56));//-1
对象扩展
Object.is 判断两个值是否完全相等
console.log(Object.is(120,120));// true
console.log(Object.is(NaN,NaN));// true
console.log(NaN === NaN);// false
Object.assign对象的合并
const config1 = {
host: 'localhost',
port: 5500,
name: 'root',
pass: 'root'
};
const config2 = {
host: 'https://www.cnblogs.com/wzx-blog/',
port: 3306,
name: 'sujinnina.com',
pass: 'abcdefgf',
}
console. log(Object.assign(config1, config2));
//相同属性:config2的数据会将config1覆盖
Object.setPrototypeOf设置原型对象 Object.getPrototypeOf
const blog = {
name: "苏槿年"
}
const cities = {
address: ["北京", "上海", "深圳"]
}
Object.setPrototypeOf(blog, cities);
console.log(Object.getPrototypeOf(blog));
console.log(blog);
模块化
模块化是指将一个大的程序文件,拆分成许多小的文件,然后将小文件组合起来。
模块化的好处
模块化的优势有以下几点:
- 防止命名冲突
- 代码复用
- 高维护性
模块化规范产品
ES6之前的模块化规范有:
- CommonJs => NodeJS、Browserify
- AMD => requireJs
- CMD => seaJS
ES6模块化语法
模块功能主要由两个命令构成:export和 import。
-
export命令用于规定模块的对外接口
-
import命令用于输入其他模块提供的功能
export命令使用
//分别暴露
export let blog = '苏槿年';
export function teach() {
console.log("ABCDEFG");
}
------------------------------
//统一暴露
let blog ='苏槿年';
function findJob(){
console.log("12456789!!");
}
export {blog,findJob};
-------------------------------
//默认暴露
export default {
blog: "苏槿年",
change: function () {
console.log("hello!!!")
}
}
import命令使用
//通用引入
import * as A from "./src/js/A.js";
//解构赋值形式
import {blog, teach} from "./src/js/B.js";
import {blog as BLOG,findJob} from "./src/js/B.js";
import {default as C} from "./src/js/C.js ";
//简便形式;针对默认暴露
import C from "./src/js/C.js";