了解es6(声明、解构、模板字符串)

ES6简介

ECMAScript 6.0(以下简称 ES6)是 JavaScript 语言的下一代标准,已经在 2015 年 6 月正式发布了。它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。

一、ES6之let和const的使用

1.1块级作用域

在ES5之前,不存在块级作用域,在编程的时候很多时候会带来很多的不便,ES6新增了块级作用域,补足了这方面的缺陷。

块级声明指的是该声明的变量无法被代码块外部访问。块作用域,又被称为词法作用域(lexical scopes),可以在如下的条件下创建:

  • 函数内部
  • 在代码块(即 { })内部

块级作用域是很多类C语言的工作机制,ECMAScript 6 引入块级声明的目的是增强 JavaScript 的灵活性,同时又能与其它编程语言保持一致。

1.2 let声明

使用let声明变量的语法和使用var声明的语法是一样的。但是let声明的变量的作用域会限制在当前的代码块中。这是let与var的最大区别。

<script type="text/javascript">
    /***  var 和 ES6 let对比 ****/
        {
            var a = 10;
            let b = 20;
        }

        console.log(a);
        // 因为let声明后具有块级作用域 出了代码块后就访问不到 说报错
        console.log(b);
</script>

<script type="text/javascript">
    //在for循环中的使用
      for (var i = 0; i < 5; i++) {

      }

      console.log(i);

      for (let j = 0; j < 5; j++) {

      }
      //这里 j 也是存在代码块中, 这里会报错
      console.log(j);
</script>

<script type="text/javascript">
      //用var 声明的时候 有变量提升的特性
      console.log(c);
      var c = 'c';

      //使用let 不会有变量提升
      console.log(d);
      let d = 'd';
</script>

<script type="text/javascript">
    var e = "e";
    if (true) {
      e = "ee";
      //在代码块中,只要存在let命令,它声明的所有变量都会绑定在它身上。
      let e = "小王";
      console.log(e);
    }
</script>

总之在代码块内,使用变量之前,一定要用let声明好。
如果let在使用变量之后声明的话,我们称为:"暂时性死区" (temporary dead zone,简称:TDZ)。

<script type="text/javascript">
    if (true) {
      //TDZ 开始
      d = "d";
      console.log(d)
      //TDZ 结束
      let d = "dd";
      console.log(d);
    }
</script>

let不允许在同一作用域中声明重复的变量

<script type="text/javascript">
    (function () {
      let a = "a";
      //let a = "b";
    })();

    (function () {
      let a = "a";
      //var a = "b";
    })();
                
    (function (arg) {
      //let arg = "a";
    })();
                
    (function (arg) {
      {
        //自己在独立的一个块级里,就不会和形参的arg有冲突了。
        let arg = "a";
      }
    })();
</script>

关于全局变量,在var声明的情况下,全局变量就等同于全局对象的属性,用ES6的let声明全局变量则不会。

<script type="text/javascript">
    var str = 33;
    console.log(window.str); //33

    let str2 = "bcd";
    console.log(window.str2); //undefined
    console.log(str2); //bcd
</script>

 利用let解决一个比较经典的问题

<input type="button" value="按钮1" id="button1" />
<input type="button" value="按钮2" id="button2" />
<input type="button" value="按钮3" id="button3" />
<script type="text/javascript">
    for (var z = 1; z < 4; z++) {
      var button = document.getElementById('button' + z);
        button.addEventListener('click', function () {
          alert('button' + (z));  //每次打印结果 都是 button4
        });
    }

    //利用函数立即执行、形成闭包。每次保存z的值 这样就可以实现我们想要的结果
    for (var z = 1; z < 4; z++) {
      var button = document.getElementById('button' + z);
      //每次循环把i存储起来
      (function (z) {
        button.addEventListener('click', function () {
          alert('button' + (z));
        });
      })(z);
    }
    
    //更简单的解决办法,形成块级作用域,使用let
    for (let z = 1; z < 4; z++) {
      var button = document.getElementById('button' + z);
        button.addEventListener('click', function () {
          alert('button' + (z));  //每次打印结果 都是 button4
        });
    }
</script>

1.3 const声明

在 ES6 使用const来声明的变量称之为常量。这意味着它们不能再次被赋值。由于这个原因,所有的 const 声明的变量都必须在声明处初始化。

const声明的常量和let变量一样也是具有块级作用域的特性,一样不支持变量(常量)提升,一样存在"TDZ"。
const命令用来声明常量,常量一旦声明,就无法改变。
const命令用来声明常量,一定要初始化。

<script type="text/javascript">
    const PI = "3.1415..";
    console.log(PI);
    PI = "能修改吗?"; // 报错,常量不能修改
    console.log(PI); 
</script>

注意:针对于引用类型,修改值就是修改变量指针的指向。指向不同的对象实例

<script type="text/javascript">
    const OBJ = {};
    //OBJ = { age : 18 };  不可以,这样相当于修改了对象的指针指向
    OBJ.name = "小雪";  //可以,这个没有修改对象的指针指向,而是修改内部的属性值
    console.log(OBJ);
                
    //我们可以使用Object.freeze()冻结这个对象,从而达到不能操作对象的属性
    Object.freeze(OBJ);
    OBJ.age = 18;
    OBJ.name = "小虹";
    console.log(OBJ);
</script>

二、变量的解构

ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)

以前,为变量赋值,只能直接指定值。

let a = 1;
let b = 2;
let c = 3;

ES6 允许写成下面这样。

let [a, b, c] = [1, 2, 3];

上面代码表示,可以从数组中提取值,按照对应位置,对变量赋值。

