ES6 速成班

一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...点击查看项目介绍 ;
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;

截止目前, 星球 内专栏累计输出 63w+ 字,讲解图 2808+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2200+ 小伙伴加入学习 ,欢迎点击围观

是的,这是另一篇关于学习 es2015(称为 es6)的文章。这是我的学习之旅,也是我的个人记事本,记录我一路上发现的新事物。随时建议新的或遗漏的部分或 为本文做出贡献 。它是开源的,在 github 上。

浏览器兼容性

es6 或 es2015 现在的官方称呼已于 2015 年 6 月发布 。因此浏览器开始实现其功能。有些已经处于良好的水平,您可以轻松在线。 kangax 是显示当前浏览器支持的示例之一

无论浏览器支持如何,从现在开始,人们将不得不依赖转译器来确保您的代码顺利运行,即使底层浏览器不完全支持所有最新的语言功能。为什么?好吧,对于名称 es2015 tc39 委员会 明确建议更频繁地每年发布一次。事实上,es7 或更好的 es2016 已经在路上了。

最受欢迎的转译器肯定是

  • babeljs - 以前的 es6-to-5 并在本教程中使用
  • 示踪剂

addy osmani 在 github 上有一个更完整的 es6-tools 列表

工装

现在尝试 es6 的最简单方法可能是在 jsbin.com 上,而无需设置本地工作站。

在 jsbin.com 上设置 es6/babel

只需创建一个新的“bin”,然后选择“es6/babel”作为你的语言。

好的,现在我们已经准备就绪,可以开始了。

let 阻止作用域

es5 定义的变量范围与目前流行的许多其他流行语言完全不同。这会造成一些麻烦,尤其是对于新手程序员,但不仅如此。 es5 具有所谓的 函数作用域 ,而不是您期望的 块作用域


 function somefunc(){
  console.log('entering in somefunc');
  if(true){
    var x = 'hi there';
  }

console.log(x); }

这是完全合法的 javascript 代码并将以下内容打印到控制台:


 function somefunc(){
  console.log('entering in somefunc');
  if(true){
    var x = 'hi there';
  }

console.log(x); }

如您所见, x 在 if 块之外也是可见的。虽然上面的示例非常清楚,但这可能会导致非常奇怪且难以阅读的代码。代码的输出是什么?


 function somefunc(){
  console.log('entering in somefunc');
  if(true){
    var x = 'hi there';
  }

console.log(x); }

它打印: 10

通过使用 let es6 允许您像预期的那样阻止变量的作用域 。让我们通过将 var 更改为 let 来调整上面的示例:


 function somefunc(){
  console.log('entering in somefunc');
  if(true){
    var x = 'hi there';
  }

console.log(x); }

这次,我们得到一个错误。显然(java 程序员会说)。


 function somefunc(){
  console.log('entering in somefunc');
  if(true){
    var x = 'hi there';
  }

console.log(x); }

虽然您 仍然可以使用 var ,但建议的新方法是切换为 let 。所以……开始习惯了。

亲自尝试一下: 点击这里

在你的代码中重新定义变量?不是 es6,坏孩子!

在 es5 中,这是完全合法的:


 function somefunc(){
  console.log('entering in somefunc');
  if(true){
    var x = 'hi there';
  }

console.log(x); }

显然,“重用”变量不是您想要做的事情,而是您很可能无意中引入了它。我想你可以想象由此产生的讨厌的错误。幸运的是 ,当你在同一个块中重新定义同一个变量时,es6 会抛出一个错误 。但是,您必须使用 let


 function somefunc(){
  console.log('entering in somefunc');
  if(true){
    var x = 'hi there';
  }

console.log(x); }

结果:

重新定义 let 变量时出错

相反, 在子范围内重新定义变量是有效的 ,并导致覆盖先前定义的变量:


 function somefunc(){
  console.log('entering in somefunc');
  if(true){
    var x = 'hi there';
  }

console.log(x); }

输出是:


 function somefunc(){
  console.log('entering in somefunc');
  if(true){
    var x = 'hi there';
  }

console.log(x); }

亲自尝试一下: 点击这里

带有 const 真常量

es5 中的常量只不过是简单的命名约定,比如在变量前加上 const 前缀: var const_pi = 3.141 。但是,没有什么会妨碍您在运行时更改值。

