ES6新特性速览

2 篇文章 0 订阅

ES6新特性速览


ECMAScript,是由ECMA国际化标准组织制定的一项脚本语言的标准化规范,而平时经常编写的JavaScript,是ECMAScript的一种实现,所以ES新特性其实指的就是 JavaScript的新特性

ES6是一个泛指,2015及后续的版本

年份版本
2015年6月ES2015
2016年6月ES2016
2017年6月ES2017
2018年6月ES2018
2019年6月ES2019
2020年6月ES2020
2021年6月ES2021

新特性:

  • 语法简洁
  • 框架开发应用

什么是ECMA?

Ecma International(正式名称是 European Computer Manufacturers Association,欧洲计算机制造商协会)是一个开发计算机硬件、通信和程序语言标准的非盈利组织。

在网络上该组织因维护 JavaScript 语言的核心规范 the ECMA-262 specification即 ECMAScript而为人所知。

ECMA的第39号技术专家委员会(Technical Committee 39,简称TC39)负责制订ECMAScript标准,成员包括Microsoft、Mozilla、Google等大公司。TC39的总体考虑是,ES5与ES3基本保持兼容,较大的语法修正和新功能加入,将由JavaScript.next完成。

ES6是继ES5之后的一次主要改进,语言规范由ES5.1时代的245页扩充至600页。具有里程碑意义。ES6增添了许多必要的特性,例如:模块和类,以及一些实用特性,例如Map、Set、Promise、生成器(Generator)等。尽管ES6做了大量的更新,但是它依旧完全向后兼容以前的版本。 其目标是将 JavaScript打造为企业级开发语言,使他能够开发复杂的大型应用程序。

let

特点

  1. 使用let声明的变量具有块级作用域

    //简单的说就是{}产生的作用域
    if(true){
       let a = 10;
        console.log(a);//10
       }
    console.log(a);// a is not defined
    //防止循环变量变成全局变量
        for(var i=0;i<2;i++){
        }
        console.log(i);//2
    	for(let j=0;j<2;j++){
        }
        console.log(j);//j is not defined
    
  2. 变量不能重复声明

  3. 不存在变量提升

    console.log(a);//Cannot access 'a' before initialization再初始化之前无法访问a
    let a = 100;
    console.log(b);//undefined
    var b = 100;
    
  4. 不影响作用域链

  5. 具有暂时性死区

var num = 10;
if(true){
    //不会向上一级作用域查找num,因为本级作用域中用let声明了num
   console.log(num);//Cannot access 'num' before initialization
    let num = 20;
   }

const

  1. 用于声明常量(存储数据对应的内存地址不可更改)
  2. 具有块级作用域
  3. 一定要赋初值
  4. 一般常量大写
  5. 对数组和对象的修改不算对常量的修改,不会报错
const PI = Math.PI;
        console.log(PI);

        // 对数组和对象元素的修改不算对常量的修改,不会报错
        const arr = [1,2,3,4,5,6];
        arr.push(7);
        console.log(arr)

let、const、var的区别

varletconst
函数作用域块级作用域块级作用域
变量提升不存在变量提升不存在变量提升
值可以更改值可以更改值不可以更改
函数的定义、数学公式中一些恒定的值、

变量解构赋值

解构:

  • 分解数据结构

负值:

  • 为变量赋值

ES6允许按照一一对应的方式从数组或者对象中提取值,并对变量进行赋值

这被称为解构赋值,可以更加简便的从数组或者对象中提取值。

1.数组的解构

//数组结构允许按照一一对应的关系从数组中提取值,然后赋值给变量
let [a,b,c] = [1,2,3];
console.log(a);//1
console.log(b);//2
console.log(c);//3
//如果不是一一对应的话
let [a,b,c,d] = [1,2,3];
console.log(a);//1
console.log(b);//2
console.log(c);//3
console.log(d);//undefined

2.对象的解构

对象结构实际上是属性匹配,变量的名字匹配对象中属性的名字

如果匹配成功就将对象中属性的值赋给变量

//对象结构允许使用变量的名字匹配对象的属性,匹配成功就将对象的属性赋值给变量
let people = {name:"yxj",age:18,say:function(){console.log("i can");}};
let {name,age,say} = people;
console.log(name);//yxj
console.log(age);//18
say();//i can
//可以使用别名
let {name:myName,age:myAge,say:MySay} = people;
console.log(myName);//yxj
console.log(myAge);//18
MySay();//i can

模板字符串

  • 内容中可以直接换行
  • 直接进行变量拼接${}
 let str = `
        <ul>
           <li>li1</li>
           <li>li2</li>
           <li>li3</li>
        </ul>`;
