ES6有何新特性?(下篇)

news/2024/7/10 23:45:15 标签: javascript, ecmascript, ES6, 笔记, 前端, Promise, 扩展运算符

目录

函数参数的默认值设置

rest参数

扩展运算符

Symbol

迭代器

生成器

Promise-toc" style="margin-left:40px;">Promise

Class

数值扩展

对象方法扩展

模块化


大家好呀!今天这篇文章继续为大家介绍ES6的新特性,上上上篇文章介绍了一部分,这篇文章会将剩下的部分新增的特性都介绍到。希望对你有帮助!

函数参数的默认值设置

ES6允许给函数参数赋值初始值,可以给形参赋初始的值,并且可以给参数指定默认的值,若给参数没有传入相应的值,则会使用默认的值。

javascript">  function add(a,b,c){
            return a+b+c;
        }
  let result=add(1,2);
  console.log(result)//NaN

以上的这种情况,传入的数值与形参的数量不一样,则最后的一个形参则会传入underfine,因此1+2+underfine则会输出NaN。同时我们可以为第三个形参赋默认的值,具有默认值的参数一般都需要放在最后一个。具体代码如下:

javascript"> // 形参初始值
 function add(a,b,c=10){
     return a+b+c;
  }
let result=add(1,2);
console.log(result)//13

除此之外,它还可以与解构赋值进行结合。可以使得获取传入的值更加方便。比如我们为一个函数传入一个对象,在函数的内部输出对象中的属性,我们传统的方式可以如下:

javascript">function connect(option){
  console.log(option.name)
  console.log(option.age)
  console.log(option.sex)
        }
 connect({
     name:'N-A',
     age:5,
     sex:"男"
 })

以上的方式会让我们觉得比较地麻烦,需要反复地使用option来进行调用,若使用函数参数结合对象解构赋值的方式来实现,则会更加地方便,具体实现如下:(同时也可以与上述的功能一样,为参数赋初始的值)

javascript"> function connect({name,age,sex}){
    console.log(name)
    console.log(age)
    console.log(sex)
        }
   connect({
     name:'N-A',
     age:5,
     sex:"男"
     })

rest参数

rest参数主要是用来获取函数的实参。它可以用来替换arguments,与arguments的作用相似。在ES5中使用arguments来获取函数的实参的方法如下:

javascript"> function date(){
            console.log(arguments)
        }
 date("N-A","5","男")

输出的结果是一个对象,而使用ES6新增的rest参数输出的结果是一个数组,因此数组更加方便我们对其进行一定的操作。具体的写法如下:

javascript">      // rest参数
        function date(...args){
            console.log(args)
        }
        date("N-A","5","男")
        // 若有多个参数,则rest参数必须要放到参数的最后
        function fn(a,b,...args){
            console.log(a);//1
            console.log(b);//2
            console.log(args);//[3,4,5,6,7,8]
        }
        fn(1,2,3,4,5,6,7,8)

注意:若有多个参数,则rest参数必须放到参数的最后。

扩展运算符

扩展运算符能将数组转为逗号分隔的参数序列。他的使用方式也是使用...与rest参数优点相似,但是他们一个是在函数声明时的参数使用,一个是在函数调用时使用。具体用法如下:

javascript">        const data=[1,2,3,4]
        function result(){
            console.log(arguments);
        }
        result(...data);//相当于result(1,2,3,4)

扩展运算符还有以下的一些用途,数组的合并,在ES5中我们使用concat可以实现数组的合并,在ES6中使用拓展运算符同样可以实现数组的合并,且更加的方便。

javascript"> const data1=[1,2,3,4]
       const data2=[5,6,7,8]
    //    传统的方式
    const result=data1.concat(data2)//[1,2,3,4,5,6,7,8]
    // 扩展运算符
    const result2=[...data1,...data2]//[1,2,3,4,5,6,7,8]

除此之外,扩展运算符还可以实现数组的克隆,但是使用它进行克隆是浅拷贝的克隆。也可以让伪数组变成真正的数组。