在 es6 中,终于有一个 const 关键字可以满足您的期望。


 function somefunc(){
  console.log('entering in somefunc');
  if(true){
    var x = 'hi there';
  }

console.log(x); }

如果您尝试写入变量,它会在运行时抛出异常。

尝试设置 const 字段时出错

但是请注意,您还可以将对象分配给 const 变量。不过,分配的是对象引用。因此,通过将另一个对象分配给变量来更改对象引用是行不通的,但您绝对可以更改对象的属性。


 function somefunc(){
  console.log('entering in somefunc');
  if(true){
    var x = 'hi there';
  }

console.log(x); }

亲自尝试一下: 点击这里

const 变量的范围是 block scope ,这完全有道理。

... 运营商:传播和休息传播

你还记得 function.prototype.apply function.prototype.call 吗?不确定我在谷歌上搜索了多少次“应用与调用”文章,因为我不记得两者中哪一个接受数组,哪个接受参数系列。

apply 通常用于将未知数量的函数参数转发给另一个函数。


 function somefunc(){
  console.log('entering in somefunc');
  if(true){
    var x = 'hi there';
  }

console.log(x); }

人们这样做的原因有很多,但我现在不想详细说明。这里重要的是上面的代码是不可读的,对吧?人们立即想到:“apply 是做什么的?”和“‘争论’从何而来?”。总的来说,没有 JavaScript 经验的开发人员很难理解。

扩展运算符允许我们以更优雅的方式编写示例:


 function somefunc(){
  console.log('entering in somefunc');
  if(true){
    var x = 'hi there';
  }

console.log(x); }

现在很明显,我们正在调用函数 anotherfunction 并且我们传递了由其他人传入的可变数量的参数。

展开运算符不仅对函数调用有用,而且在 操作数组 时也很有用。这是一个简单的场景:你知道如何在 javascript 中连接两个数组吗?比如,拥有一个数组并将另一个数组的元素推入第一个数组?


 function somefunc(){
  console.log('entering in somefunc');
  if(true){
    var x = 'hi there';
  }

console.log(x); }

es6代码:


 function somefunc(){
  console.log('entering in somefunc');
  if(true){
    var x = 'hi there';
  }

console.log(x); }

更具可读性,不是吗?你甚至可以这样做:


 function somefunc(){
  console.log('entering in somefunc');
  if(true){
    var x = 'hi there';
  }

console.log(x); }

亲自尝试一下: 点击这里

休息

不,它与休息(代表性状态转移)无关。其余参数是捕获“其余参数”的一系列函数参数中的最后一个。


 function somefunc(){
  console.log('entering in somefunc');
  if(true){
    var x = 'hi there';
  }

console.log(x); }

我什至不打算详细说明如何在 es5 中执行此操作(让我们忘记过去)。它与从 arguments 值“切片”到传递给当前函数的参数数量等有关......

解构赋值

解构赋值是将可迭代对象的值赋给变量的过程。 ponyfoo 最近还发布了您可能感兴趣的关于解构的深入指南

数组解构


 function somefunc(){
  console.log('entering in somefunc');
  if(true){
    var x = 'hi there';
  }

console.log(x); }

执行此代码, juri thomas 将从分配的 myarray 中获取相应的值。

亲自尝试一下: 点击这里

通过 将解构与 ... 运算符相结合, 您可以获得更有趣的用例(也通常从函数式编程语言中得知)。提取列表的头部或尾部变得非常容易。


 function somefunc(){
  console.log('entering in somefunc');
  if(true){
    var x = 'hi there';
  }

console.log(x); }

亲自尝试一下: 点击这里

有了这个,再加上一点递归,求和函数可以定义为……


 function somefunc(){
  console.log('entering in somefunc');
  if(true){
    var x = 'hi there';
  }

console.log(x); }

亲自尝试一下: 点击这里

还有更多:您可以 在应用解构运算符时忽略值


 function somefunc(){
  console.log('entering in somefunc');
  if(true){
    var x = 'hi there';
  }

console.log(x); }

对象解构

与数组类似,解构也适用于对象。甚至语法也很相似:


 function somefunc(){
  console.log('entering in somefunc');
  if(true){
    var x = 'hi there';
  }

console.log(x); }

