JS 高级(六)ES6的特性与功能

简介: JS 高级(六)ES6的特性与功能

ES6: (ECMAScript第六个版本)

1. 模板字符串

       在旧 js 中,拼接字符串只能用+,这样极容易和算术计算的加法计算混淆,所以就需要用到模板字符串,它是一种支持换行、动态拼接内容的特殊字符串格式。


模板字符串的使用:


a. 整个字符串用一对儿反引号` `包裹;

b. 在反引号中可以写单引号,双引号,换行等;

c. 在反引号中凡是动态拼接的变量或 js 表达式都要放在 ${ } 中。


       在模板字符串的 ${ } 中,可以放变量、算术计算、三目、对象属性、创建对象、调用函数、访问数组元素等有返回值的合法的js表达式;但不能放没有返回值的js表达式,也不能放分支、循环等程序结构,比如: if  else  for  while...等。


举例:使用模板字符串动态拼接各种各样字符串;


<script>
    var uname = "卫国";
    console.log(`姓名:${uname}`);
    var sex = 1;
    console.log(`性别:${sex = 1 ? "男" : "女"}`);
    var price = 12.5;
    var count = 5;
    console.log(`
      单价:${price}
      数量:${count}
      ================
      小计:${price * count}
    `);
    var time = 1622773370370;
    console.log(`下单时间:${new Date(time).toLocaleString()}`);
    var day = new Date().getDay();
    var arr = ["日", "一", "二", "三", "四", "五", "六"];
    console.log(`今天星期${arr[day]}`);
  </script>

打印结果如图:

image.png


2. let

       在以往的 js 程序中,我们都是用 var 关键字来声明变量,但是这样会有两个问题:


       首先是会声明提前,打乱程序正常的执行顺序;其次没有块级作用域,导致代码块内的变量会超出代码块的范围,影响外部的变量。


       块级作用域:JS 中没有,在其他语言中指除了对象 { } 和 function 的 { } 之外,其余 if  else、for、等程序结构的 {} 范围。但是,在 js 中这些 { },都不是作用域,所以拦不住内部的局部变量声明被提前。


        解决以上两个问题的方法就是使用 let 关键字代替 var 关键字来声明变量。如下举例:


<script>
    // 定义全局变量
    var t = 0;
    function fun1() {
      //var t;//undefined
      console.log(`函数一用时6s`);
      t += 6;
      // 此处添加如下代码(不执行)
      if (false) {
        var t = new Date(); //此处的t被提前到了当前函数fun1的首部,待执行t+=6时,t的值为undefined+6;无法计算,所以结果却少了6秒,且因为if(false)该语句不执行。
        //-----------------------------------------------------------------------------
        // 解决方式:
        // 将var改为使用let声明变量,第一种写法:
        // let t  =new Date();
        // let底层相当于匿名函数自调,所以第二种写法:
        // (function (true) {
        //   var t = new Date();
        //   console.log(`上线时间:${t.toLocaleString()}`)
        // })();
        //------------------------------------------------------------------------------
        console.log(`上线时间:${t.toLocaleString()}`)
      }
    }
    function fun2() {
      console.log(`函数二用时4s`);
      t += 4;
    }
    fun1(); //函数一用时6s
    fun2(); //函数一用时4s
    console.log(`共耗时:${t}秒`); //使用var时的打印结果:共耗时4秒   缺少了函数一的6秒
  </script>

       let 关键字与 var 相比,不会被声明提前,可以保证程序顺序执行;还可以让程序块也变成了块级作用域(并没有真正变成块级,只是采用了匿名函数自调的方式),保证块内的变量不会影响块外的变量。


       注意:let 关键字底层的本质其实就是匿名函数自调。


let 关键字的三个特点:


a. 因为不会声明提前,所以不能在声明变量之前,提前使用该变量。

b. 在相同作用域内,禁止声明两个同名的变量!

c. let 底层相当于匿名函数自调,所以,即使在全局创建的 let 变量,在 window 中也找不到!


<script>
    console.log(a);
    // 1.禁止在声明之前,提前使用该变量
    //console.log(b); //报错:Cannot access 'b' before initialization
    let b = 100;
    console.log(b);
    // 2.相同作用域内,不允许重复声明同名变量
    var a = 10;
    //let a = 100; //报错:Identifier 'a' has already been declared
    // 3.即使在全局let的变量,在window也找不到
    var c = 10; 默认保存在window对象中
    console.log(c); //10
    console.log(window.c); //10
    console.log(window["c"]); //10
    (function () {
      let d = 100;
      console.log(d); //100
    })();
    console.log(window.d); //undefined
    console.log(window["d"]); //undefined
  </script>