console.log(`我输出的内容是:${str}`);

简化对象写法

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

let name = '尚硅谷';
        let change = function(){
            console.log("我可以改变!");
        }
        const school ={
            // 加入name 和 change属性
            name,//等效于name:name,change:change
            change,
            // improve:function (){
            //     console.log('我们可以提高你的技能');
            // },
            // 简化写法
            improve(){
                console.log('我的技能得到提高了!');
            }
        }
        console.log(school);

箭头函数

在ES6里允许使用()=>{}来定义函数

特性:

1.this是静态的(它不绑定this),始终是指向函数声明时所在作用域下的this的值,无法使用call、apply等函数方法改变

const obj = {name:"yxj"}
function fn(){
    console.log(this);//谁调用fn this就是谁
    return ()=>{
        console.log(this);//应该指向定义它的区域的this 谁调用fn this就是谁
    }
}
fn.call();//window
const newFn = fn.call(obj);
newFn();//obj

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

3.不能使用 arguments

4.形参有且只有一个的时候 可以简写

let add = a=> a+a;
console.log(add(2));//4

5.允许将一个不定数量的参数表示为一个数组

function sum(first,...second){
    console.log(first);//1
    console.log(second);//他是一个数组,可以使用数组的方法[2, 3, 4]
}
sum(1,2,3,4);

测试this指向

        //var age = 100;
        var obj = {
            let:20,
            //obj是一个对象,不能产生作用域
            say:()=>{
                //箭头函数没有自己的this它指向的是定义他的区域的this
                console.log(this.age);
            }
        }
        // obj是一个对象,不能产生作用域,相当于调用了window.age
        obj.say();//undefined 

        var obj2 ={
            age:16,
            say:function(){
                console.log(this.age);
            },
        }
        obj2.say();//16

函数参数的默认值设置

ES6允许给函数参数设置初始值

  1. 形参初始值
// 一般将有默认值的参数放后面
        function add(a,b,c=10){
            // 
            return a+b+c;
        }
        let result = add(1,2);
        console.log(result);
        // 
        function connect(option){
            // 每次都要写option
            let host = option.host;
            let username = option.username;
        }
        // 与解构赋值结合简化写法
        function connect2(host='http://127.0.0.1',username,password ,port){
            console.log(host);
            console.log(username);
            console.log(password);
            console.log(port);
        }
        connect({
            host:'localhost',
            username:'root',
            password:'123456',
            port:3306
        });

rest(剩余)参数

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

当函数实参个数大于形参个数时,可以将剩余的实参放到一个数组(是真正的数组,不是数伪组)中

function sum(first,...arg){
    console.log(first);//10
    console.log(arg);//[20,30]
    console.log(arg instanceof Array);//true
}
sum(10,20,30);

扩展运算符

. . .

拆分数组

扩展运算符能将数组转换为逗号分割的参数序列后,将参数序列又放在了console.log方法中,参数序列中的逗号会被当成方法的参数分隔符

let array = [1,2,3];
// 为什么输出结果没有逗号?
console.log(...array);//1 2 3
// 因为参数序列中的逗号会被当成方法的参数分隔符
console.log(1,2,3);//1 2 3

扩展运算符的应用

  • 合并数组
//方法1
let arr1 = [1,2,3];
let arr2 = [4,5,6];
let arr3 = [...arr1,...arr2];// [ 1, 2, 3, 4, 5, 6 ]
//方法2
arr1.push(...arr2);
console.log(arr1);//[ 1, 2, 3, 4, 5, 6 ]
  • 将伪数组转换为真正的数组
let oDivs = document.querySelectorAll("div");
console.log( oDivs instanceof Array);//false
oDivs = [...oDivs];
console.log( oDivs instanceof Array);//true
  • 实现数组的浅拷贝

补充:

Array.from()
方法也可以将伪数组或可遍历的对象转为真正的数组

该方法可以接受两个参数

  1. 要转换的对象(伪数组)

    let arryLike = {
        "0":"a",
        "1":"b",
        "2":"c",
        length:3//必须要有length属性
    }
    let arr = Array.from(arryLike);
    console.log(arr);//[ "a", "b", "c" ]
    
  2. 一个函数,对数组中的元素进行加工处理,数组中有多少个元素,函数就会执行多少次,函数有一个形参,代表要处理的值,只需要将要处理的结果返回即可

let arryLike = {
    "0":"1",
    "1":"2",
    "2":"c",
    length:3
}
let newArr = Array.from(arryLike,(item)=>{
    return item*2;
});
console.log(newArr);//[ 2, 4, NaN ]

Symbol

ES6引入了一种新的原始(基本)数据类型,表示独一无二的值。他是JavaScript语言的第七种数据类型,是一种类似于字符串的数据类型。