唯一可能看起来很奇怪的是您必须用大括号括起表达式。

亲自尝试一下: 点击这里

现在,在上面的示例中 ,变量名称必须与 object 中的名称相匹配 。情况可能并非总是如此。但是 es6 有一个解决方案。


 function somefunc(){
  console.log('entering in somefunc');
  if(true){
    var x = 'hi there';
  }

console.log(x); }

你可以让它更短(虽然不确定那是你想要的):


 function somefunc(){
  console.log('entering in somefunc');
  if(true){
    var x = 'hi there';
  }

console.log(x); }

默认值

如果在解构期间不存在给定值怎么办?应用默认值!


 function somefunc(){
  console.log('entering in somefunc');
  if(true){
    var x = 'hi there';
  }

console.log(x); }

我对函数参数的默认值更加兴奋:


 function somefunc(){
  console.log('entering in somefunc');
  if(true){
    var x = 'hi there';
  }

console.log(x); }

目前你必须这样写


 function somefunc(){
  console.log('entering in somefunc');
  if(true){
    var x = 'hi there';
  }

console.log(x); }

另一个有趣的用例是将 默认值与对象解构 结合起来。


 function somefunc(){
  console.log('entering in somefunc');
  if(true){
    var x = 'hi there';
  }

console.log(x); }

这种检查很麻烦,并且在嵌套对象时变得更加奇怪。


 function somefunc(){
  console.log('entering in somefunc');
  if(true){
    var x = 'hi there';
  }

console.log(x); }

亲自尝试一下: 点击这里

