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";
posted @ 2022-03-16 18:40  苏槿年  阅读(99)  评论(0编辑  收藏  举报