javascript">    // 数组的克隆
    const data1=[1,2,3,4]
    const data2=[...data1]
    console.log(data2)//[1,2,3,4]
    // 将伪数组变成真数组
    // html部分代码省略
    const divs=document.querySelectorAll("div")
    const divArr=[...divs];
    console.log(divArr)

Symbol

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

1) Symbol 的值是唯一的,用来解决命名冲突的问题

2) Symbol 值不能与其他数据进行运算

3) Symbol 定义 的 对象属 性 不能 使 用 for…in 循 环遍 历 ,但 是可 以 使 用Reflect.ownKeys 来获取对象的所有键名

javascript">        // 创建Symbol
        let s=Symbol();
        let s2=Symbol("N-A");
        let s3=Symbol("N-A");
        console.log(s2==s3);//false
        // 使用Symbol.for创=创建
        let s4=Symbol.for('N-A');
        let s5=Symbol.for('N-A');
        console.log(s4==s5);//true

它可以为对象添加属性和方法,让该属性或者方法是独一无二的,就算原本的对象中有一个同名的方法,它也能够进行添加成功。同时也能够保持其安全性,不会破坏对象原本的属性和方法。

javascript"> let plan={
            name:"N-A",
            study(){
                console.log("今天学习ES6");
            },
            sport(){
                console.log("今天去游泳");
            }
        };
        // 声明一个对象
        let methods={
            study:Symbol(),
            sport:Symbol()
        };

        plan[methods.study]=function(){
            console.log("今天学习Vue.js")
        };
        plan[methods.sport]=function(){
            console.log("今天去跑步")
        };
        console.log(plan);
        // 方法二
        let plan={
            name:"N-A",
            [Symbol('study')]:function(){
                console.log("今天学习ES6");
            },
            [Symbol('sport')]:function(){
                console.log("今天去游泳");
            }
        };

除了定义自己使用的 Symbol 值以外,ES6 还提供了 11 个内置的 Symbol 值,指向语言内部使用的方法。可以称这些方法为魔术方法,因为它们会在特定的场景下自动执行。

以第二个例子,其使用方式如下:

javascript">const arr=[1,2,3,4];
      const arr2=[5,6,7,8];
    //   不可展开
      arr2[Symbol.isConcatSpreadable]=false;
      console.log(arr.concat(arr2))//[1, 2, 3, 4, Array(4)]

迭代器

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

ES6 创造了一种新的遍历命令 for...of 循环,Iterator 接口主要供 for...of 消费。原生具备 iterator 接口的数据(可用 for of 遍历)有:Array、Arguments、Set、Map、String、TypedArray、NodeList。

其工作原理如下:首先创建一个指针对象,指向当前数据结构的起始位置。第一次调用对象的 next 方法,指针自动指向数据结构的第一个成员。接下来不断调用 next 方法,指针一直往后移动,直到指向最后一个成员。每调用 next 方法返回一个包含 value 和 done 属性的对象。

javascript"> const study=['ES6','Vue','Webpack','CSS'];
        // 使用for...of遍历数组
        for(let item of study){
            console.log(item)
        }
        // 原理
        let iterator=study[Symbol.iterator]();
        // 调用对象的next方法
        console.log(iterator.next());//{value: 'ES6', done: false}
        console.log(iterator.next());//{value: 'Vue', done: false}
        console.log(iterator.next());//{value: 'Webpack', done: false}
        console.log(iterator.next());//{value: 'CSS', done: false}
        console.log(iterator.next());//{value: undefined, done: true}

它可以用于自定义遍历数据,以一个实例来进行演示,假如有一个对象,对象中有一个两个属性,一个为name,一个为study。study为一个数组,现在需要使用for...of来进行遍历(不考虑其他方式),该如何实现。

javascript">  const plan={
            name:'N-A',
            study:[
                'ES6',
                'Webpack',
                'Vue',
                'CSS'
            ],
            [Symbol.iterator](){
                // 声明索引变量
                let index=0;
                return{
                    next:()=>{
                        if(index<this.study.length){
                            const result={value:this.study[index],done:false};
                            index++;
                            return result;
                        }else{
                            return {value:undefined,done:true}
                        }
                        
                    }
                }
            }
            
        }
        for(let item of plan){
            console.log(item)
        }