3. 箭头函数

       箭头函数是对绝大多数匿名函数的简写,今后几乎所有匿名函数都可用箭头函数简化。箭头函数的简化方法遵循三个原则:


       a. 去掉 function,在()和{}之间加=>

       b. 如果只有一个形参,则可以省略( )

       c. 如果函数体只有一句话,则可以省略{ };函数体仅剩的一句话是 return,则必须去掉 return。


举例:将各种 function 改为箭头函数;


<script>
    // -------------------------------------------------
    // function add(a, b) {
    //   return a + b;
    // }
    var add = (a, b) => a + b; //箭头函数写法
    console.log(add(3, 5)); //8
    // -------------------------------------------------
    var arr = [12, 123, 23, 1, 3, 2];
    // arr.sort(function (a, b) {
    //   return a - b
    // });
    arr.sort((a, b) => a - b); //箭头函数写法
    console.log(arr);
    // -------------------------------------------------
    var arr = ["亮亮", "楠楠", "东东"];
    // arr.forEach(function (elem) {
    //   console.log(`${elem} - 到!`)
    // })
    arr.forEach(elem => console.log(`${elem} - 到!`)); //箭头函数写法
    // -------------------------------------------------
    var arr = [1, 2, 3];
    // var arr2 = arr.map(function (elem) {
    //   return elem * 2;
    // })
    var arr2 = arr.map(elem => elem * 2); //箭头函数写法
    console.log(arr2);
    // -------------------------------------------------
    var arr = [1, 2, 3, 4, 5];
    // var sum = arr.reduce(function (box, elem) {
    //   return box + elem;
    // }, 0)
    var sum = arr.reduce((box, elem) => box + elem, 0); //箭头函数写法
    console.log(sum);
    // -------------------------------------------------
    // (function () {
    //   var t = new Date();
    //   console.log(`页面内容加载完成,at:${t.toLocaleString()}`);
    // })();
    (() => { //箭头函数写法
      var t = new Date();
      console.log(`页面内容加载完成,at:${t.toLocaleString()}`);
    })();
    // -------------------------------------------------
    var t = 5;
    // var timer = setInterval(function () {
    //   t--;
    //   console.log(t);
    //   if (t == 0) {
    //     console.log("boom!!!")
    //     clearInterval(timer);
    //   }
    // }, 1000);
    var timer = setInterval(() => { //箭头函数写法
      t--;
      console.log(t);
      if (t == 0) {
        console.log("boom!!!")
        clearInterval(timer);
      }
    }, 1000)
  </script>

箭头函数与 this


       在常规的写法中,当对象中方法需要通过 this 调用属性时,会出现一定的问题,如下代码:


<script>
    var lilei = {
      sname: "卫国",
      friends: ["宝国", "爱国", "建国", "护国"],
      intr() {
        this.friends.forEach(
          function (n) {
            console.log(`${this.sname}是${n}的哥哥!`);
          }
        )
      }
    }
    lilei.intr();
  </script>

this.friends.forEach 语句中的 this 指代对象 lilei,可以正常调用,但是函数 function 在打印时仍然用到了 this.sname,需要注意,此处的this已经不再指代对象 lilei,由于它处于 function 函数当中,默认指代 window(全局),而全局中是不存在 sname 属性的。以上代码打印效果如下:

image.png

uname 显示为 undefined。


       为了解决此问题,我们便可用箭头函数,箭头函数可让函数内的this与函数外的 this 保持一致。所以将以上对象中的函数改用箭头函数:


<script>
    var lilei = {
      sname: "卫国",
      friends: ["宝国", "爱国", "建国", "护国"],
      intr() {
        this.friends.forEach(
          // 使用箭头函数
          n => console.log(`${this.sname}是${n}的哥哥!`)
        )
      }
    }
    lilei.intr();
  </script>

显示效果如下:


image.png


所以,我们可以得出结论:


a:如果函数中不包含 this,或希望函数内的this与外部 this 保持一致时,就可以改为箭头函数;

b:如果不希望函数内的 this 与函数外的 this 保持一致时,就都不能改为箭头函数。


4. for of

       遍历数字下标的数组或者类数组对象 arguments 时,可以用到多种循环;普通 for 循环既可遍历索引数组,又可以遍历类数组对象,但没有可简化的空间;forEach 循环可以配合 ES6 的箭头函数,很简化,但无法用于遍历类数组对象。