Symbol的特点

  • Symbol的值是唯一的,用来解决命名冲突的问题
  • Symbol的值不能与其他数据进行运算
  • Symbol定义的对象属性不能使用for…in循环遍历,但是可以使用Reflect.ownKeys来获取对象的所有键名

创建一个 Symbol

  • 方法1

    let s = Symbol();
    console.log(s,typeof s);//Symbol() symbol
    
  • 方法2

    // yxj 是一个描述字符串,描述它是为谁设置的,作用相当于一个注释
    //此时s1,s2是一个函数
    let s1 = Symbol("yxj");
    let s2 = Symbol("yxj");
    console.log(s1 === s2);//false
    
  • 方法3

    //此时s3是一个对象
    let s3 = Symbol.for("yxj");
    let s4 = Symbol.for("yxj");
    console.log(s3,typeof s3);//Symbol("yxj") symbol
    console.log(s3 === s4);//true
    

Symbol的作用

  • 给对象和属性添加方法

    //向game对象添加up、down方法
    let game ={
        up:function(){
            console.log("我是原生的up");
        },
        down:function(){
            console.log("我是原生的down");
        },
        // 原生的添加方式
        [Symbol("say")]:function(){
            console.log("我是原生的Symbol");
        }
    }
    //先声明一个对象
    let methods= {
        up:Symbol(),
        down:Symbol()
    }
    //通过该方法向原来的对象里添加方法,不会破环对象原有的属性
    game[methods.up] = function(){
        console.log("我是新添加的up");
    }
    game[methods.down] = function(){
        console.log("我是新添加down");
    }
    console.log(game);
    /**
     *  down: function down()​
        up: function up()​
        Symbol(say): function say()​
        Symbol(): function methods.up()​
        Symbol(): function methods.down()
    */
    

Symbol的内置属性

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

  • 其实就是Symbol的属性

  • 它用来做对象的属性

  • 通过对这些属性的设置来改变对象在特定场景下的表现结果

Symbol的内置值描述
Symbol.hashInstance(这个整体将作为对象的属性)当其他对象使用instanceof运算符判断该对象的实例时,会调用这个方法
Symbol.isConcatSpreadable对象的Symbol.isConcatSpreadable属性等于的是一个布尔值,表示该对象用于用于Array.prototype.concat()时,是否可以展开
Symbol.unscopables指定了使用with关键字时,哪些属性会被with环境排除
Symbol.match当执行Symbol.match(Object)时如果属性存在会调用它,返回该方法的返回值
Symbol.repalce当该对象被Symbol.repalce(Object)方法调用时,会返回该方法的返回值
Symbol.search当该对象被Symbol.search(Object)方法调用时,会返回该方法的返回值
Symbol.spilt当该对象被Symbol.spilt(Object)方法调用时,会返回该方法的返回值
Symbol.iterator对象进行for…of循环遍历,会调用Symbol.iterator方法,返回该对象的默认遍历器
Symbol.toPrimitive该对象转为原始类型的值时,会调用这个方法,返回该方法对应的原始类型值
Symbol.species创建衍生对象时,会使用该属性
  • Symbol.hashInstance
  • 可以自己控制类型检测
class Person{
    // 该方法和其他方法不一样,有自动执行的场景,
    static [Symbol.hasInstance](param){//可以把o这个对象传递进来
        console.log(param);//{}
        console.log("我被用来检测类型了");
        // 可以自动控制类型检测
        return true;
    }
}
let o ={};
console.log(o instanceof Person);//true
  • Symbol.isConcatSpreadable

    当使用concat方法对数组进行合并的时候,可以通过Symbol.isConcatSpreadable属性,设置合并数组的值能不能展开

const arr = [1,2,3];
const arr2 =[4,5,6];
console.log(arr.concat(arr2));//[ 1, 2, 3, 4, 5, 6 ]
arr2[Symbol.isConcatSpreadable] = false;//用于控制值是否可以展开
console.log(arr.concat(arr2));//[ 1, 2, 3, [4,5,6] ]

迭代器

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

  • 再js里Iterator接口指的是对象里的一个属性,该属性的名字是Symbol.Iterator

  • ES6创造了一种新的遍历命令for…of循环,Iterator接口主要提供for…of消费

  • 原生具备Iterator接口的数据结构(可用for…of遍历)

    1. Array
    2. arguments
    3. Set
    4. Map
    5. String
    6. TypedArray
    7. NodeList
  • 工作原理(为什么Symbol.Iterator能够实现循环遍历)

    1. 创建一个指针对象,指向当前数据结构的起始位置
    2. 第一次调用对象的next方法(返回对象身上的一个方法),指针会自动指向数据结构的第一个成员,将结果返回给我们
    3. 接下来不断调用next方法(每次调用都会返回新的值),指针一直往后移动,直到指向最 后一个成员
    4. 每次返回时都会返回一个对象,该对象包含了value和done属性,done是一个是否完成的状态(done:)done为真时返回undefined,并结束循环
