Js基础回顾--ES6常用内容

 


ES6常用内容汇总

1.let const

  let、const的特点:具有块级作用域,没有变量提升,不能重复声明,const在必须在声明时赋值。看一个栗子:

复制代码
var声明的i在全局内有效,setTimeout在循环结束才执行;let声明的i只在当前循环中有效
//输出0,1,2,3,4
for (let i = 0; i < 5; i++) {
   setTimeout(() => {
       console.log(i);
   }, 100);
}

//输出5,5,5,5,5
for (var i = 0; i < 5; i++) {
   setTimeout(() => {
       console.log(i);
   }, 100);
}
复制代码

2.解构赋值

  解构赋值是对赋值运算符的扩展,针对数组或者对象进行模式匹配,然后对其中的变量进行赋值。

复制代码
//-------------数组
//基本
let [a, b, c] = [1, 2, 3];         //a=1,b=2,c=3
//可嵌套
let [a, [[b], c]] = [1, [[2], 3]]; //a=1,b=2,c=3
//剩余运算符
let [a, ...b] = [1, 2, 3];         //a=1,b=[2,3]


//-------------对象
//基本
let { foo, bar } = { foo: 'aaa', bar: 'bbb' };       //foo='aaa',bar='bbb'
//可嵌套
let obj = {p: ['hello', {y: 'world'}] };
let {p: [x, { y }] } = obj;                          //x='hello',y='world'
//剩余运算符
let {a, b, ...rest} = {a: 10, b: 20, c: 30, d: 40};  //rest={c:30,d:40}
复制代码

3 Symbol

  ES6 数据类型除了 Number 、 String 、 Boolean 、 Objec t、 null 和 undefined ,还新增了 Symbol,表示独一无二的值。

let sy=Symbol('hello');
let sy1=Symbol('hello');
console.log(sy);        //Symbol(hello)
console.log(typeof(sy));//symbol
console.log(sy===sy1);  //false

  Symbol的最大作用是作为独一无二的属性名

复制代码
//Symbol的最大作用就是做独一无二的属性名,不能使用点运算符,而是[];
//注意Symbol类型的属性名不能用for in,Object.keys(obj),Object.getOwnPropertyName(obj)获取
let name=Symbol('name');
let obj={[name]:"jack"}
obj.name="111"
console.log(obj[name]);//jack
console.log(Object.getOwnPropertyNames(obj));//[]
console.log(Object.keys(obj));//[]
console.log(Object.getOwnPropertySymbols(obj));//[Symbol(name)]
复制代码

4 Map和Set

  Map存放键值对(key唯一),Set存放唯一值,都可以通过size属性获取元素个数。

复制代码
//----------------------------------------------------map
let myMap=new Map();
let student1={name:'jack',age:22};
//添加元素
myMap.set(0,"zero");
myMap.set(1,"one");
myMap.set(student1,"这是一个学生的信息");
myMap.set("mykey","myvalue");
console.log(myMap.size);          //4,获取元素个数
//遍历map
myMap.forEach(function(key,value){
    console.log(key+"---"+value);
})
console.log(myMap.get(student1));//这是一个学生的信息
console.log(myMap.has("mykey")); //true,判断mykey是否存在

//----------------------------------------------------set
let mySet=new Set();
//添加元素
mySet.add(student1);
mySet.add(1);
mySet.add(1);
mySet.add(0);
console.log(mySet.size);        //3,因为1虽然添加了两次但是只保留一个相同元素
console.log(mySet.has(student1))//true,判断student1是否存在

//Set实现数组去重
var set=new Set([1,1,2])
var arr=Array.from(set2)
复制代码

5 数值新增

//二进制和八进制
console.log(0b11===3); //ob、oB表示二进制数
console.log(0o11===9); //0o、0O表示八进制数

//浮点数精度丢失问题,Number.EPSILON是一个常量,表示 1 与大于 1 的最小浮点数之间的差。
console.log(0.1+0.2===0.3);//false
console.log(0.1+0.2-0.3<Number.EPSILON);//true

