【ES6学习】— (1)ES6简介、let与const命令以及变量的解构赋值

来源:互联网 发布:整型数组 编辑:程序博客网 时间:2024/04/28 09:12

最近团队要求使用React Native开发移动应用, 会使用到JS的相关知识, 趁此机会学习一下ES6, 也算是拓宽自己的知识栈了。学习参考的是阮一峰老师的《ES6标准入门(第二版)》一书, 同时也参考了《JavaScript 标准参考教程》回顾JS在ES6之前的内容。 之前虽然对JS已经有所了解,但终归不是很熟悉,希望通过这次学习可以对JS有一个比较全面和深入的了解,书籍看过了但是还是不够深刻,因此这里将学习的内容整理做下笔记,加深理解与记忆的同时也便于以后查阅。

一、ES6简介

ES6(ECMAScript)是JavaScript语言的下一代标准, 已于2015年6月发布, 其目标是使JavaScript语言可用于编写复杂的大型应用程序。有人疑惑ECMAScript和JavaScript的关系, 简单来说就是前者是后者的规格,后者是前者的一种实现。一般来说两者其实等价

1.ECMAScript发展历史

  • 1997年ECMA1.0发布, 1998年发布2.0, 1999年12月发布3.0
  • 2000年开始制定4.0并于2007年发布草案,但因太过激进遭到反对,因此将一部分修改延后
  • 2009年12月发布5.0
  • 2015年6月ECMAScript6.0正式通过

2.部署进度查询

通过访问这里可以查看各大浏览器的最新版本对ES6的支持。
阮一峰老师也写了一个ec-checker模块检查各个运行环境对ES6的支持。
通过运行下面命令可以查看本机对ES6的支持程度。

$ npm install -g es-checker$ es-checker

3.Babel与Traceur转码器

Babel是一个ES6转码器,可以将ES6代码转化为ES5代码,从而在浏览器或其他环境中执行。这意味着我们可以用ES6的方式编写程序, 而又不需要担心现有的环境是否支持,具体的使用方式参阅官网介绍,这里不再赘述。
代码示例:

//转码前input.map(item => item+1);//转码后input.map(function(item){    return item + 1;});

Traceur是谷歌公司提供的转码器,有兴趣的同学可以查阅其官网学习。

二、 let与const命令

1.let命令

ES6新增了let命令用来声明变量, 用法与var类似,但是用let声明的变量只在其let所在的代码块内有效。在ES5中, 我们一般都是用var声明变量,在函数之外声明的变量会被视为全局变量,同时存在变量提升现象,其方法和变量的声明都会被默认提升到所在作用域的顶部,因此即使在我们声明之前我们依然可以使用变量和方法,但是let命令与其不同,下面是let命令的几个特点:

  • 不存在变量提升, 因此变量必须在声明之后才能使用,否则会报错
  • 暂时性死区,因为在变量声明之前该变量是无法使用,在声明之前的代码区域对于该变量而言相当于死区, 这在语法上成为暂时性死区
  • let不允许在相同作用域内重复声明同一个变量

ps: 感觉let命令与var命令相比更接近于Java等面向对象语言的声明变量的方式

2.块级作用域

在ES5中只有全局作用域和变量作用域,由此引发了两个问题:

  • 内层变量覆盖外层变量
  • 用来计数的循环变量会泄露为全局变量

在ES6中因为let命令的加入,实际是使ES6多了一个块级作用域。因为let声明的变量是在let所在的代码块内有效,因此我们可以很明确的知道:

  • 外层作用域无法读取内层作用域的变量
  • 块级作用域外部无法调用块级作用域内部定义的函数, ES6规定函数本身的作用域在其所在的块级作用域内

注意一点: 在严格模式下,函数只能在顶层作用域和函数内声明, 其他情况下(比如在if/循环代码块)中声明都会报错

3.const命令

const用来声明常量, 一旦声明,其值不能改变。const命令具有以下特点:

  • const一旦声明常量,必须立即初始化,不能留到以后赋值
  • const的作用域与let相同, 只在声明所在的块级作用域有效,
  • const和let一样,不可以重复声明常量
  • 对于复合类型变量, 变量名不指向数据, 而是指向数据所在的地址。const命令只保证该地址不会变, 但是该地址的数据可以改变,这一点和Java一样,地址不变,但地址中的对象可以改变。

总体而言感觉let和const命令的加入使得JS声明变量和常量的方式更加像面向对象语言的局部变量了。

如果真的需要将对象冻结, 需要使用Object.freeze方法。下面是一个将对象彻底冻结的函数:

var constanize = (obj) => {    Object.freeze(obj);    Object.keys(obj).forEach((key, value) => {        if(typeof obj[key] === 'object'){            constantize(obj[key]);        }    });};

4.跨模块常量以及全局对象的属性

const声明的常量只能在当前代码块有效,如果想要设置跨模块的常量需要用到export和import命令.代码示例如下:

//constants.js模块export const A = 1;export const B = 2;//test.js模块import * as constants form './constants';console.log(constants.A);//1

