• 有问题请联系QQ:2374146085
  • 有问题请联系QQ:2374146085

Es6+

2年前 (2021-10-07) 3762次浏览 已收录 1个评论 扫描二维码

导读

本篇文章包括let变量声明、const声明常量、解构赋值、模版字符串、对象简化、箭头函数、rest参数、扩展运算符、Symbol、迭代器、手写迭代器、生成器、Promise、数值扩展、Set、模块化


let变量声明

//变量不能重复声明
let star = 'zll';
let star = 'wxl';//此时会报错

//块级作用域有效 全局、函数、ecal
{ //if for else while
    let str='zzl';
}
console.log(str);//此时会报错,因为拿不到

// 不存在变量提升
console.log(name);//会报错,不能使用name这个变量
let name='zzl';

//不影响作用域链
{
    let name='zzl';//虽然是块级作用域,但是不影响作用域链的效果
    function fn(){
        console.log(name);
    }
    fn();//可以拿到
}

const声明常量

  • 一定要赋初始值
  • 常量的值不能再修改
  • 也是块级作用域
//声明常量
const CL='zzl';

// 对于数组和对象的元素修改,不算2中的常量修改,不会报错
const SZ=['zzl','wxl'];
SZ.push('ll');//此时不会报错,因为只是修改数据,并没有修改地址

解构赋值

//数组解构赋值
const nameS=['zzl','wxl','ll'];
let [name1,name2,name3]=nameS;
console.log(name1);//输出zzl

//对象的结构赋值
const data={
    name:'zzl',
    age:'22',
    active:function(){
        console.log('我会飞');
    }
}
let {name,age,active}=data;
console.log(name);//输出zzl
active();//调用方法,输出我会飞

// let(active)=data;
// active();

模版字符串

let str=`字符串`
  • 它可以支持换行
  • 变量拼接
let name='zzl';
let data=`${name}是个人`
//输出 zzl是个人

对象简化写法

es6允许在大括号里面直接写入变量名和函数名,作为对象的属性和方法

let name='zzl';
let fun=function(){
    console.log('我是人');
}
const data={
    name, //可以直接写变量名,不用再写值了
    fun
}
console.log(data);
// 结果输出name:'zzl',fun()

方法定义

const data={
    // 旧的方法定义
    // act:function(){
    //     console.log('我会动');
    // }
    //新的方法定义
    act(){
        console.log('我会动');
    }

}

箭头函数

// 声明一个函数
let fn=function(a,b){

}

// 箭头函数声明一个函数
let fn=(a,b)=>{

}

fn(1,2);

特点

// 箭头函数的额this是静态的,this始终指向函数声明时所在作用域下的this的值
function getname(){
    //name是zzl,直接调用的话this值指向window
}
    console.log(this.name);//zzl
let getname2=()=>{
    //而这个箭头函数是在全局作用域下声明的,所以this也是指向window
    console.log(this.name);//zzl
}

window.name='zzl';
const data={
    name:'wxl'
}

//直接调用
getname();//name是zzl,直接调用的话this值指向window
getname2();//而箭头函数是在全局作用域下声明的,所以this也是指向window

// call方法调用
getname.call(data);//此时普通函数this的值已经变为data了。
getname2.call(data);
//输出wxl,因为它的this依然指向函数getname2声明时所在作用域下的this的值window.name='zzl';

////////////////////////////////////////////////////////////////////////////////

// 不能作为构造实例化对象
let Person=(name,age)=>{
    this.name=name;
    this.age=age;
}
let me=new Person('zzl','22');//此时会报错,箭头函数不能作为实例化对象。

////////////////////////////////////////////////////////////////////////////////

//不能使用arguments变量
// arguments:用来保存实参的
let fn=()=>{
    console.log(arguments);
}
fn(1,2,3);//会报错,不用用来保存实参

简写箭头函数

// 省略小括号
let add=(n)=>{
    return n+n;
}
console.log(add(9));

//简写为下面----------

//当形参有且只有一个的时候,可以省略小括号
let add=n=>{
    return n+n;
}
console.log(add(9));

////////////////////////////////////////////////////////////////////////////////

//省略花括号
//当代码体只有一条语句的时候

let sum=(n)=>{
    return n*n;
};
console.log(sum(9));

//简写为下面----------

//当代码体只有一条语句的时候,此时return必须省略,而且语句的执行结果就是函数的返回值
let sum=(n)=>n*n;
console.log(sum(9));

//小括号和花括号同时省略----------
let sum=n=>n*n;
console.log(sum(9));

箭头函数注意事项

  • 箭头函数适合与this无关的回调,比如定时器,数组的方法回调。
  • 箭头函数不适合与this有关的回调,比如DOM元素的事件回调、对象的方法。
