关于es6:ECMAScript-6新特性简介

6次阅读

共计 4294 个字符,预计需要花费 11 分钟才能阅读完成。

简介

ECMAScript 6.0(以下简称 ES6)是 JavaScript 语言的下一代规范,正式公布与 2015 年 6 月。它的指标,是使得 JavaScript 语言能够用来编写简单的大型应用程序,成为企业级开发语言。

明天咱们将会解说一下 ES6 中引入的语法新个性。

ECMAScript 和 JavaScript 的关系

1996 年 11 月,JavaScript 的创造者 Netscape 公司,决定将 JavaScript 提交给国际标准化组织 ECMA.

1997 年, ECMA 公布 262 号标准文件 ECMAScript 1.0。

ECMAScript 和 JavaScript 的关系是,前者是后者的规格,后者是前者的一种实现。

咱们看一下 ECMAScript 的发行历史:

从 2015 年 ES2015,也就是 ES6 公布以来,ECMAScript 以每年一个版本的发行速度发行到了 ES2020。

前面的文章咱们会解说一下这些新版本的 ECMAScript 的新个性。

let 和 const

ES6 中引入了 let 和 const, 是为了解决之前的 var 变量的种种问题。

在 ES6 之前,JS 中变量的作用域有两种:全局作用域和函数作用域。

全局作用域很好了解,咱们在浏览器控制台或者 Node.js 交互终端中开始编写 JavaScript 时,即进入了所谓的全局作用域。

全局作用域的变量能够在任何其余作用域中拜访。

函数作用域就是定义在函数外部的变量,在函数外部都能够拜访到该变量。

这两种作用域会有一些问题:

  1. 变量晋升

var 命令会产生”变量晋升”景象,即变量能够在申明之前应用,值为 undefined.

// var 的状况 
console.log(foo);  // 输入 undefined 
var foo = 2; 
  1. 变量笼罩

当咱们在函数作用域应用全局变量的时候,如果函数作用域中定义了同样名字的变量,不论是在哪里定义的,都会笼罩掉全局的变量。如下所示:

var tmp = new Date(); 
function f() {console.log(tmp); 
if (false) {var tmp = "hello world";} } 
f(); // undefined
  1. 变量泄露

变量泄露的意思是,咱们原本只心愿在小范畴作用域应用的变量,后果泄露到了范畴里面,如下所示:

var s = 'hello'; 
for (var i = 0; i < s.length; i++) {console.log(s[i]); 
} 
console.log(i); // 5
~~

为了解决下面两个问题,ES6 引入了 let 和 const。这两个都是块级作用域。不同的是 const 定义的变量初始化之后就不能变动了。什么是块级作用域呢?相似于 if、switch 条件抉择或者 for、while 这样的循环体即是所谓的块级作用域, 或者更简略一点应用大括号括起来的就叫做块级作用域。块级作用域的最大益处就是不会产生作用域晋升,如下所示:

{
let a = 10;
var b = 1;
}
a // ReferenceError: a is not defined.
b // 1


# 解构赋值

什么是解构赋值呢?ES6 容许依照肯定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构。如下所示:

let [a, b, c] = [1, 2, 3];
let [, , third] = [“foo”, “bar”, “baz”];
let [x, , y] = [1, 2, 3];
let [head, …tail] = [1, 2, 3, 4];

let [x, y] = [1, 2, 3];


解构赋值还能够设定默认值,咱们来看上面的几个例子:

let [foo = true] = [];
foo // true

let [x, y = ‘b’] = [‘a’];
// x=’a’, y=’b’

let [x, y = ‘b’] = [‘a’, undefined];
// x=’a’, y=’b’

let [x = 1] = [undefined];
x // 1
let [x = 1] = [null];
x // null


如果解构的默认值是一个函数,那么能够触发惰性赋值:

function f() {
console.log(‘aaa’);
}

let [x = f()] = [1];


下面的例子中,f 函数将不会被执行。除了构造变量之外,还能够构造对象:

let {bar, foo} = {foo: “aaa”, bar: “bbb”};
foo // “aaa”
bar // “bbb”

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

var {foo: baz} = {foo: ‘aaa’, bar: ‘bbb’};
baz // “aaa”

let obj = {first: ‘hello’, last: ‘world’};
let {first: f, last: l} = obj;
f // ‘hello’
l // ‘world’


解构还反对嵌套的构造:

let obj = {p: [ ‘Hello’, { y: ‘World’} ] };

let {p: [x, { y}] } = obj;

x // “Hello”
y // “World”


解构赋值有两个十分重要的作用。第一就是替换变量:

let x = 1;
let y = 2;
[x, y] = [y, x];


咱们就能够不再应用两头变量,间接进行两个变量值的交互。第二个作用就是从函数中返回多个值:

// 返回一个数组
function example() { return [1, 2, 3]; }
let [a, b, c] = example();

// 返回一个对象
function example() { return { foo: 1, bar: 2}; }
let {foo, bar} = example();

// 提取 JSON 数据
let jsonData = {id: 42, status: “OK”, data: [867, 5309] };
let {id, status, data: number} = jsonData;


# 数组的扩大

ES6 中的 Array.from 办法用于将上面两类对象转为真正的数组:* 相似数组的对象(array-like object)* 可遍历(iterable)的对象(包含 ES6 新增的数据结构 Set 和 Map)。什么是相似数组对象呢?所谓相似数组的对象,本质特征只有一点,即必须有 length 属性。因而,任何有 length 属性的对象,都能够通过 Array.from 办法转为数组。上面的变量就是类数组变量:

let arrayLike = {‘0’: ‘a’, ‘1’: ‘b’, ‘2’: ‘c’, length: 3};


这个类数组对象怎么转换成为数组呢?

// ES5 的写法
var arr1 = [].slice.call(arrayLike);
// [‘a’, ‘b’, ‘c’]

// ES6 的写法 let arr2 = Array.from(arrayLike);
// [‘a’, ‘b’, ‘c’]


咱们看下通常的应用场景:

// NodeList 对象
let ps = document.querySelectorAll(‘p’);
Array.from(ps).forEach(function (p) {console.log(p); });

// arguments 对象
function foo() { var args = Array.from(arguments);
// …
}


什么是可遍历对象呢?只有是部署了 Iterator 接口的数据结构,都叫做可遍历对象。咱们看下上面的例子:

Array.from(‘hello’) // [‘h’, ‘e’, ‘l’, ‘l’, ‘o’]
let namesSet = new Set([‘a’, ‘b’])
Array.from(namesSet) // [‘a’, ‘b’]


同时还引入了扩大运算符(...),通过扩大运算符,也能够很不便的转换为数组对象:

function foo() { var args = […arguments]; } // arguments 对象
[…document.querySelectorAll(‘div’)] // NodeList 对象


Array.from 办法还能够接管第二个参数,用来对数组中的元素进行操作:

Array.from(arrayLike, x => x * x);
// 等同于
Array.from(arrayLike).map(x => x * x);

Array.from([1, 2, 3], (x) => x * x)
// [1, 4, 9]


Array.of 办法能够很不便的创立新的数组:

Array.of(3, 11, 8) // [3,11,8]
Array.of(3) // [3]
Array.of(3).length // 1

Array() // []
Array(3) // [, , ,]
Array(3, 11, 8) // [3, 11, 8]


# 函数的扩大

ES6,能够反对函数的默认值了:

function log(x, y = ‘World’) {console.log(x, y); }
function Point(x = 0, y = 0) {this.x = x; this.y = y;}


函数的默认值能够和解构赋值默认值组合起来应用:

function foo({x, y = 5}) {console.log(x, y); }
foo({}) // undefined, 5
foo({x: 1}) // 1, 5
foo({x: 1, y: 2}) // 1, 2
foo() // TypeError: Cannot read property ‘x’ of undefined


接下来,咱们看一个简单的例子:

// 写法一
function m1({x = 0, y = 0} = {})
{return [x, y]; }

// 写法二
function m2({x, y} = {x: 0, y: 0})
{return [x, y]; }


咱们来看一下,下面的两种写法有什么不同呢?当函数没有参数的状况:

m1() // [0, 0]
m2() // [0, 0]


当 x 和 y 都有值的状况:

m1({x: 3, y: 8}) // [3, 8]
m2({x: 3, y: 8}) // [3, 8]


当 x 有值,y 无值的状况:

m1({x: 3}) // [3, 0]
m2({x: 3}) // [3, undefined]


当 x 和 y 都无值的状况:

m1({}) // [0, 0];
m2({}) // [undefined, undefined]
m1({z: 3}) // [0, 0]
m2({z: 3}) // [undefined, undefined]


看出区别了吗?m1 的解构赋值,对于 x,y 来说是有默认值 0 的。而 m2 的解构赋值对于 x,y 来说是没有默认值的。> 本文作者:flydean 程序那些事
> 
> 本文链接:[http://www.flydean.com/ecmascript-6-startup/](http://www.flydean.com/ecmascript-6-startup/)
> 
> 本文起源:flydean 的博客
> 
> 欢送关注我的公众号:「程序那些事」最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!
正文完
 0