const name =["yxj","lqy","son","girl"];
// 使用for...of遍历,保存的是键值
for(let v of name){
    // console.log(v);//yxj lqy son girl
}

//使用for...of遍历,保存的是键名
for(let n in name){
    console.log(n);//0 1 2 3
}

// 为什么数组可以使用for...of遍历
//因为数组的原型上有Symbol(Symbol.iterator)这个属性: function values()
console.log(name);//Symbol(Symbol.iterator): function values()

迭代器的应用

  • 需要自定义遍历数据时,就要用到迭代器

    const obj = {
        name:"yxj",
        game:[
            "a",
            "b",
            "c",
            "d"
        ],
        // 使用迭代器自定义遍历数据
        [Symbol.iterator](){
            // 定义索引变量
            let index = 0;
            let that = this;
            return{
                next:function(){
                    if(index<that.game.length){
                        const result = {value:that.game[index],done:false};
                        // 下标自增
                        index++;
                        // 返回结果
                        return result;
                    }else{
                        return {value:undefined,done:true};
                    }
                }
            }
        }
    }
    //遍历出game数组的值
    obj.game.forEach((item)=>{//但是不符合面向对象的思想
        // console.log(item);//a b c d
    })
    // 要使用for of遍历,且返回值是数组的成员
    for(let v of obj){
        console.log(v);//a b c d
    }
    

生成器

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

  • 之前的异步编程(node fs、ajax、mongodb)的实现:纯回调函数

  • 生成器函数的声明和执行方式比较特殊

function * generator(){
    console.log("我是生成器函数");
}
let iterator = generator();
console.log(iterator);//Generator {  } 
//是一个迭代器对象,可以使用next方法
iterator.next();
  • 生成器函数的yield语句

    算是函数代码的分隔符

function * generator(){
    console.log("代码块1");
    yield '我是函数代码的分隔符1';
    console.log("代码块2");
    yield '我是函数代码的分隔符2';
    console.log("代码块3");
    yield '我是函数代码的分隔符3';
    console.log("代码块4");
}
  • yield语句,由next方法控制执行
//三个分隔符产生四块代码
function * generator(){
    console.log("代码块1");
    yield '我是函数代码的分隔符1';
    console.log("代码块2");
    yield '我是函数代码的分隔符2';
    console.log("代码块3");
    yield '我是函数代码的分隔符3';
    console.log("代码块4");
}
let iterator = generator();
// iterator.next();//代码块1
// iterator.next();//代码块2
// iterator.next();//代码块3

生成器函数的参数

  • 执行获取迭代器对象
function * gen(){
    yield 111;
    yield 222;
    yield 333;
}
// 执行获取迭代器对象
let iterator = gen();
console.log(iterator.next());//Object { value: 111, done: false }
console.log(iterator.next());//Object { value: 222, done: false }
console.log(iterator.next());//Object { value: 333, done: false }
console.log(iterator.next());//Object { value: undefined, done: true }
  • next方法可以传入实参
function * gen(arg){
    console.log(arg);
   	yield 111;
    yield 222;
    yield 333;
}
// 执行获取迭代器对象,并传入实参
let iterator = gen("yxj");
// 第一次调用next方法输出的是yxj
console.log(iterator.next());// yxj   { value: 111, done: false }
  • 该实参就是yield语句整个的返回结果
function * gen(arg){
    console.log(arg);
   	let one = yield 111;
    console.log(one);
    yield 222;
    yield 333;
}
let iterator = gen("yxj");
console.log(iterator.next());//yxj  tmp.html:19 {value: 111, done: false}
//第二次调用next方法,传入BBB实参,将作为第一个yield语句的整体返回结果
console.log(iterator.next('BBB'));//BBB  tmp.html:21 {value: 222, done: false}

生成器函数的实例

js是异步单线程的,很多操作都是异步的:文件操作(读取)、网络操作(ajax、request)、数据库操作。

  • 回调地狱的例子(一秒钟输出一个语句)定时器实现异步任务
setTimeout(()=>{
    console.log("1s");
    setTimeout(()=>{
        console.log("2s");
        setTimeout(()=>{
            console.log("3s");
        },1000)
    },1000)
},1000)
//如果异步任务特别多的话....
  • 生成器函数在异步编程的实现(异步任务)