btn.addEventListener("click",function(){
    //此时普通函数的this指向事件缘
    //如果使用箭头函数,事件源将变成外部作用域的this值,即这个函数所在的作用域
})

函数参数初始值

function add(a,b,c=10){

}

//函数参数初始值与结构赋值结合使用
function data({name,age='22'}){
    console.log(name);
    console.log(age);
}
data({
    name='zzl',
    // age='23'
})

rest参数

用于获取函数的实参,可以代替arguments。

// function data(){
//     console.log(arguments);//输出的是一个对象
// }
// data('zzl','wxl');

// rest参数
function data(...args){
    console.log(args); //输出的是一个数组,可以使用filter some...
}
data('zzl','wxl');
rest参数必须放在参数最后。

function data(a,b,...args){
    console.log(a);//1
    console.log(b);//2
    console.log(args);//345
}
data(1,2,3,4,5)

const obj1={
    q:'zzl'
}
const obj2={
    s:'wxl'
}
const data={...obj1,...obj2}; //相当于合并了两个对象
console.log(data);//{q:'zzl',s:'wxl'}

扩展运算符…

它能将数组转换为逗号分隔的参数序列

const names=['zzl','wxl','ll'];

function data(){
    console.log(arguments);
}
//不用扩展运算符
data(names);//只输出一个结果,是一个数组

// 用扩展运算符
data(...names);//输出3个结果,等价于:data('zzl','wxl','ll'),即参数序列

如果数组里面有引用类型的话,扩展呢运算符也只是浅拷贝。
  • 可以用来数组的合并
  • 数组的克隆
  • 伪数组转为真正的数组
// 数组的合并
const a=['zzl'];
const b=['wxl'];
const c=[...a,...b];
// c=['zzl','wxl']

//将伪数组转为真正的数组
const divs=document.querySelectorAll('div');//得到伪数组
const divdata=[...divs];//转为真正的数组

Symbol

它一种新的数据类型,表示独一无二的值,类似于字符串的数据类型。

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

 

let game={
    //假如有很多代码很多变量名
}

//声明一个对象
let data={
    //Symbol保证了up和down的属性名是独一无二的,
    // 所以添加进去也不怕也不怕有属性名冲突
    up:Symbol(),//up属性的数据类型为Symbol
    down:Symbol()
};

//第一种添加方式
//把这个Symbol添加到game方法中
game[data.up]=function(){
    console.log('我会飞'); //安全的向这个对象中添加了两个方法
}
game[data.down]=function(){
    console.log('我会爬');
}
console.log(game);


//////////////////////////////////////
//第二种添加方式
let play={
    name='run',
    [Symbol('say')]:function(){
        console.log('我会说话');
    },
    [Symbol('sleep')]:function(){
        console.log('我会睡觉');
    }
}
console.log(paly);
//补充代码
const title1 = Symbol("title")
const title2 = Symbol("title")
const info={
    [title1]:'zzl',
    [title2]:'wxl'
}
Symbol有很多内置方法

迭代器

任何数据结构只要部署了Iterator接口,就可以使用for…of遍历.

具备iterator接口的数据类型

  • Array
  • Argunments
  • Set
  • Map
  • String
  • TypedArray
  • NodeList

这个接口就是对象里面的一个属性,属性的名字叫Symbol.iterator,也可以自己对结构进行布置iterator接口。

for( let i in data){
i是键名
}
for( let i of data){
i是键值
}

const arr=['zzl','wxl'];
console.log(arr);
//arr里面就有Symbol.iterator这个属性。

工作原理

  • 先创建一个指针对象,指向当前数据结构的起始位置
  • 第一次调用对象的next方法,指针自动指向数据结构的第一个成员
  • 接下来不断调用next方法,指针一直往后移动,直到指向最后一个成员
  • 每次调用next方法就会返回一个包含value和done属性(是否完成)的对象
迭代器可以自定义遍历数据

手写迭代器

//声明一个对象
const data={
    name:'zzl',
    lis:[
        'wxl',
        'll',
        'hll'
    ],
    //自己给某些结构加上iterator接口
    [Symbol.iterator](){
        //索引变量
        let index=0;
        let _this=this;
        return {//返回一个指针对象,即创建一个指针对象
            next:function(){ //创建对象的next方法
                // 返回一个包含value和done属性(是否完成)的对象
                if(index<_this.lis.length){
                    const result= {value:_this.lis[index],done:false};
                    index++;
                    return result;
                }else{                   
                    return {value:undefined,done:true};
                }
            }
        };
    }
}
//自定义遍历这个对象
for(let v of data){
    console.log(v);
}
console.log('--------------------')
console.log(data);
结果演示

数组的常用方法

forEach