6 对象新增

  1.属性表达式 ES6允许用表达式作为属性名,但是一定要将表达式放在方括号内

//属性表达式
let person = {
 ["say"+"hi"]:function(){
  console.log('hello');
  }
}
person.sayhi()//hello

  2.扩展运算符(...),可以用于拷贝、合并对象

复制代码
//拷贝对象
let person = {name: "Amy", age: 15};
let someone = { ...person };
someone;  //{name: "Amy", age: 15}

//合并对象
let age = {age: 15};
let name = {name: "Amy"};
let person = {...age, ...name};
person;  //{age: 15, name: "Amy"}

//同名属性,后边值会覆盖前边的值
let person = {name: "Amy", age: 15};
let someone = {name: "Mike", age: 17, ...person};
someone;  //{name: "Amy", age: 15}
复制代码

  3.新方法Object.assign(target, source1, ···) 可用于用于拷贝属性

复制代码
let target = {a: 1};
let object2 = {b: 2};
let object3 = {c: 3};
Object.assign(target,object2,object3);  
// 第一个参数是目标对象,后面的参数是源对象
target;  // {a: 1, b: 2, c: 3}

//assign的属性拷贝属于浅拷贝 
let sourceObj = { a: { b: 1}};
let targetObj = {c: 3};
Object.assign(targetObj, sourceObj);
targetObj.a.b = 2;
sourceObj.a.b;  // 2
复制代码