ES6 中提供了 for of 循环,只要遍历数字下标,都可用 for of 代理普通 for 循环和 forEach;格式如下:


for(var 变量  of  索引数组/类数组对象){
    //of会依次取出数组或类数组对象中每个属性值
    //自动保存of前的变量中
  }

举例:使用 for of 点名,并实现计算任意多个数字的和;


<script>
    // 点名
    var arr = ["小红", "小兰", "小绿", "王刚"]
    // for循环遍历
    // for (var i = 0; i < arr.length; i++) {
    //   console.log(`${arr[i]} - 到!`);
    // }
    // for-of遍历
    for (var t of arr) {
      console.log(`${t} - 到!`);
    }
    // 定义函数求任意多个数之和
    function add() {
      var result = 0;
      //for循环遍历
      // for (j = 0; j < arguments.length; j++) {
      //   result += arguments[j]
      // }
      // for-of遍历
      for (var n of arguments) {
        result += n;
      }
      return result;
    }
    console.log(add(1, 4, 5)); //10
  </script>

       然而 for of 也存在以一些问题,无法获得下标位置i,只能获得元素值;更无法控制遍历的顺序或步调。但是绝大多数循环都是从头到尾,一个接一个遍历的,且绝大多数循环不太关心下标位置,只关心元素值,所以 for of 将来用的还是非常多的!


各类循环区分:


image.png

总结起来就是:下标为数字选 for of,下标为自定义字符串选 for in。


5. 参数增强

参数默认值

       调用函数时,如果不传入实参值,虽然语法不报错,但是形参会默认为 undefined,而Undefined 极容易造成程序错误!所以在调用函数时,不传入实参值时,为了使形参变量也有默认值可用,不至于是 undefined,就用到默认值。格式如下:


function 函数名(形参1=默认值1, 形参2=默认值2, ...){

    //调用函数时,给形参传了实参值,则首选用户传入的实参值。如果没有给形参传是实参值,则形参默认启用=右边的默认值。

  }

举例:使用参数默认值解决订套餐问题;


<script>
    // 定义一个点套餐的函数
    function order(
      zhushi = "香辣鸡腿堡",
      xiaochi = "烤鸡翅",
      yinliao = "可乐"
    ) {
      console.log(`
        您点的套餐为:
        主食:${zhushi}
        小吃:${xiaochi}
        饮料:${yinliao}
        `);
    }
    // a点默认套餐
    order();
    // b自定
    order("牛肉汉堡", "鸡米花", "雪碧");
    // c只换主食
    order("烤鸡");
  </script>

剩余参数(rest)

       箭头函数虽然好用,但不支持类数组对象 arguments,如果箭头函数遇到参数个数不确定时,就需要用剩余参数语法来代替 arguments。格式:


var 函数名=( ...数组名 )=>{

     //将来传入函数的所有实参值,都会被...收集起来,保存到...会指定的数组中。

   }

       剩余参数的优点是支持箭头函数,生成的数组是纯正的数组类型,所以可使用数组家所有函数自定义数组名,比 arguments 简单的多。而且还可以和其它形参配合使用,只获得其它形参不要的剩余参数。格式如下:


var 函数名=(形参1, 形参2,...数组名)=>{ }

举例:使用剩余参数语法计算不同员工的总工资;


<script>
    // 定义计算员工总工资的函数
    function add(ename, ...arr) {//计算除ename之外的剩余参数
      console.log(arr);
      var total = arr.reduce(
        function (m, n) {
          return m + n;
        },
        0
      );
      console.log(`${ename}的总工资为:${total}`);
    }
    add("李雷", 10000, 200, 3000);
    add("韩梅梅", 5000, 500, 300, 1200, 200);
  </script>

展开运算符(spread)

       apply 拆散数组时,强迫我们必须提供一个替换 this 的对象,那是因为 apply() 本职工作不是拆散数组,而是替换 this,是在替换 this 同时,顺便拆散数组。所以,今后若希望单纯拆散数组,都用...展开运算符。格式:


函数名(...数组);

展开运算符的原理是...先将数组拆散为多个实参值,再依次分别传给函数的每个形参变量。


举例:获取数组中的最大值

<script>
    // 获取数组中的最大值
    var arr = [1, 5, 6, 8];
    // 错误写法
    console.log(Math.max(1, 5, 6, 8));
    console.log(Math.max(arr));
    // 正确,但必须提供一个替换this的对象
    console.log(
      Math.max.apply(null, arr),
      Math.max.apply(arr, arr),
      Math.max.apply("", arr),
      Math.max.apply(Math, arr)
    );
    // 使用展开运算符
    console.log(Math.max(...arr));
  </script>