生成器

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

javascript">  function* gen() {
            yield '一只没有耳朵';
            yield '一只没有尾巴';
            yield '真奇怪';
        }
        let iterator = gen();
        console.log(iterator.next());//{value: '一只没有耳朵', done: false}
        console.log(iterator.next());//{value: '一只没有尾巴', done: false}
        console.log(iterator.next());//{value: '真奇怪', done: false}
        console.log(iterator.next());//{value: undefined, done: true}

以上的代码* 的位置没有限制,可以偏左偏右或者处于中间。生成器函数返回的结果是迭代器对象,调用迭代器对象的 next 方法可以得到yield 语句后的值。yield 相当于函数的暂停标记,也可以认为是函数的分隔符,每调用一次 next方法,执行一段代码。next 方法可以传递实参,作为 yield 语句的返回值。

javascript"> function * gen(arg){
            console.log(arg);//AAAA
            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 iterator=gen('AAAA');
        console.log(iterator.next());
        // next方法传入实参
        console.log(iterator.next('BBB'));
        console.log(iterator.next('CCC'));
        console.log(iterator.next('DDD'));

同时还可以在next()中传入实参,传入的数据会作为上一次yield语句的返回结果。

应用实例如下:现在我们需要实现1s之后在控制台打印111,然后再过2s之后在控制台打印222,在过3s之后在打印333。可以使用传统的函数回调进行实现,但是代码的可读性以及维护性并不好,同时也会存在回调地狱的问题,因此使用生成器来实现具体如下:

javascript"> function one(){
        setTimeout(()=>{
            console.log(111);
            iterator.next();

        },1000)
      }
      function two(){
        setTimeout(()=>{
            console.log(222);
            iterator.next();
        },2000)
      }

      function three(){
        setTimeout(()=>{
            console.log(333);
            iterator.next();
        },3000)
      }
      function * gen(){
        yield one();
        yield two();
        yield three();
      }
    //   调用生成器函数
      let iterator=gen();
      iterator.next();

Promise">Promise

PromiseES6 引入的异步编程的新解决方案。语法上 Promise 是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果。

javascript">  // 实例化Promise对象
        const p=new Promise(function(resolve,reject){
            setTimeout(function(){
                let data='数据库中的数据';
                // 调用resolve,让其结果为成功,让p实例的状态为成功,会执行then方法中成功的回调。
                // resolve(data);
                // 让其状态为失败
                let err='请求失败';
                reject(err);
            })

        });
        // 调用promise对象的then()方法
        p.then(function(value){
            console.log(value);
        },function(reason){
            console.error(reason);
        })

首先需要实例化Promise对象,Promise()接受有个参数,该参数为一个函数,函数有两个参数:resolve以及reject。在后续调用resolve时,promise对象的状态就会变成成功,reject则会失败。当对象的状态发生改变时,就会调用then方法,该方法有两个函数,成功的回调函数以及失败的回调函数。若promise对象的状态为成功则执行成功的对调,否则执行失败的回调。

使用promise封装ajax请求具体实现如下:

javascript">        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) {
                    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中的then方法,返回的结果是一个Promise对象,对象的状态由回调函数的执行结果决定。如果回调函数中返回的结果是非promise类型的属性,状态为成功,返回的值为对象的成功的值。若没有return返回结果,则同样是成功的状态,只是对应的值为undefined。

javascript"> const p = new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve("用户数据");
            }, 1000)
        });
        const result = p.then(value => {
            console.log(value);
            return 1234;
        }, reason => {
            console.error(reason);
        });
        console.log(result);//[[PromiseState]]: "fulfilled" (代表成功)  [[PromiseResult]]:1234

若返回的是一个promise对象,then返回的状态则为return中promise对象的状态,其值也是对应的内部return中promise的值。

javascript"> const p = new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve("用户数据");
            }, 1000)
        });
        const result = p.then(value => {
            console.log(value);
            return new Promise((resolve,reject)=>{
                resolve('ok');
            });
        }, reason => {
            console.error(reason);
        });
        console.log(result);//[[PromiseState]]: "fulfilled" (代表成功)  [[PromiseResult]]:ok

