ES6新特性速览

ES6新特性速览

2018-2-5 作者: 张子阳 分类: Web前端

引言

ES6引入了很多新的语言特性和能力,这篇文章仅快速地做一个概览。包括let、解构、箭头函数、模块化、Spread运算符 等。ES6还有很多更深入的内容,有时间再单独总结。大部分的ES6新特性,最新版的Chrome浏览器都原生支持,所以下面大多数代码不需要使用Babel转码器即可直接运行。但是模块化的import和export则暂未支持,只能通过Babel经过webpack等工具打包后使用。

let和var

let具有括号作用域,而var仅有函数作用域,没有括号作用域,因此在大多数情况下都推荐使用let。下面是简单的对比。

for(var i=0; i<3; i++){}
console.log(i); // 3

for(let j=0; j<3; j++){}
console.log(j); // Uncaught ReferenceError: j is not defined

使用var时,为了避免变量冲突,通常是使用立即执行函数来建立一个块级作用域:

(function(){
    var i = 1;
    console.log("a:", i); // 1    
})();

console.log("b:", i);     // Uncaught ReferenceError: i is not defined

如果是代码块,变量在代码块结束后依然会存在:

{
    var j = 1;
    console.log("a:", j); // 1   
}

console.log("b:", j);   // 1 

使用let则不会有这个问题:

{
    let i = 1;
    console.log("a:", i); // 1   
}

console.log("b:", i);  // Uncaught ReferenceError: i is not defined

一个典型的作用域问题是:遍历li对象,并赋予点击事件:

<ul>
    <li>项目A</li>
    <li>项目B</li>
    <li>项目C</li>
</ul>
var arr = document.querySelectorAll("li");

for(var i=0; i<arr.length; i++){
    arr[i].onclick = function(){
        alert("你点击了第"+ i +"个项目");
    }
}

console.log("i:", i); // 3

此时,不管点击哪个li,都会弹出“你点击了第3个项目”,因为在for循环结束后,i依然“活着”,并且值为3。

只需要将var i=0 改为 let i=0,则没有这个问题。而在let出现以前,传统的解决方案依然是利用函数作用域,将i作为立即执行函数的参数,写一个闭包函数:

var arr = document.querySelectorAll("li");

for(var i=0; i<arr.length; i++){
    (function(x){
        arr[x].onclick = function(){
            alert("你点击了第"+ x +"个项目");
        }    
    })(i);    
}

const

服务端的很多语言都有const,例如我比较熟悉的C#,顾名思义,变量用const声明后值不可以再变。

const PI = 3.1415926;
PI = 3;      // Uncaught TypeError: Assignment to constant variable.

const还有两个注意事项,1:声明时就需要赋值。

const PI;           // Uncaught SyntaxError: Missing initializer in const declaration
PI = 3.1415926;

2:如果是对象,可以修改内部值,但不能重新赋值。

const loc = { x:1 , y: 2}
loc.x = 3;
console.log(loc);       // {x:3, y:2}

loc = {}      // Uncaught TypeError: Assignment to constant variable.

箭头函数

箭头函数类似C#中的lambda表达式,大多数情况下,可以作为函数的简写形式。

function multiply(x){
    return x*2;
}

// 相当于
const multiply = (x) => {
    return x*2;
}

当函数体只有一行return时,可以再次简化,省略掉花括号和return关键字。

const multiply = (x) => x*2;

当只有一个输入参数时,参数的圆括号()也可以省略掉。(如果有多个参数或者没有参数,则必须有圆括号)。

const multiply = x => x*2;

var i = multiply(1);
console.log(i);     // 2

箭头函数和普通函数最重要的一个区别,就是this关键字绑定到了函数定义时的作用域,而非函数运行时的作用域。下面是一个例子:

function Product(){
    this.title = "NS Switch";
    
    this.showName1 = function(){
        console.log(this)
        console.log("showName1:", this.title);
    }
    
    this.showName2 = ()=>{
        console.log(this)
        console.log("showName2:", this.title);
    }
}

var p = new Product();

var showName1 = p.showName1;
var showName2 = p.showName2;
showName1();        // Uncaught TypeError: Cannot read property 'title' of undefined
showName2();        // NS Switch

setTimeout(p.showName1, 1000)   // this为window,this.title为undefined
setTimeout(p.showName2, 1000)   // NS Switch

import和export

import和export用于支持模块化(modules)。假设utility.js用来创建模块,而page.js使用该模块,则用法如下所示:

方式1:使用default关键字