function one(){
    setTimeout(()=>{
        console.log(1);
        interator.next();
    },1000)
}
function two(){
    setTimeout(()=>{
        console.log(2);
        interator.next();
    },1000)
}
function three(){
    setTimeout(()=>{
        console.log(3);
        interator.next();
    },1000)
}
// 把异步函数的调用放在了生成器函数里
function * gen(){
    yield one();
    yield two();
    yield three();
}
//调用生成器函数
let interator = gen();
interator.next();//1 2 3 

生成器函数模拟数据获取

// 用户数据获取 订单数据 商品数据
function getUsers(){
    setTimeout(()=>{
        let data = '用户数据';
        // 调用next方法,并将数据传入
        iterator.next(data);
    },1000)
}
function getOders(){
    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 getOders();
    console.log(orders);
    let goods = yield getGoods();
    console.log(goods);
}
//调用生成器函数
let iterator = gen();
iterator.next();//间隔1s输出 用户数据  订单数据  商品数据

Promise

  • Promise是ES6引入的异步编程的新解决方案(主要是解决回调地狱的问题)。语法上Promise是一个构造函数,用来封装异步操作并可以获取其成功或者失败的回调结果。
  • 没有生成器、Promise之前处理异步编程时都是层层回调嵌套的,行成回调地狱的局面,不好看也很难维护。
  • 异步编程主要是指的是一些IO的代码、文件IO、数据库IO、网络请求
  1. Promise的构造函数:Promise(excutor){}
  2. Promise:prototype.then方法
  3. Promise.prototype.catch方法
  • Promise对象有三个状态
    1. 初始化
    2. 成功(通过resolve方法改变)
    3. 失败(通过reject方法该改变)

实例化Promise对象

//该对象接受一个参数,参数类型为函数,该函数有两个参数
const p = new Promise(function(resolve,reject){
    //封装一个异步操作
    setTimeout(()=>{
        //假设请求到了数据
        let data = "用户数据"},1000)
});
  • 请求到数据以后可以调用resolve、reject函数来改变Promise对象的状态
const p = new Promise(function(resolve,reject){
    setTimeout(()=>{
        let data = '数据库中的数据';
        resolve(data);//当调用resolve函数后Promise对象的状态就变成了成功
    },1000)
});
  • 成功或者失败都可以调用Promise对象的then方法

    then接收两个参数,两个参数都是函数类型

    每个函数都有一个形参

    成功的形参为value,失败的形参为reason

p.then(function(value){
    //成功时才会调用
    console.log(value);
},function(reason){
    //失败时才会调用该方法
    console.error(reason);
})
  • 数据读取错误时
const p = new Promise(function(resolve,reject){
    setTimeout(()=>{
        let data = '数据库中的数据';
        let err = "数据读取错误"
        reject(err);//此时状态为失败
    },1000)
});
p.then(function(value){
    console.log(value);
},function(reason){
    //此时会调用该方法
    console.error(reason);
})

通过以上方式可以将异步任务封装在Promise对象里

Promise读取文件内容

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

// 使用promise封装
const p = new Promise(function(resole,reject){
    fs.readFile('./为学.md',(err,data)=>{
        if(err){
            reject(err);
        }else if(data){
            resole(data);
        }
    })
});
p.then(function(value){
    console.log(value.toString());
},function(reason){
    console.log("读取失败");
})
//node 文件名 运行

Promise封装AJAX

  • 原生的Ajax
const xhr = new XMLHttpRequest();
// 初始化
xhr.open("GET","https://api.apiopen.top/getJoke");
//发送请求
xhr.send();
//处理结果
xhr.onreadystatechange = function(){
    if(xhr.readyState == 4){
        if(xhr.status >= 200 && xhr.status < 300){
            console.log(xhr.response);
        }else{
            console.error(xhr.status);
        }
    }
}
  • Promise封装的AJAX
const p = new Promise((resolve,reject)=>{
const xhr = new XMLHttpRequest();
// 初始化
xhr.open("GET","https://api.apiopen.top/getJoke");
// 发送请求
xhr.send();
//根据返回结果判断Promise状态
xhr.onreadystatechange = function(){
    if(xhr.readyState == 4){
        if(xhr.status >= 200 && xhr.status < 300){
            // 表示成功
            resolve(xhr.response);
            // console.log(xhr.response);
        }else{
            // 成功
            reject(xhr.status);
            console.error(xhr.status);
        }
    }
}
});
// 区别在于处理成功和失败的方式不一样了,原生Ajax是在回调函数里执行成功或者失败的结果
// 现在是在异步任务的后边通过then方法来指定回调,不会产生对调地狱的问题
p.then(function(value){
console.log(value);
},function(reason){
console.error(reason);
})