若是抛出错误,则then返回的promise对象的状态为失败的状态,对应的值为抛出的值。

javascript"> const p = new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve("用户数据");
            }, 1000)
        });
        const result = p.then(value => {
            console.log(value);
           throw new Error('出错啦!')
        }, reason => {
            console.error(reason);
        });
        console.log(result);//[[PromiseState]]: "rejected"  [[PromiseResult]]:Error: 出错啦!

promise中的catch方法,相当于是then方法中的第二个回调函数,promise实例的状态失败时执行的方法。

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

Class

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

javascript">        class Phone{
            constructor(band,price){
                this.band=band;
                this.price=price;
            }
            call(){
                console.log("我可以电话!!")
            }
        }
        let type=new Phone("Huawei",5999);

class中的静态成员,使用static声明的属性以及方法属于类,并不属于实例对象。因此使用实例对象无法访问。具体代码如下:

javascript">      class Phone{
        // 声明静态属性
        static name='手机';
        static change(){
            console.log("我可以改变世界");
        }
      }
      let type=new Phone();
      console.log(type.name);//undefined
      console.log(Phone.name)//手机

同时还可以使用calss来实现继承,具体代码如下。子类可以对父类的方法进行重写,但是无法使用super来调用父类同名的方法。

javascript">      class Phone{
        constructor(brand,price){
            this.brand=brand;
            this.price=price;
        }
        call(){
            console.log("我可以打电话");
        }
      }

      class SmartPhone extends Phone{
        constructor(brand,price,color){
            super(brand,price);//相当于Phone.call(this,brand,price)
            this.color=color;
        }
        phone(){
            console.log("拍照")
        }
      }
      const type=new SmartPhone('小米',2987,'白色');

数值扩展

1.Number.EPSILON是js表示的最小进度。若两个数的差值小于它,就认为这两个数相等。

2.ES6 提供了二进制和八进制数值的新的写法,分别用前缀 0b 和 0o 表示。

3.Number.isFinite() 用来检查一个数值是否为有限的。Number.isNaN() 用来检查一个值是否为 NaN。

4.Number.parseInt() 与 Number.parseFloat() 。用于将字符串转为整数或者浮点数,若字符串中包含不能转化的字符,则不会在往后转换。

5.Math.trunc,用于去除一个数的小数部分,返回整数部分。

6.Number.isInteger() 用来判断一个数值是否为整数。

7.Math.sign,用于检测一个数为正数,负数或者为零。若为正数则会返回1,若为零则会返回0 ,若会负数则会返回-1。

对象方法扩展

1) Object.is 比较两个值是否严格相等,与===行为基本一致,主要区别在于Object.is判断两个NaN是返回的是true,而使用===返回的是false。

2) Object.assign 对象的合并,将源对象的所有可枚举属性,复制到目标对象。后面的对象会覆盖前面对象中具有同名的属性。若不同名则会合并。

3) Object.setPrototypeOf、 Object.getPrototypeOf 可以直接设置对象的原型,以及获取对象的原型。

模块化

模块化是指将一个大的程序文件,拆分成许多小的文件,然后将小文件组合起来。它可以防止命名冲, 代码复用以及使得代码的维护性更高。

ES6 之前的模块化规范有:1) CommonJS => NodeJS、Browserify 2) AMD => requireJS 3) CMD => seaJS

模块功能主要由两个命令构成:export 和 import。export 命令用于规定模块的对外接口。 import 命令用于输入其他模块提供的功能。暴露的方式如下

方法一:分别暴露,编写一个index.js文件,代码如下:

javascript">//分别暴露
export let name='N-A';
export function study(){
console.log("学习ES6新特性")
}

在主文件中使用通用的引入方式。

javascript"><script type="module">
    //引入index.js模块的内容,全部引入
    import * as m1 from "./src/js/index.js";
</script>

方法二:统一暴露,编写一个index.js文件,在主文件中进行引入,引入方法同上。代码如下:

javascript">//统一暴露
let name='N-A';
function study(){
console.log("学习ES6新特性")
}
export {name,study};