7 函数新增

  ES6中的函数改变有箭头函数(类似lambda表达式,和C#基本一样)、默认参数、不定参数

复制代码
//默认参数   
function  foo(name,age=22){
    console.log(name+","+age);
}
foo('jack');//jack,22
foo('tom',25);//tom,25

//不定参数,vals是一个数组
function getMax(...vars){
    console.log(vars.length)
}
getMax(1,2);    //2
getMax(1,2,3,4);//4
复制代码

8 迭代器和for...of

  迭代器是用于遍历数据结构元素的指针,它是通过一个键为Symbol.iterator 的方法来实现.。可迭代的数据结构有Array,String,Map,Set,arguments。

let items=['one','twe','three']
//获取迭代器
let it=items[Symbol.iterator]()
console.log(it.next())//{value: "one", done: false}
console.log(it.next())//{value: "twe", done: false}
console.log(it.next())//{value: "three", done: false}
console.log(it.next())//{value: undefined, done: true}

  for...of的栗子

复制代码
//Map遍历
let myMap=new Map();
myMap.set(0,'zero');
myMap.set(1,'one');
myMap.set(2,'twe');
myMap.set(3,'three');
for (const [key,value] of myMap) {
    console.log(key+'--'+value);
}

//Set遍历
let mySet=new Set();
mySet.add('zero');
mySet.add('one');
mySet.add('twe');
mySet.add('three');
for (const item of mySet) {
    console.log(item)
}
复制代码

9 Generator

  Generator 函数可以通过 yield 关键字,把函数的执行流挂起。Generator在调用的时候不会执行函数,而是返回一个Iterator对象,调用Iterator的next()方法才会真正执行,一个简单栗子:

复制代码
   function *foo() {
        console.log(1)
        yield 'one';
        console.log(2)
        yield 'twe';
        console.log(3)
        return 'three';

    }
    let it = foo();
    console.log(it.next()); //1,{value: "one", done: false}
    console.log(it.next()); //2,{value: "twe", done: false}
    console.log(it.next()); //3,{value: "three", done: true}
复制代码

  Generator函数提供了消息双向传输的机制next()的数目要比yield多一个,第一个next()方法启动Generator(生成器),并返回第一个yield表达式的值({value:xxx,done:yyy}形式);第二个next(arg)会把参数赋值给第一个yield表达式,同时返回第二个yield表达式的值;第三个next(arg)会把参数赋值给第二个yield表达式,同时返回第三个yield表达式的值,以此类推。如果Generator中没有return的话,隐式包含一个return undefined。

复制代码
    function* bar(num) {
        let x = num* (yield 'hello');
        console.log('x=' + x);
        let y = (yield x * 3);
        console.log('y=' + y);
        return 'world'
    }
    var it = bar(5);
    console.log(it.next());//启动生成器,返回第一个yield的值 {value: 'hello', done: false}
    console.log(it.next(3));//第二个next把自己的参数赋值给第一个yield,同时返回第二个yield的值 || x=15 {value: 45, done: false}
    console.log(it.next(4));//第三个next把自己的参数赋值给第二个yield,同时返回第三个yield的值 || y=4  {value: 'world', done: true}
复制代码

10 Promise

  Promise是异步编程的一种解决方案,从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。

Promise对象有以下两个特点:

  (1)对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。

  (2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。

当新建一个Promise对象时,Promise会直接执行:

    let p=new Promise((resolve,reject)=>{
       setTimeout(() => {
           console.log("异步任务执行完成");
           resolve("返回的结果数据")
       }, 1000);
    });
    //控制台直接打印【异步任务执行完成】

  一般我们会把Promise包裹在一个函数中,当需要使用Promise的时候调用这个函数:

复制代码
    let myfunc = () => {
        let p = new Promise((resolve, reject) => {
            setTimeout(() => {
                console.log("异步任务执行完成");
                resolve("返回的结果数据")
            }, 1000);
        });
        return p;
    }
    //调用函数
    myfunc().then(
         (result)=> {console.log(result)},
         (error)=> {console.log(error)}
    );
    //控制台打印【异步任务执行完成】
    //控制台打印【返回的结果数据】
复制代码

  then 方法接收两个函数作为参数,第一个参数是 Promise 执行成功时的回调,第二个参数是 Promise 执行失败时的回调,两个函数只会有一个被调用,then 方法将返回一个 resolved 或 rejected 状态的 Promise 对象用于链式调用。

复制代码
    let myfunc = () => {
        let p = new Promise((resolve, reject) => {
            setTimeout(() => {
                console.log("异步任务执行完成");
                resolve ("返回的结果数据")
            }, 1000);
        });
        return p;
    }
    //调用函数
    myfunc().then(
         (result)=> {console.log(result); return("第一个then返回的结果")},
         (error)=> {console.log(error)}
    ).then(
        (result)=> {console.log(result); return("第二个then返回的结果")},
         (error)=> {console.log(error)}
    ).then(
        (result)=> {console.log(result);},
         (error)=> {console.log(error);}
    )
    //控制台打印【异步任务执行完成】
    //控制台打印【返回的结果数据】
    //控制台打印【第一个then返回的结果】
    //控制台打印【第二个then返回的结果】
复制代码

  Promise.all([promises]),Promise.race([promises])用于流程控制,Promise.all表示所有的promise都执行完成后执行回调;Promise.race表示任意一个promise执行完成(无论是否成功,只要完成就行)就会执行回调

复制代码
    let myfunc1 = () => {
        let p = new Promise((resolve, reject) => {
            setTimeout(() => {
                console.log("异步任务执行完成1");
                resolve("返回的结果数据")
            }, 1000);
        });
        return p;
    }
    let myfunc2 = () => {
        let p = new Promise((resolve, reject) => {
            setTimeout(() => {
                console.log("异步任务执行完成2");
                resolve("返回的结果数据2")
            }, 2000);
        });
        return p;
    }
    let myfunc3 = () => {
        let p = new Promise((resolve, reject) => {
            setTimeout(() => {
                console.log("异步任务执行完成3");
                resolve("返回的结果数据3")
            }, 3000);
        });
        return p;
    }
    //all方法, 所有的Promise都执行成功后再执行then, 如果有任意一个没有执行成功就会报错
    Promise.all([myfunc1(), myfunc2(), myfunc3()])
        .then(
            (results) => {
                console.log(results);
            })
    //results:["返回的结果数据", "返回的结果数据2", "返回的结果数据3"]

     //race方法,有一个Promise执行完成(无论成功还是失败),就会执行then
    Promise.race([myfunc1(), myfunc2(), myfunc3()])
        .then(
            (result) => {
                console.log('success' + result)
            },
            (error) => {
                console.log('error' + error)
            }
        )
      //result:返回的结果数据
复制代码

 11 class

  在ES6中,class (类)作为对象的模板被引入,先看一个ES5中定义一个构造函数的方式:

复制代码
    //ES5构造函数
    function Person(name, age) {
        this.name = name;
        this.age = age;
        this.say = function () {
            console.log(`我是${this.name},我今年${this.age}岁了`);
        }
    }
    //添加/重置原形对象中的方法
    Person.prototype.sayhi = function () {
        console.log(`${this.name}:hello!`)
    }
    //实例化一个Person
    let person = new Person('jack', 22);
    person.say(); //我是jack,我今年22岁了
    person.sayhi(); //jack:hello!
复制代码

  ES6中的class 的本质还是 function,它可以看作一个语法糖,让对象原型的写法更加清晰、更像面向对象编程的语法。

复制代码
    let Person = class {
        constructor(name, age) {
            this.name = name;
            this.age = age;
        }
        say() {
            console.log(`我是${this.name},我今年${this.age}岁了`);
        }
    }
    //添加/重置原形对象中的方法
    Object.assign(Person.prototype, {
        sayhi() {
            console.log(`${this.name}:hello!`)
        }
    })
    //实例化一个Person
    let person = new Person('jack', 22);
    person.say(); //我是jack,我今年22岁了
    person.sayhi(); //jack:hello!

    //class只是一个语法糖,原型、原型链和es5中没什么区别
    console.log(person.__proto__.constructor==Person);//true
    console.log(person.__proto__==Person.prototype)//true
复制代码

  class的封装和继承,使用过C#/Java的话,这个毫无难点,看一个栗子即可:

复制代码
    let Person = class {
        constructor(name, age) {
            this.name = name;
            this.age = age;
        }
        say() {
            console.log(`我是${this.name},我今年${this.age}岁了`);
        }
    }

    //Worker继承Person类
    class Worker extends Person {
        constructor(name, age, job) {
            super(name, age)
            this.job = job
        }
        getwork() {
            console.log(`我的职业是${this.job}`);
        }
    }
let worker
= new Worker('tom', 25, '司机'); worker.say() //我是tom,我今年25岁了 worker.getwork() //我的职业是司机 //看一下使用继承后清晰的原型链 console.log(worker.__proto__ == Worker.prototype) //true console.log(worker.__proto__.__proto__ == Person.prototype) //true console.log(worker.__proto__.__proto__.__proto__ == Object.prototype) //true console.log(worker.__proto__.__proto__.__proto__.__proto__ == null) //true,因为Object.prototype.__proto__==null,这是原型链的终点
复制代码

12 async await

  async 是 ES7 才有的与异步操作有关的关键字,async方法返回一个Promise对象,可以使用then添加回调,看一个简单的栗子:

复制代码
    async function sayhiAsync() {
        return "hello";
    }
//async函数返回一个Promise对象
    console.log(sayhiAsync()) //Promise {<resolved>: "hello"}
   
 //通过then添加回调    
    sayhiAsync().then((result) => {
        console.log(`sayhiAsync的回调,sayhiAsync的结果:${result}`)
    })
    //打印:【sayhiAsync的回调,sayhiAsync的结果:hello】
复制代码

  介绍await前,我们先看一个栗子:

复制代码
    let myfunc1 = () => {
        let p = new Promise((resolve, reject) => {
            setTimeout(() => {
                console.log("异步任务执行完成1");
                resolve("返回的结果数据")
            }, 3000);
        });
        return p;
    }
    let myfunc2 = () => {
        let p = new Promise((resolve, reject) => {
            setTimeout(() => {
                console.log("异步任务执行完成2");
                resolve("返回的结果数据2")
            }, 2000);
        });
        return p;
    }
    let myfunc3 = () => {
        let p = new Promise((resolve, reject) => {
            setTimeout(() => {
                console.log("异步任务执行完成3");
                resolve("返回的结果数据3")
            }, 1000);
        });
        return p;
    }

    async function foo() {
         myfunc1();
         myfunc2();
         myfunc3();
        console.log('耗时任务都执行完了,foo方法执行完成')
    }
    foo()
复制代码

执行的结果是:

  这是因为JavaScript 是一门单线程语言,异步操作都会放到事件循环队列里面,等待主执行栈来执行的,Js中并没有专门的异步执行线程。如果我们想在Js中实现类似于C#,Java中的同步执行,就可以使用await了。async 函数执行时,如果遇到 await 就会先暂停执行 ,等到触发的异步操作完成后,恢复 async 函数的执行并返回解析值。修改上边的代码来实现同步执行的效果,只需要异步任务前边加上await即可:

复制代码
    let myfunc1 = () => {
        let p = new Promise((resolve, reject) => {
            setTimeout(() => {
                console.log("异步任务执行完成1");
                resolve("返回的结果数据")
            }, 3000);
        });
        return p;
    }
    let myfunc2 = () => {
        let p = new Promise((resolve, reject) => {
            setTimeout(() => {
                console.log("异步任务执行完成2");
                resolve("返回的结果数据2")
            }, 2000);
        });
        return p;
    }
    let myfunc3 = () => {
        let p = new Promise((resolve, reject) => {
            setTimeout(() => {
                console.log("异步任务执行完成3");
                resolve("返回的结果数据3")
            }, 1000);
        });
        return p;
    }

    async function foo() {
        await myfunc1();
        await myfunc2();
        await myfunc3();
        console.log('耗时任务都执行完了,foo方法执行完成')
    }
    foo()
复制代码

执行结果如下

13 模块化

  ES6 引入了模块化,其设计思想是在编译时就能确定模块的依赖关系,以及输入和输出的变量。ES6 的模块化分为导出(export) @与导入(import)两个模块。注意:每个模块都有自己的上下文,模块内声明的变量都是局部变量,不会污染全局作用域。一个简单的export/import栗子,test1.js导出,test2.js导入:

复制代码
//----------------------------------test1.js
//变量
let myname='jack';
let myage=25;
//function
let myfunc=function(){
    console.log(`我叫${myname},今年${myage}岁了`);
}
//class
let myClass=class{
    constructor(a,b){
        this.a=a;
        this.b=b;
    }
    sum(){
        console.log( this.a+this.b);
    }
}
//导出
export{myname,myage,myfunc,myClass}



//--------------------------------------test2.js
//导入
import{myname,myage,myfunc,myClass} from "./test1.js";
console.log(myname);          //jack
console.log(myage);           //25
myfunc()                      //我叫jack,今年25岁了
let c = new myClass(1, 2);
c.sum()                       //3
复制代码

  有时候会在导出或者导入时需要更改变量、方法、类的名字(如为了避免重名),可以使用as进行重命名

复制代码
/*-----export时重命名-----*/
//test1.js
let oldname= "jack";
export { oldname as newname}
 
//test2.js
import { newname} from "./test1.js";
console.log(newname);// jack


/*-----import时重命名-----*/
//test1.js
let oldname= "jack";
export { oldname}
 
//test2.js
import { oldname as newname} from "./test1.js";
console.log(newname);// jack
复制代码

export default命令

  在一个文件或模块中,export、import 可以有多个,export default 仅有一个。export方式导出时,必须使用import {}来接收,export default向外暴露的成员可以使用任意变量接收

//test1.js导出
let myname='jack';
export default myname

//test2.js导入,不用使用import{myname}形式
import a from "./test1.js";
console.log(a);//jack

 

posted @   捞月亮的猴子  阅读(425)  评论(0编辑  收藏  举报
编辑推荐:
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
阅读排行:
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 字符编码:从基础到乱码解决
历史上的今天:
2018-09-13 Entity Framework入门教程(17)---记录和拦截数据库命令
2018-09-13 Entity Framework入门教程(16)---Enum
2018-09-13 Entity Framework入门教程(15)---DbContext追踪实体状态改变
2018-09-13 Entity Framework入门教程(14)---DbFirst下的存储过程
2018-09-13 Entity Framework入门教程(13)---EF中的高并发
2018-09-13 Entity Framework入门教程(12)--- EF进行批量添加/删除
点击右上角即可分享
微信分享提示