缺点:找到目标还会继续循环,并且不受return和break的影响。

some

找到目标后,可以通过return结束循环。

const arr=[]
arr.some((item,index)=>{
  if(item=='zzl'){
    console.log(item)
    return true
  }
})

every

只要每一项都满足every里面的判断条件,则最终返回true。

const arr=[
  {id:1,state:true},
  {id:2,state:true}
]
//判断数组中的所有state是否都为true
const result=arr.every(item=>item.state)

filter

const data=arr.filter(item=>item.state)

filter会把满足条件的数据重新过滤到的新数组中。

reduce

arr.filter(item=>item.state).reduce(累加的结果,当前循环项)=>{ },初始值)

第一次循环累加的结果默认等于初始值,以后循环累加的结果等于上一次累加的结果加上循环项里的数据。

const arr=[{id:1,state:true,price:10}]
let sum=0
arr.filter(item=> item.state).reduce((sum,item)=>{
    return sum+= item.price
    //return给下一次累加使用
},0)

生成器

生成器就是一个特殊的函数,是异步编程新的解决方案。分别通过以下代码可知运行逻辑。

function * fun(){
    console.log('zzl');
}
let a=fun();
// console.log(a);//输出一个迭代器对象(有next方法)
a.next();//输出zzl
function * fun(){
    console.log('zzl');
    console.log('wxl');
}
let a=fun();
// console.log(a);//输出一个迭代器对象(有next方法)
a.next();//输出zzl wxl 即全部输出
function * fun(){
    console.log('zzl');
    yield '我要暂停'
    console.log('wxl');
}
let a=fun();
// console.log(a);//输出一个迭代器对象(有next方法)
a.next();//输出zzl 我要暂停
function * fun(){
    console.log('zzl');
    yield '我要暂停'
    console.log('wxl');
}
let a=fun();
// console.log(a);//输出一个迭代器对象(有next方法)
a.next();//输出zzl
a.next();//输出wxl
function * fun(){
    // console.log('zzl');
    yield '我要暂停'
    // console.log('wxl');
}
let a=fun();
// console.log(a);//输出一个迭代器对象(有next方法)
for(i of fun()){
    console.log(i);//我要暂停
}
function * fun(){
    // console.log('zzl');
    yield '我要暂停'
    // console.log('wxl');
}
let a=fun();
console.log(a.next()); //输出 {value: '我要暂停', done: false}

生成器函数的参数传递

function * fun(arg){
    console.log(arg);//输出aaa
    let one=yield 111;
    console.log(one);//输出bbb
    let two=yield 222;
    console.log(two);//输出ccc
    let three=yield 333;
    console.log(three);//输出ddd
}
let a=fun('aaa');
console.log(a.next());//第一次调用next
//next方法可以传入实参
//第二次调用next的实参将作为第一个yield的整体返回结果
console.log(a.next('bbb'))//输出{value: 222, done: false}
console.log(a.next('ccc'))
console.log(a.next('ddd'))

解决回调地狱

// setTimeout(() => {
//     console.log(111);
//     setTimeout(() => {
//         console.log(222);
//         setTimeout(() => {
//             console.log(333);
//         }, 3000);
//     }, 2000);
// }, 1000);

function one(){
    setTimeout(()=>{
        console.log(111);
        a.next();//定时器运行完调用下一个,实现了异步编程
    },1000)
}
function two(){
    setTimeout(()=>{
        console.log(222);
        a.next();
    },2000)
}
function three(){
    setTimeout(()=>{
        console.log(333);
        a.next();
    },3000)
}
function *fun(){
    yield one();
    yield two();
    yield three();
}
//调用生成器函数
let a=fun();
a.next();
结果演示
function one(){
    setTimeout(()=>{
        let data='用户数据';
        a.next(data);//第二次调用next的实参将作为第一个yield的整体返回结果
    },1000)
}
function two(){
    setTimeout(()=>{
        let data='订单数据';
        a.next(data);
    },1000)
}
function three(){
    setTimeout(()=>{
        let data='商品数据';
        a.next(data);
    },1000)
}
function *fun(){
    let users= yield one(); //用户数据 作为第一个yield的整体返回结果
    console.log(users);
    let orders= yield two();
    console.log(orders);
    let goods= yield three();
    console.log(goods);
}
//调用生成器函数
let a=fun();
a.next();
结果演示

Promise

它是es6中异步编程的新的解决方案。相当于一个构造函数。

function fun(){
    return new Promise((resolve,reject)=>{
        //如果成功就调用resolve
        let data='数据库中的数据';
        resolve(data); //promise状态变为成功
        //如果失败就调用reject
        let err='数据库读取失败';
        reject(err);//promise状态变为失败
    })
}
var promise = fun()
promise.then(//调用then方法
    function(success){//promise状态变为成功后then会调用第一个回调函数
        console.log(success);
    },function(err){//promise状态变为失败后then会调用第二个回调函数
        console.log(err);
    }
)
更过promise的内容请看以往文章,或者去看阮一峰的es6,讲的非常详细。
异步与回调