2.1 数组的解构

只要等号两边的模式相同,左边的变量就会被赋予对应的值。下面是一些使用嵌套数组进行解构的例子。

let [foo, [[bar], baz]] = [1, [[2], 3]];
console.log(foo) // 1
console.log(bar) // 2
console.log(baz) // 3

let [ , , third] = ["foo", "bar", "baz"];
console.log(third) // "baz"

let [x, , y] = [1, 2, 3];
console.log(x) // 1
console.log(y) // 3

let [head, ...tail] = [1, 2, 3, 4];
console.log(head) // 1
console.log(tail) // [2, 3, 4]

let [x, y, ...z] = ['a'];
console.log(x) // "a"
console.log(y) // undefined
console.log(z) // []

如果解构不成功,变量的值就等于undefined。

let [foo] = [];
let [bar, foo] = [1];

以上两种情况都属于解构不成功,foo的值都会等于undefined。

另一种情况是不完全解构,即等号左边的模式,只匹配一部分的等号右边的数组。这种情况下,解构依然可以成功。

let [x, y] = [1, 2, 3];
console.log(x) // 1
conole.log(y) // 2

let [a, [b], d] = [1, [2, 3], 4];
console.log(a) // 1
console.log(b) // 2
console.log(d) // 4

上面两个例子,都属于不完全解构,但是可以成功。

如果等号的右边不是可遍历的结构,那么将会报错。

// 报错
let [foo] = 1;
let [foo] = false;
let [foo] = NaN;
let [foo] = undefined;
let [foo] = null;
let [foo] = {};

上面的语句都会报错,因为等号右边的值,要么转为对象以后不具备 Iterator 接口(前五个表达式),要么本身就不具备 Iterator 接口(最后一个表达式)。

2.2 对象的解构

解构不仅可以用于数组,还可以用于对象。

let { foo, bar } = { foo: "aaa", bar: "bbb" };
console.log(foo) // "aaa"
console.log(bar) // "bbb"

对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。

let { bar, foo } = { foo: "aaa", bar: "bbb" };
console.log(foo) // "aaa"
console.log(bar) // "bbb"

let { baz } = { foo: "aaa", bar: "bbb" };
baz // undefined

上面代码的第一个例子,等号左边的两个变量的次序,与等号右边两个同名属性的次序不一致,但是对取值完全没有影响。第二个例子的变量没有对应的同名属性,导致取不到值,最后等于undefined。

如果变量名与属性名不一致,必须写成下面这样。

let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
console.log(baz) // "aaa"

let obj = { first: 'hello', last: 'world' };
let { first: f, last: l } = obj;
console.log(f) // 'hello'
console.log(l) // 'world'

这实际上说明,对象的解构赋值是下面形式的简写)。

let { foo: foo, bar: bar } = { foo: "aaa", bar: "bbb" };

也就是说,对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者。

let { foo: baz } = { foo: "aaa", bar: "bbb" };
console.log(baz) // "aaa"
console.log(foo) // error: foo is not defined

上面代码中,foo是匹配的模式,baz才是变量。真正被赋值的是变量baz,而不是模式foo。

如果要将一个已经声明的变量用于解构赋值,必须非常小心。

// 错误的写法
let x;
{x} = {x: 1};
// SyntaxError: syntax error

上面代码的写法会报错,因为 JavaScript 引擎会将{x}理解成一个代码块,从而发生语法错误。只有不将大括号写在行首,避免 JavaScript 将其解释为代码块,才能解决这个问题。

// 正确的写法
let x;
({x} = {x: 1});

2.3 字符串的解构

字符串也可以解构赋值。这是因为此时,字符串被转换成了一个类似数组的对象。

const [a, b, c, d, e] = 'hello';
console.log(a) // "h"
cnosole.log(b) // "e"
console.log(c) // "l"
console.log(d) // "l"
console.log(e) // "o"

类似数组的对象都有一个length属性,因此还可以对这个属性解构赋值。

let {length : len} = 'hello';
console.log(len) // 5

三、模板字符串

模板字符串(template string)是增强版的字符串,用反引号(`)标识。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。

// 普通字符串
`In JavaScript '\n' is a line-feed.`

// 多行字符串
`In JavaScript this is
 not legal.`

console.log(`string text line 1
string text line 2`);

// 字符串中嵌入变量
let name = "Bob", time = "today";
`Hello ${name}, how are you ${time}?`
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,014评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,796评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,484评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,830评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,946评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,114评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,182评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,927评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,369评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,678评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,832评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,533评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,166评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,885评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,128评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,659评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,738评论 2 351

推荐阅读更多精彩内容

  • [TOC] 参考阮一峰的ECMAScript 6 入门参考深入浅出ES6 let和const let和const都...
    郭子web阅读 1,773评论 0 1
  • 第2章 基本语法 2.1 概述 基本句法和变量 语句 JavaScript程序的执行单位为行(line),也就是一...
    悟名先生阅读 4,135评论 0 13
  • 前面的话 我们经常定义许多对象和数组,然后有组织地从中提取相关的信息片段。在ES6中添加了可以简化这种任务的新特性...
    sunnyghx阅读 754评论 0 0
  • 1.数组的解构赋值 2.对象的解构赋值 3.字符串的解构赋值 4.数值和布尔值的解构赋值 5.函数参数的解构赋值 ...
    卞卞村长L阅读 917评论 0 0
  • 今晚,做一个幸福的吃货,研究研究来自天南海北,五湖四海,独具特色,色香味俱佳,吸引人流口水,让人感觉小幸福的好吃的...
    雅轩1号阅读 485评论 0 1