语法糖(拓展):


       i. 复制一个数组: var arr2=[...arr1];

       ii. 合并多个数组和元素值: var arr3=[...arr1,值,...arr2,值];

       iii. 复制一个对象: var obj2={ ... obj1 }

       iv. 合并多个对象和属性: var obj3={ ...obj1, 属性:值, ...obj2, 属性:值 }


相关文章
|
21天前
|
JavaScript 前端开发 容器
jQuery多功能滑块插件r-slider.js
r-slider.js是一款jQuery多功能滑块插件。使用该插件,可以制作出滑块、开关按钮、进度条、向导步骤等多种效果。
29 5
|
23天前
|
JavaScript 前端开发 安全
JavaScript与TypeScript的对比,分析了两者的特性及在实际项目中的应用选择
本文深入探讨了JavaScript与TypeScript的对比,分析了两者的特性及在实际项目中的应用选择。JavaScript以其灵活性和广泛的生态支持著称,而TypeScript通过引入静态类型系统,提高了代码的可靠性和可维护性,特别适合大型项目。文章还讨论了结合使用两种语言的优势,以及如何根据项目需求和技术背景做出最佳选择。
42 4
|
28天前
|
JavaScript 前端开发 安全
ECMAScript 6(以下简称 ES6)的出现为 JavaScript 带来了许多新的特性和改进,其中 let 和 const 是两个非常重要的关键字。
ES6 引入了 `let` 和 `const` 关键字,为 JavaScript 的变量管理带来了革新。`let` 提供了块级作用域和暂存死区特性,避免变量污染,增强代码可读性和安全性;`const` 用于声明不可重新赋值的常量,但允许对象和数组的内部修改。两者在循环、函数内部及复杂项目中广泛应用,有助于实现不可变数据结构,提升代码质量。
26 5
|
28天前
|
自然语言处理 JavaScript 前端开发
ECMAScript 6 的出现为 JavaScript 带来了许多新的特性和改进
这些只是ES6的一些主要特性,它们极大地增强了JavaScript的功能和表现力,使得JavaScript在大型应用开发、前端框架等领域能够更加高效地编写复杂的应用程序。
|
1月前
|
JavaScript
js实现简洁实用的网页计算器功能源码
这是一款使用js实现简洁实用的网页计算器功能源码。可实现比较基本的加减乘除四则运算功能,界面简洁实用,是一款比较基本的js运算功能源码。该源码可兼容目前最新的各类主流浏览器。
24 2
|
1月前
|
存储 JavaScript 前端开发
JS的ES6知识点
【10月更文挑战第19天】这只是 ES6 的一些主要知识点,ES6 还带来了许多其他的特性和改进,这些特性使得 JavaScript 更加现代化和强大,为开发者提供了更多的便利和灵活性。
25 3
|
2月前
|
JavaScript 前端开发 编译器
掌握现代化JavaScript:ECMAScript提案与特性
【10月更文挑战第13天】本文介绍了ECMAScript(ES)的最新提案与特性,包括可选链、空值合并运算符、类字段和顶层Await等。通过跟踪TC39提案、使用Babel或TypeScript、测试兼容性以及逐步迁移,开发者可以高效地采用这些新特性,简化代码、提高开发效率并增强应用功能。文章还提供了实战技巧,帮助开发者在现代Web开发中充分利用这些现代化的特性。
|
2月前
|
JavaScript 前端开发 索引
JavaScript ES6及后续版本:新增的常用特性与亮点解析
JavaScript ES6及后续版本:新增的常用特性与亮点解析
56 4
|
2月前
|
人工智能 JavaScript 网络安全
ToB项目身份认证AD集成(三完):利用ldap.js实现与windows AD对接实现用户搜索、认证、密码修改等功能 - 以及针对中文转义问题的补丁方法
本文详细介绍了如何使用 `ldapjs` 库在 Node.js 中实现与 Windows AD 的交互,包括用户搜索、身份验证、密码修改和重置等功能。通过创建 `LdapService` 类,提供了与 AD 服务器通信的完整解决方案,同时解决了中文字段在 LDAP 操作中被转义的问题。
|
2月前
|
自然语言处理 JavaScript 前端开发
JavaScript高级——ES6基础入门
JavaScript高级——ES6基础入门
31 1