// utility.js
const Person = {
    name : "jimmy"
}

export default Person
// page.js
import util from "./utility.js"

console.log(util);      // {name:"jimmy"}

方式2:多个对象时使用星号 *

// utility.js
export const Person = {
    name : "jimmy"
}

export const Student = {
    score: 100
}
// page.js
import * as util from "./utility.js"

console.log(util.Person);      // {name:"jimmy"}
console.log(util.Student);      // {score:100}

方式3:多个对象时使用析构

模块导出不变。模块引入才用下面的方式。

// page.js
import { Person, Student } from "./utility.js"

console.log(Person);      // {name:"jimmy"}
console.log(Student);      // {score:100}

Spread和Rest运算符

这两个运算符的表示方法都是三个点:...,根据使用的位置来区分。

Spread运算符:用于展开数组或者对象。

// 数组展开
var oldArr = [1,2,3]
var newArr = [0, ...oldArr, 4]
console.log(newArr);    // [0,1,2,3,4]
// 对象展开
var oldObj = { x:1, y:2}
var newObj = { ...oldObj, z:3 }
console.log(newObj);    // {x: 1, y: 2, z: 3}

需要注意的是,当新对象的属性名重复时,会进行覆盖:

var oldObj = { x:1, y:2}
var newObj = {...oldObj, y:3 }
console.log(newObj);    // {x: 1, y: 3}

Rest运算符:用于个数不定的函数参数

可以看到,实际上相当于将不定个数的函数参数合并成了数组。

function total(...args){
    var t = 0;
    for(let i=0; i< args.length;i++){
        t += args[i]
    }
    return t;
}
console.log(total(1,2)) // 3
console.log(total(3,4,5)) // 12

析构(destructering)

更方便地将数组元素或者对象属性提取出来保存到变量中。

// 析构数组
const arr = [1,2,3]
var [x, y] = arr;
console.log(x, y);    // 1, 2

var [, , z] = arr;
console.log(z);    // 3
// 析构对象
const obj = { x:1, y:2, z:3 }
var {x, z} = obj;
console.log(x, z); // 1, 3

感谢阅读,希望这篇文章能给你带来帮助!

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • .Net 框架

    对于在.NET框架(.NET Framework)下进行开发的程序员来说,无法回避的一个问题就是:什么是.NET框架?它包含了哪些内容?为开发程序提供了哪些支持...

    张子阳
  • 在Web站点中创建和使用Rss源

    Rss是将你Web站点的内容与其他人分享的标准方式。Rss代表着:Really Simple Syndication。它不过是一个标准化的XML标记,用于描述你...

    张子阳
  • ppk谈JavaScript

    这本书买得比较早,断断续续读了几次。这次花了一周时间重新读了一遍。总得来说,这本书中的部分理念,不说完全过时,但在现在的技术环境下也很难实现了。例如书中提到的“...

    张子阳
  • [OHIF-Viewers]医疗数字阅片-医学影像-es6解构赋值-const{}=-let{}=

    解构赋值语法是一种 Javascript 表达式。通过解构赋值, 可以将属性/值从对象/数组中取出,赋值给其他变量。

    landv
  • JS中数组解构赋值4

    用户7873631
  • JavaScript的概念,引入,基本数据类型

    JavaScript(下文我们会用简称JS来代替)是脚本编程语言,JS语言开发的文件是以.js为后缀,通过在html文件中引入该js文件来控制html代码的交互...

    小小咸鱼YwY
  • JavaScript基础

    JavaScript 从 Java 中借用其大部分语法,但也受 Awk,Perl 和 Python的影响。因此本篇博客基于对Java和Python的认识来记录J...

    职场亮哥
  • 解析浏览器和nodejs环境下console.log()的区别

    怎么会这样呢?在google和Safari的webkit中,console.log并没有立即拍摄对象快照,相反, 他只是存储了一个指向对象的引用,然后在代码返...

    Theone67
  • JavaScript正则表达式(Regular Expression):RegExp对象

    第一部分:新建正则表达式 JavaScript中正则表达式是参照Perl 5(一门历史很悠久的语言,现在tiobe编程语言排行依然在10名左右)建立的。 新建正...

    用户1149564
  • ES6(三):变量的解构赋值

    解构赋值语法是一个Javascript表达式,这使得可以将值从数组或属性从对象提取到不同的变量中,文中主要讲数组的解构赋值、对象的解构赋值、字符串的解构赋值、数...

    从入门到进错门

扫码关注云+社区

领取腾讯云代金券