全局对象是最顶层的对象, 在浏览器环境指window对象,在Node.js中指的是global对象。在ES5中全局对象的属性和全局变量是等价的。因为我们很容易不知不觉中创建全局变量,这被视为一个很大的问题。ES6中做了修正:

  • var命令和function命令声明的全局变量依旧是全局对象的属性
  • let、const、class命令声明的全局变量不属于全局对象的属性

备注: ES6中一共有6种声明变量的方法,除了传统的var和function命令, ES6新添加了let、const、import、class命令。

三、变量的解构赋值

概念: ES6允许按照一定的模式, 从数组对象中提取值,对变量进行赋值, 这被称为解构。
代码示例:

//以前的变量赋值var a = 1;var b = 2;var c= 3;//ES6解构赋值var [a,b,c] = [1,2,3];

本质上这种写法属于”模式匹配”, 只要等号两边的模式相同,左边的变量就会被赋予对应的值。

解构赋值的条件: 等号右边必须是可遍历的解构。只要某种数据结构具有Iterator接口, 都可以采用数组形式的解构赋值。

解构赋值允许指定默认值, ES6内部使用严格相等===来判断一个位置是否有值,只有右边的值严格等于undefined,默认值才会生效;同时默认值也可以引用解构赋值的其他变量, 但是该变量必须已经声明。

1.对象的解构赋值

除了数组之外解构还可用于对象,但与数组不同,数组的元素是按次序排列的, 变量的取值由它的位置决定; 而对象的属性没有次序,变量必须与属性同名才能取到正确的值,代码示例:

var {bar, foo} = {foo:"aaa", bar:"bbb"};foo//"aaa"bar//"bbb"//实际上上面对象的解构赋值是以下形式的简写var {foo:foo, bar:bar} = {foo:foo, bar:bar}

对象的解构赋值的内部机制, 是先找到同名属性, 然后在赋值给对应的变量。真正被赋值的是后者, 而不是前者。代码示例:

var {foo:baz} = {foo:"aaa", bar:"bbb"};//首先找到与属性同名的foo,然后为其对应的变量baz赋值,真正被赋值的是变量baz.baz //"aaa"foo //error:foo is not defined

对象解构赋值的注意事项:
* 对象解构也可以指定默认值,其生效的条件是对象的属性值严格等于undefined;
* 解构赋值的变量都会重新声明, 因此不能使用let或者const命令提前声明变量, var命令可以;

  • 解构也可以用于嵌套结构的对象,如果是嵌套的对象,而且子对象所在的父属性不存在,那么将会报错。代码示例:
var obj = {    p:[       "hello",       {y:"world"}       ]}var {p:[x,{y}]} = obj;x//"hello"y//"world"//报错var {foo:{bar}} = {baz:"baz"}

2.字符串的解构赋值

字符串可以被转换为一个类似数组的对象, 因此也可以解构赋值, 代码示例:

const{a,b,c,d,e} = 'hello';a//"h"b//"e"c//"l"d//"l"e//"o"//另外转成的对象还有length属性:let{length:len} = 'hello';len//5

3.数值和布尔值的解构赋值

如果等号右边是数值或者布尔值,则会先转换为对象,其包装对象都有toString属性,因此我们可以获取到其属性值,代码示例:

let{toString:s} = 123;s === Number.prototype.toString //true

解构赋值的规则是:只要等号右边的值不是对象,就将其先转化为对象。由于undefined和null无法转换为对象所以对他们进行结构赋值会报错

4.函数参数的结构赋值

函数参数也可以结构赋值,代码示例:

//参数并不是数组,而是通过结构得到x和y变量function add([x, y]){    return x+y;}add([1,2])//3//也可以使用默认值,undefined会触发函数擦书的默认值function move({x=0, y=0}={}){    return [x,y];}

5.圆括号的使用问题

下面三种解构赋值不能使用圆括号:
* 变量声明语句中不得使用圆括号;
* 函数参数中,模式不能带有圆括号;
* 不能将整个模式或嵌套模式中的一层放在圆括号中;

可以使用圆括号的情况只有一种:赋值语句的非模式部分可以使用圆括号

6.解构赋值的用途

交换变量的值

[x,y] = [y,x];

定义函数参数

function f([x,y,z]){...}//f([1,2,3])functionf({x,y,z}){...}//f({z:3,y:2,x:1})

从函数返回多个值

//返回一个数组function example(){    return [1,2,3];}var [a,b,c] = example();//返回一个对象function test(){    return {        foo:1,        bar:2    };}var {foo, bar} = test();

提取JSON数据

var jsonData = {    id:42,    status:"OK",    data:[867, 5309]}let {id, status, data:number} = jsonData;//id = 42, status = OK, number = [867, 5309];

指定函数参数的默认值

function move({x=0,y=0}){...}

遍历Map结构

任何部署了Iterator接口的对象都可以用for…of循环遍历,Map原生支持Iterator结构配合解构赋值,获取key和value非常方便

//获取键keyfor(let [key] of map){}//获取值valuefor(let[,value] of map){}//获取键值for(let [ley,value] of map){}

输入模块的指定方法
加载模块时,往往需要指定输入哪些方法, 解构赋值使得输入语句非常清晰

const {SourceMapConsumer, SourceNode} = require("source-map");

上面就是关于ES6let和const命令的相关简记,继续学习ES6+的其他知识点。

0 0