then方法的返回结果

//创建promise对象
const p = new Promise((resolve,reject)=>{
    setTimeout(()=>{
        resolve('用户数据');
    },1000)
})
const result = p.then(value=>{
    console.log(value);
    // 1.返回非promise类型的属性
    return 123;//<state>: "fulfilled" <value>: 123
},reason=>{
    console.log(reason);
})
//查看then方法的返回结果
//也是一个promise对象,他的状态由回调函数的执行结果来决定,
console.log(result);// Promise { <state>: "pending" }

then方法的链式调用

//因为then方法可以返回一个promise对象,所以他是可以链式调用的
p.then(value=>{

},reason=>{
    
}).then(value=>{

}).then(value=>{

}).then(value=>{

})

Promise.catch方法

catch方法是then的语法糖,可以只指定一个回调

const p = new Promise((resolve,reject)=>{
    setTimeout(()=>{
        reject("出错了");
    },1000)
})
p.catch(function(reason){
    console.error(reason);
})

Set

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

集合的属性和方法:

  • size 返回集合的元素个数
  • add 增加一个新元素,返回当前集合
  • delete 删除元素,返回boolean值
  • has 检测集合中是否包含某个元素,返回boolean值

声明Set

let s = new Set();
console.log(s);//Set []
console.log(typeof s);//object

操作Set

let s = new Set([1,2,3,4,5,6]);
// 查看元素个数
console.log(s.size);//6

//添加新元素
s.add(7);
console.log(s);//Set(7) [ 1, 2, 3, 4, 5, 6, 7 ]

// 删除元素
s.delete(2);
console.log(s);//[ 1, 3, 4, 5, 6, 7 ]

//检测元素
console.log( s.has(3));//true

// 遍历
for(let a of s){
    console.log(a);//1 3 4 5 6 7
}

// 清空集合
s.clear();
console.log(s);//set []

Set实现数组去重

let arr = [2,3,5,4,1,5,2,3,6,9,1,5,2];
let result = [...new Set(arr)];
console.log(result);//[ 2, 3, 5, 4, 1, 6, 9 ]

Set获取交集

let arr =[14,2,1,3,2,1,3,2,8];
let arr2 = [3,14,5,6,9,11];
// 求交集之前先去重
let result = [...new Set(arr)];
let result2 = new Set(arr2);
result =  result.filter((item)=>{
    if(result2.has(item)){
        return true;
    }else{
        return false;
    }
})
console.log(result);//14 ,3
let result = [...new Set(arr)].filter((item)=>{
    return new Set(arr2).has(item)
});
console.log(result);//[14,3]

Set获取并集

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

Set获取的差集

// 差集其实就是交集取反
let A = [1,2,3];
let B = [3,4,5,6];
// A与B的差集(A-B),A里有但是B没有
let diff = [...new Set(A)].filter((item)=>{
    return !(new Set(B).has(item));
})
console.log(diff);//[1,2]

// B与A的差集(B-A)
let diff2 = [...new Set(B)].filter((item)=>{
    return !(new Set(A).has(item));
})
console.log(diff2);//[1,2]

Map

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

Map的属性和方法

  • size 返回Map的元素个数
  • Set 增加一个新元素,返回当前Map
  • get 返回键名对象的键值
  • has 检测Map中是否包含某个元素,返回Boolean值
  • clear 清空集合,返回undefined

声明Map

let m = new Map();
console.log(m);//Map(0)
  • 添加元素
let m = new Map();
m.set('name','yxj');
console.log(m);//Map { name → "yxj" }

m.set('change',function(){
    console.log("change");
});
let key = {
    address:'xian'
}
m.set(key,['王道村','马道村','禄道村']);
console.log(m);
/*
    size: 3
    <entries>
    0: name → "yxj"
    1: change → function ()​​
    2: Object { address: "xian" } → Array(3) [ "王道村", "马道村", "禄道村" ]
*/
  • 删除元素
let m = new Map();
m.set('name','yxj');
console.log(m);//Map(0)
  • 获取
let m = new Map();
m.set('name','yxj');
m.set('age',18);
console.log(m.get('name'));//yxj
  • 清空
let m = new Map();
m.set('name','yxj');
m.set('age',18);
m.clear();
console.log(m);//Map(0)
  • for…of遍历
let m = new Map();
m.set('name','yxj');
m.set('age',18);
for(let v of m){
    console.log(v);
}
/*
    结果是一个数组,第一项是键,第二项是值
    Array [ "name", "yxj" ]
    Array [ "age", 18 ]
*/

class 类

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

class声明类