链接

  • mdn: 解构赋值
  • 箭头函数

    如果您是经验丰富的 JavaScript 开发人员,这应该看起来很熟悉:

    
     function somefunc(){
      console.log('entering in somefunc');
      if(true){
        var x = 'hi there';
      }
    

    console.log(x); }

    这是一个 jquery 单击处理程序的示例。注意到 var that = this 行了吗?这是您必须处理的解决方法 - 主要是在声明回调时 - 以调整 this 的值。回调中 this 的值指向调用回调的函数,而不是回调已实现的外部范围。通常,你想要后者,这就是为什么使用像 var that = this var self = this 的“hacks”。

    亲自尝试一下: 点击这里

    jquery 甚至有一个 jquery.proxy 来帮助你解决这个问题,但我很少看到它被使用。

    es2015 引入了在其运算符之后表示的箭头函数: => 。他们帮助应对这些情况。

    
     function somefunc(){
      console.log('entering in somefunc');
      if(true){
        var x = 'hi there';
      }
    

    console.log(x); }

    因此,上面的内容可以改写为:

    
     function somefunc(){
      console.log('entering in somefunc');
      if(true){
        var x = 'hi there';
      }
    

    console.log(x); }

    亲自尝试一下: 点击这里

    与许多 javascript 评论家(主要是那些不太了解 javascript 的人)相反,该语言是完全面向对象的。在 es5 中创建对象的新实例非常简单

    
     function somefunc(){
      console.log('entering in somefunc');
      if(true){
        var x = 'hi there';
      }
    

    console.log(x); }

    通过这种方式,您可以直接创建并实例化一个新类,您可以立即使用它:

    
     function somefunc(){
      console.log('entering in somefunc');
      if(true){
        var x = 'hi there';
      }
    

    console.log(x); }

    如您所见,您可以在对象本身上设置属性和调用方法/函数。
    在 es5 中还有另一种定义对象的方法,使用所谓的构造函数,然后通过对象的原型扩展该函数。

    
     function somefunc(){
      console.log('entering in somefunc');
      if(true){
        var x = 'hi there';
      }
    

    console.log(x); }

    为了能够使用这样的类,它 必须 使用 new 关键字实例化。

    
     function somefunc(){
      console.log('entering in somefunc');
      if(true){
        var x = 'hi there';
      }
    

    console.log(x); }

    大多数服务器端开发人员对这种方法感觉更舒服。我的意思是,实例化人的第一行是完全有效的 C# 代码!
    关于这是否是一件好事,网络上有很长一段时间的争论(只需谷歌搜索原型继承与经典继承)。我现在不打算在这里概述它。过去的东西。

    类定义

    es2015 对类有原生支持……围绕它们的讨论仍在继续。但让我们看看技术细节:

    
     function somefunc(){
      console.log('entering in somefunc');
      if(true){
        var x = 'hi there';
      }
    

    console.log(x); }

    很简单,不是吗?没有告诉你我在 getfullname() 函数中使用了另一个很酷的特性: 模板字符串 。但稍后会详细介绍。

    另一个重要的事情是 类没有提升 ,这意味着 - 与函数不同 - 你不能在定义之前调用/实例化一个类。

    吸气剂和吸气剂

    类可以为属性设置 getter 和 setter,这就像在方法之前放置 get set 一样简单。

    
     function somefunc(){
      console.log('entering in somefunc');
      if(true){
        var x = 'hi there';
      }
    

    console.log(x); }

    亲自尝试一下: 点击这里

    静态方法

    静态方法可以定义如下:

    
     function somefunc(){
      console.log('entering in somefunc');
      if(true){
        var x = 'hi there';
      }
    

    console.log(x); }

    遗产

    你试过在 es5 中继承吗?? 您必须使用原型链并将它们之间的对象连接起来。请参阅下面的代码链接。

    亲自尝试一下: 点击这里

    了解原型链的工作原理并不难,但阅读该代码却一团糟。

    我尝试在 es2015 中重写上面的例子。

    亲自尝试一下: 点击这里

    不确定你,但对我来说,这更具可读性。它主要是语法糖,但更简洁。请注意,用法完全相同!

    动态方法名

    方法名称也可以在运行时确定。就在 es5 中,您可以使用数组符号 aperson['firstname'] 调用对象的属性/函数,您还可以在 es2015 类中定义此类方法:

    
     function somefunc(){
      console.log('entering in somefunc');
      if(true){
        var x = 'hi there';
      }
    

    console.log(x); }

    显然也适用于静态方法。此类动态或计算属性的一个有趣用例是当您使用 es2015 符号数据类型作为方法名称时。想一想。

    亲自尝试一下: 点击这里

    模块

    就个人而言,模块是我最喜欢 es2015 的地方。到目前为止,在浏览器应用程序中有不同的模块方法。

    最简单的形式,一个 iife(立即调用的函数表达式):

    
     function somefunc(){
      console.log('entering in somefunc');
      if(true){
        var x = 'hi there';
      }
    

    console.log(x); }

    主要目标:创建私有范围,避免命名冲突并有选择地向外界发布功能。但是一旦必须异步加载“dependency1”和“dependency2”,事情就会变得一团糟。

    这就是 amd 和 commonjs 发挥作用的地方,旨在标准化模块的创建和加载方式。 addy osmani 写了整篇关于如何编写模块化 javascript 的 在线文章

    所以基本上你到目前为止所拥有的是

    
     function somefunc(){
      console.log('entering in somefunc');
      if(true){
        var x = 'hi there';
      }
    

    console.log(x); }

    受害最大的是:可读性。嵌套级别很高,即使可以通过良好的缩进以某种方式减轻它。

    es2015 中的相同模块定义

    
     function somefunc(){
      console.log('entering in somefunc');
      if(true){
        var x = 'hi there';
      }
    

    console.log(x); }

    很好,不是吗?

    非常简单,一个模块支持两种导出:

    • 默认导出(只能是一个)
    • 命名导出

    不应该混合。例如:

    
     function somefunc(){
      console.log('entering in somefunc');
      if(true){
        var x = 'hi there';
      }
    

    console.log(x); }

    通过这种方式,模块可以在外部使用

    
     function somefunc(){
      console.log('entering in somefunc');
      if(true){
        var x = 'hi there';
      }
    

    console.log(x); }

    同样,如果我们将上面的示例转换为默认导出,它看起来像

    
     function somefunc(){
      console.log('entering in somefunc');
      if(true){
        var x = 'hi there';
      }
    

    console.log(x); }

    ..然后将被消费为

    
     function somefunc(){
      console.log('entering in somefunc');
      if(true){
        var x = 'hi there';
      }
    

    console.log(x); }

    (更多即将推出...)

    更多即将到来。本文是逐步编写的。当发布新更新时,您将通过 @juristr 我的 rss feed 收到通知。

    相关文章