方式三:默认暴露,编写一个index.js文件,引入方法同上。代码如下:

javascript">//默认暴露
export default{
let name='N-A';
function study(){
console.log("学习ES6新特性")
}
}

如果使用该方法进行编写的话,在主文件中想要获取到相应的方法或者属性需要再增加一层default进行调用。

导入文件的方式除了上面提到的通用方法之外,还可以使用如下的方法。

javascript">//解构赋值形式
import {name,study} from "./src/js/index.js";
//若名字重复现需要其别名
import {name as ming,sport} from "./src/js/index2.js";
import {default as def} from "./src/js/index.js";
//简便形式,只能用于默认暴露的方式
import m from './src/js/index.js'

若引入的文件较多,都写在script标签中会使代码编写不简洁,因此可以单独地创建一个js文件来编写文件的import引入,然后再在主文件中的script标签通过src属性进行引入,然后script标签还需要增加一个type等于“module”的属性。


http://www.niftyadmin.cn/n/5198601.html

相关文章

C++17折叠表达式(Fold Expressions)

语法 template<typename... Args>( args op ... )&#xff08;一元右折叠&#xff09;( ... op args)&#xff08;一元左折叠&#xff09;( args op ... op init )&#xff08;二元右折叠&#xff09;( init op ... op args)&#xff08;二元左折叠&#xff09; 说明 …

软件测试/测试开发/人工智能丨基于Spark的分布式造数工具:加速大规模测试数据构建

随着软件开发规模的扩大&#xff0c;测试数据的构建变得越来越复杂&#xff0c;传统的造数方法难以应对大规模数据需求。本文将介绍如何使用Apache Spark构建分布式造数工具&#xff0c;以提升测试数据构建的效率和规模。 为什么选择Spark&#xff1f; 分布式计算&#xff1a;…

EI论文程序:Adaboost-BP神经网络的回归预测算法,可作为深度学习对比预测模型,丰富实验内容,自带数据集,直接运行!

适用平台&#xff1a;Matlab 2021及以上 本程序参考中文EI期刊《基于Adaboost的BP神经网络改进算法在短期风速预测中的应用》&#xff0c;程序注释清晰&#xff0c;干货满满&#xff0c;下面对文章和程序做简要介绍。 为了提高短期风速预测的准确性&#xff0c;论文提出了使用…

Using Set Processing Effectively 有效地使用集合处理

Using Set Processing Effectively 有效地使用集合处理 The information in the topics that follow applies if you are developing new or upgrading older Application Engine programs to adhere to a set-based model. 如果要开发新的应用程序引擎程序或升级旧的应用程序…

【NGINX--2】高性能负载均衡

1、HTTP 负载均衡 将负载分发到两台或多台 HTTP 服务器。 在 NGINX 的 HTTP 模块内使用 upstream 代码块对 HTTP 服务器实施负载均衡&#xff1a; upstream backend {server 10.10.12.45:80 weight1;server app.example.com:80 weight2;server spare.example.com:80 backup; …

day29_Servlet

今日内容 零、 复习昨日 一、Servlet 零、 复习昨日 一、Servlet 1.1 Servlet介绍 javaweb开发,就是需要服务器接收前端发送的请求,以及请求中的数据,经过处理(jdbc操作),然后向浏览器做出响应. 我们要想在服务器中写java代码来接收请求,做出响应,我们的java代码就得遵循tomca…

nginx的反向代理和负载均衡

目录 1、nginx的反向代理和负载均衡&#xff1a; 1.1四层代理和七层代理的区别&#xff1a; 1.2反向代理的作用&#xff1a; 1.3作为反向代理如何实现以及负载均衡的算法&#xff1a; 1.4负载均衡的算法&#xff1a; 总结&#xff1a; 四层和七层之间的区别&#xff1a;…

C语言--每日五道选择题--Day20

第一题 1. 在如下结构定义中&#xff0c;不正确的是&#xff08; &#xff09;。 A&#xff1a; struct student {  int no;  char name[10];  float score; }; B&#xff1a; struct stud[20] {  int no;  char name[10];  float score; }; C&#xff1a; struct stu…