class People{
    //构造方法
    //函数只要new生成实例时,就会自动调用这个方法;
    constructor(unamae,age){
        //
        this.unamae = unamae;
        this.age = age;
    }
    say(){
        console.log("666");
    }
    
}
var ldh = new People("刘德华",18);
console.log(ldh.age);//18

构造函数的静态成员

  • 在构造函数本身上添加的成员
  • 不能通过实例成员来访问
function Star(name,age){}
//静态成员,
Star.sex = '男';
console.log(yxj.name);//undefined
console.log(Star.name);//Star

static(类的静态成员)

  • 对于static标识的属性,属于类;不属于对象
  • 不能通过实例对象访问静态属性
class Phone{
    // 静态属性
    static name = 'Nova6';
    static price(){
        console.log("¥2500");
    }
}
let huawei = new Phone();
console.log(huawei.name);//undefined
console.log(Phone.name);//Nova6

构造函数的实例成员

function Star(name,age){
    //实例成员
    this.name = name;
    this.age = age;
}
//通过构造函数实例化的对象
var ldh = new Star('刘德华',18);
//通过实例化的对象来访问实例成员
console.log(ldh.name);//刘德华
//不可以通过构造函数来访问实例成员
console.log(Star.name);//Star

类的继承

  • extends 用于实现类与类之间的继承
  • super 用于访问和调用对象父类上的函数。可以调用父类的构造函数,也可以调用父类的普通函数
class Phone{
    constructor(name,price){
        this.name = name;
        this.price = price;
    }
    // 父类的方法
    play(){
        console.log("我可以玩游戏");
    }
}
class SmartPhone extends Phone{
    constructor(name,price,color){
        //super必须放在this前
        // super就是父类的constructor方法
        super(name,price);
        this.color = color;

    }
    photo(){
        console.log("拍照");
    }
}
const oppo = new SmartPhone('Find x5','¥4799','紫色');
console.log(oppo);//Object { name: "Find x5", price: "¥4799", color: "紫色" }

子类对父类方法的重写

  • 当子类的方法名与父类的方法名一样时就会重写父类的方法
  • 子类不能直接调用父类的同名方法(在普通的成员方法里不能出现super)
class Phone{
    constructor(name,price){
        this.name = name;
        this.price = price;
    }
    // 父类的方法
    play(){
        console.log("我可以玩游戏");
    }
}
class SmartPhone extends Phone{
    constructor(name,price,color){
        // super就是父类的constructor方法
        super(name,price);
        this.color = color;

    }
    photo(){
        console.log("拍照");
    }
    play(){
        console.log("我可以玩大型游戏");
    }
}
const oppo = new SmartPhone('Find x5','¥4799','紫色');
oppo.play();//我可以玩大型游戏

get和set

用于对对象的属性进行方法的绑定

可以添加一个get方法,当对某一个属性进行获取时,会执行get对应的函数

当对某一个属性进行设置时会执行set对应的函数

  • get 通常用于对对象的动态属性进行封装,比如求整数、平均数时
  • set 通常用于控制和判断 例如判断值的类型是否合法
class Phone{
    constructor(price){
        this.price = price;
    }
    //对price属性读取时就会调用
    get price(){
        console.log("价格属性被读取了");
        return '新价格'
    }
    //对price属性修改时就会调用
    //他必须接收一个参数
    set price(newVal){
        console.log("价格被修改了");
    }
    
}
//实例化一个对象
let s = new Phone("2999");
console.log(s.price);
/*
    价格被修改了 
    价格属性被读取了 
    新价格
*/

数值扩展

  • Number.EPSION 是JS表示的最小精度

    主要用于用于浮点数运算

    let m =Number.EPSILON;
    console.log(m);//2.220446049250313e-16
    console.log(0.1+0.2 === 0.3);//false
    
    function equal(a,b){
        //误差精度小于Number.EPSILON时为真
        if(Math.abs(a-b) < Number.EPSILON){
            return true;
        }else{
            return false;
        }
    }
    console.log(equal(0.1 + 0.2,0.3));//true
    
  • 二进制八进制十六进制

    //二进制 ob
    let b = 0b0010;
    console.log(b);//10
    
    // 八进制 0o
    let o = 0o777;
    console.log(o);511
    
    // 十六进制
    let x = 0xff;
    console.log(x);//255
    
  • Number.isFinite()

    检测一个数是否为有限数

    let a = 100;
    console.log(Number.isFinite(a));//true
    
  • Number.isNaN()

  • 检测一个数是否为NaN

    let g = 100;
    console.log(Number.isNaN(g));//false
    
  • Number.parseInt()

  • Number.ParsFloat()

  • Number.Integer()

    判断一个数是否为整数

  • Math.trunc()

    去掉数值的小数部分

  • Math.sign 判断一个数到底为正数、负数、还是0