JS进阶-异步


数值扩展

console.log(0.1+0.2===0.3);//不等于 输出false
function bj(a,b){
    if(Math.abs(a-b)<Number.EPSILON){ //a-b的差值小于这个误差,就认为你们相等
        return true;
    }else{
        return false;
    }
}
console.log(bj(0.1+0.2,0.3));//输出true,0.1+0.2===0.3

Set

类似于数组,但是成员的值是唯一的,即自动去重。

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


//交集
let arr2=[1,4,5,6,5,6];
let result2=[...new Set(arr)].filter(item=>{
    let s2=new Set(arr2);//[1,4,5,6]
    if(s2.has(item)){
        return true;
    }else{
        return false;
    }
})
console.log(result2);//[1,4];


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

//差集,交集的逆运算
let arr2=[1,4,5,6,5,6];
let result2=[...new Set(arr)].filter(item=>{
    let s2=new Set(arr2);//[1,4,5,6]
    if(!s2.has(item)){//item不在s2里面
        return true;
    }else{
        return false;
    }
})
console.log(result2);//[1,4]

模块化

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

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

ES Module

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

js模块代码

//第一种暴露方法:分别暴露
export let a='zzl'; //向外暴露
export function fun(){
    console.log('我是谁');//向外暴露
}

//第二种暴露方法:统一暴露[ 注意{}导出的并不是对象 ]
let a='zzl';
export{a,fun};

//第三种:默认暴露
export default{
    a:'zzl',
    fun:function(){
        console.log('我是谁');
    }
}

html代码引入js模块

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script type="module">
        //第一种引入方式:引入mi.js暴露的模块
        import * as m from './模块化/m1.js';
        console.log(m.a); //zzl

        //第二种引入方式解构赋值形式:引入mi.js暴露的模块
        import {a as a1,fun} from './模块化/m1.js';
        console.log(a1);//可以给a一个别名a1 输出zzl

        //默认暴露的引入比较特殊,引入语法是
        import * as m from './模块化/m1.js';
        m.default.fun();
        //默认暴露的解构赋值
        import{default as mm} from './模块化/m1.js';
        console.log(mm);

        //简便形式 针对默认暴露
        import m from './模块化/m1.js';

        //动态调用模块,即使用时再导入
        import('./模块化/m1.js').then(module =>{
             module.fun();
    })
    </script>
</body>
</html>
也可以专门创建一个文件a,里面专门放import…引入,然后在另一个文件里引入文件a

<script src="文件a" type="module"><script>

以便减少一个主文件的代码量

module.exports 与 exports的使用与区别

二者都是专门负责导出的东西,都属于commonJS规范,是同步加载的.

exports

a.js

const a=10

//导出 (实际上exports就是一个对象)
exports._a=a

b.js

// 引入a.js导出的对象,实际就是exports对象
const ba=require('./a.js') // === exports对象

console.log('输出',ba._a) //输出 10
require是同步执行

module.exports

a.js

const a=10

//导出 (实际上exports就是一个对象)
// exports._a=a


/**
 * 实际上module也是一个对象
 * 下边三行代码具体逻辑如下:
 * 1、module.exports = exports 即4行的exports,
 *      此时是引用赋值,并且可以继续使用原来b.js的导入方式
 * 2、重新给module.exports一个新对象地址{_a:a}
 * 3、b.js导入方式不变,因为只是对象地址,该对象module.exports依然是导出对象
 */
module.exports={ 
    _a:a
}

b.js

// 引入a.js导出的对象,实际就是module.exports对象
const ba=require('./a.js') // === module.exports对象

console.log('输出',ba._a) //输出 10

require()与import()

if (true){
   import * from './a.js'
}

以上代码是错误的,因为imprt关键字不支持在这类代码里,但是require支持,因为require本质是函数,但是,require不支持在浏览器里运行,并且它是同步执行的,所以ESModule里可以用import函数来引入外部模块,并且它是异步执行的.

if(true){
    import('./a.js').then(res=>{
        console.log(res._a)
    }).catch(err=>{
        console.log(err)
    })
}

<script src type=”module”> 也是异步加载执行的,相当于加了async属性


Babel

它能将js的新语法转化为旧语法,以便更好的兼容。


渣渣龙, 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:Es6+
喜欢 (29)

您必须 登录 才能发表评论!

(1)个小伙伴在吐槽
  1. 补:箭头函数绑定不了this
    厚积薄发2021-10-16 17:00