对象方法的扩展

  • 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:'locahost',
        port:3306,
        name:'root',
        pass:'root',
        test:'test'
    };
    const config2 = {
        host:'http://www.yxj.com',
        port:8080,
        name:'yxj',
        pass:'666'
    };
    //后边的对象会把前面的对象覆盖(重名情况下才会覆盖)
    let obj = Object.assign(config1,config2);
    console.log(obj);//Object { host: "http://www.yxj.com", port: 8080, name: "yxj", pass: "666" }
    
  • Object.setPrototypeOf

    设置原型对象

    const school ={
        naem:'xust'
    }
    const cities = {
        area:['临潼','骊山','雁塔']
    }
    Object.setPrototypeOf(school,cities);
    console.log(school);//school的原型对象指向了cities对象
    
  • Object.getPrototypeOf

    获取原型对象

    const school ={
        naem:'xust'
    }
    const cities = {
        area:['临潼','骊山','雁塔']
    }
    console.log( Object.getPrototypeOf(school));//Object { … }
    

模块化

模块化是将一个大的文件拆分成很多小的文件,然后将小的文件组合起来。这些小文件就是模块

模块化的好处

  • 防止命名冲突
  • 代码复用
  • 高维护性

模块化规范产品

es6之前的模块化规范

  1. commonJS => Node.js、Browserify
  2. AMD => requireJS
  3. CMD => seaJS

ES6模块化语法

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

  • export 命令用于规定模块的对外接口
  • import 命令用于输入其他模块提供的功能

模块暴露语法

  • 分别暴露

    export  let obj ={
        name:'yxj',
        age:18
    }
    export let school = 'xust';
    
//通用导入my.js模块内容
import * as my from './my.js';
console.log(my);
/*
    obj: Object { name: "yxj", age: 18 }
    school: "xust"
    Symbol(Symbol.toStringTag): "Module"
*/
  • 统一暴露

    let obj ={
        name:'yxj',
        age:18
    }
    let school = 'xust';
     export{obj,school}
    
import * as my from './my.js';
console.log(my);
  • 默认暴露

     export default{
         obj :{
            name:'yxj',
            age:18
        },
         school:'xust'
     }
    
    import * as my from './my.js';
    console.log(my);
    //调用方法的话必须加一个default
    my.default.log();//666
    

模块引入语法

  • 通用导入方法

    import * as my from './my.js';
    console.log(my);
    
  • 解构赋值的方式 对分别暴露使用

    import {obj} from './my.js'
    console.log(my);
    
  • 使用别名引入 对统一暴露使用

    import {obj as obj1} from './my.js';
    console.log(obj1);
    
  • 引入默认暴露

    import {default as school} from "./my.js"
    console.log(school);
    
  • 简便引入形式(只能针对默认暴露)

    import obj from "./my.js";
    console.log(obj);
    

浏览器使用ES6模块化的另一种方式

  • 新建一个app.js文件。他负责引入其他模块的js文件,作为所有js代码的入口

    import *  as obj from "./my.js";
    import *  as obj2 from "./my2.js";
    console.log(obj);
    console.log(obj2);
    
  • 在index页面引入app.js文件

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

ES6模块化在项目中的使用方式

Bable

一个JavaScript编译器,能够将ES新特性的语法转化为浏览器能够识别的语法

安装工具

  • babel-cli

    babel命令行的工具

  • bababel-preset-env

    是一个预设包,能够把ES最新的特性转换为ES5的语法

  • browserify(webpack)

    一个打包工具

安装工具命令

npm init --yes
npm i babel-cli babel-preset-env browserify -D

对指定文件夹的文件代码进行语法转换

npx babel js -d dist/js --presets=babel-preset-env
  • npx 表示局部安装,如果是全局安装的话就直接使用babel
  • babel后的第一个参数表示源文件的目录
  • -d后边是 指定转换完成后存储的路径
  • 最后加上 --presets=babel-preset-env

生成对应的文件后还需要进一步打包

npx browserify  dist/js/app.js -o dist/pack.js

这样再引入就可以了

<script src="./pack.js"></script>

ES6模块化与npm包的使用

通过jQuery包对index.html的背景颜色做一个修改

  • 安装jQuery的包

    npm i jquery
    
  • 在入口文件(不是打包之后的app.js) 导入npm包

    import $ from 'jquery';
    //相当于 const $ = require('juety')
    $('body').css('background','pink');
    
  • 然后重新打包

    npx babel js -d dist/js --presets=babel-preset-env
    npx browserify  dist/js/app.js -o dist/pack.js
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

独立寒秋-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值