ES6 入门
1、简介
ECMAScript 6.0 是 JavaScript 语言的下一代标准,已经在 2015 年 6 月正式发布了。它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。
ECMAScript 和 JavaScript 的关系是,前者是后者的规格,后者是前者的一种实现(另外的 ECMAScript 方言还有 JScript 和 ActionScript)。日常场合,这两个词是可以互换的。
2、let 和 const 命令
在ES6以前,var关键字声明变量。无论声明在何处,都会被视为声明在函数的最顶部(不在函数内即在全局作用域的最顶部)。
ES6新增了 let 和 const 命令,用来声明变量。let 表示变量、const表示常量,它们都是块级作用域。说白了,就是大括号 {} 内的代码块即为 let 和 const 的作用域。
ES6 明确规定,如果区块中存在let
和const
命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。总之,在代码块内,使用let
命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。
if (true) {
// TDZ开始
tmp = 'abc'; // ReferenceError
console.log(tmp); // ReferenceError let tmp; // TDZ结束
console.log(tmp); // undefined tmp = 123;
console.log(tmp); //
}
上面代码中,在let
命令声明变量tmp
之前,都属于变量tmp
的“死区”。
“暂时性死区”也意味着typeof
不再是一个百分之百安全的操作,如下:
typeof x; // ReferenceError
let x;
上面代码中,变量x
使用let
命令声明,所以在声明之前,都属于x
的“死区”,只要用到该变量就会报错。因此,typeof
运行时就会抛出一个ReferenceError。
不允许重复声明
let
不允许在相同作用域内,重复声明同一个变量。如下:
// 报错
function func() {
let a = 10;
var a = 1;
} // 报错
function func() {
let a = 10;
let a = 1;
}
因此,不能在函数内部重新声明参数。
function func(arg) {
let arg;
}
func() // 报错 function func(arg) {
{
let arg;
}
}
func() // 不报错
3、变量的解构赋值
ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。
- 数组的结构赋值
以前,为变量赋值,只能直接指定值:
let a = 1;
let b = 2;
let c = 3;
ES6 写法:
let [a, b, c] = [1, 2, 3];
这种写法属于“模式匹配”,等号两边的模式相同。也有嵌套数组进行结构的例子,如下:
let [foo, [[bar], baz]] = [1, [[2], 3]];
foo //
bar //
baz // let [ , , third] = ["foo", "bar", "baz"];
third // "baz" let [x, , y] = [1, 2, 3];
x //
y // let [head, ...tail] = [1, 2, 3, 4];
head //
tail // [2, 3, 4] let [x, y, ...z] = ['a'];
x // "a"
y // undefined
z // []
如果结构不成功,变量的值则为 undefined.
let [foo] = [];
let [bar, foo] = [1];
以上两种情况都属于解构不成功,foo
的值都会等于undefined
。
另一种情况是不完全解构,即等号左边的模式,只匹配一部分的等号右边的数组。这种情况下,解构依然可以成功。
let [x, y] = [1, 2, 3];
x //
y // let [a, [b], d] = [1, [2, 3], 4];
a //
b //
d //
- 对象的解构赋值
结构不仅可以用于数组,还可以用于对象。
let { foo, bar } = { foo: 'aaa', bar: 'bbb' };
foo // "aaa"
bar // "bbb"
对象与数组的解构有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性的同名,才能取到正确的值。
let { bar, foo } = { foo: 'aaa', bar: 'bbb' };
foo // "aaa"
bar // "bbb" let { baz } = { foo: 'aaa', bar: 'bbb' };
baz // undefined
对象的解构赋值,可以很方便的将现有对象的方法赋值到某个变量。
// 例一
let { log, sin, cos } = Math; // 例二
const { log } = console;
log('hello') // hello
上面代码的例一将Math
对象的对数、正弦、余弦三个方法,赋值到对应的变量上,使用起来就会方便很多。例二将console.log
赋值到log
变量。
如果变量名与属性名不一致,必须写成下面这样:
let { 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 { foo: baz } = { foo: 'aaa', bar: 'bbb' };
baz // "aaa"
foo // error: foo is not defined
上面代码中,foo
是匹配的模式,baz
才是变量。真正被赋值的是变量baz
,而不是模式foo
。
与数组一样,解构也可以用于嵌套结构的对象。
let obj = {
p: [
'Hello',
{ y: 'World' }
]
}; let { p: [x, { y }] } = obj;
x // "Hello"
y // "World"
注意,这时p
是模式,不是变量,因此不会被赋值。如果p
也要作为变量赋值,可以写成下面这样。
let obj = {
p: [
'Hello',
{ y: 'World' }
]
}; let { p, p: [x, { y }] } = obj;
x // "Hello"
y // "World"
p // ["Hello", {y: "World"}]
- 字符串的解构赋值
字符串也可以解构赋值。这是因为此时,字符串被转换成了一个类似数组的对象。
const [a, b, c, d, e] = 'hello';
a // "h"
b // "e"
c // "l"
d // "l"
e // "o"
类似数组的对象都有一个length
属性,因此还可以对这个属性解构赋值。
let {length : len} = 'hello';
len //
- 数值与布尔值的解构赋值
解构赋值时,如果等号右边是数值和布尔值,则会先转为对象。
let {toString: s} = 123;
s === Number.prototype.toString // true let {toString: s} = true;
s === Boolean.prototype.toString // true
上面代码中,数值和布尔值的包装对象都有toString
属性,因此变量s
都能取到值。
解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象。由于undefined
和null
无法转为对象,所以对它们进行解构赋值,都会报错。
let { prop: x } = undefined; // TypeError
let { prop: y } = null; // TypeError
- 函数参数的解构赋值
function add([x, y]){
return x + y;
} add([1, 2]); //
[[1, 2], [3, 4]].map(([a, b]) => a + b);
// [ 3, 7 ]
function move({x = 0, y = 0} = {}) {
return [x, y];
} move({x: 3, y: 8}); // [3, 8]
move({x: 3}); // [3, 0]
move({}); // [0, 0]
move(); // [0, 0]
变量解构赋值的用途:
- 交换变量的值
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();
- 函数参数的定义
// 参数是一组有次序的值
function f([x, y, z]) { ... }
f([1, 2, 3]); // 参数是一组无次序的值
function f({x, y, z}) { ... }
f({z: 3, y: 2, x: 1});
- 提取JSON数据
let jsonData = {
id: 42,
status: "OK",
data: [867, 5309]
}; let { id, status, data: number } = jsonData; console.log(id, status, number);
// 42, "OK", [867, 5309]
- 函数参数的默认值
jQuery.ajax = function (url, {
async = true,
beforeSend = function () {},
cache = true,
complete = function () {},
crossDomain = false,
global = true,
// ... more config
} = {}) {
// ... do stuff
};
- 遍历Map解构
任何部署了 Iterator 接口的对象,都可以用for...of
循环遍历。Map 结构原生支持 Iterator 接口,配合变量的解构赋值,获取键名和键值就非常方便。
const map = new Map();
map.set('first', 'hello');
map.set('second', 'world'); for (let [key, value] of map) {
console.log(key + " is " + value);
}
// first is hello
// second is world
如果只想获取键名,或者只想获取键值,可以写成下面这样。
// 获取键名
for (let [key] of map) {
// ...
} // 获取键值
for (let [,value] of map) {
// ...
}
- 输入模块的指定方法
加载模块时,往往需要指定输入哪些方法。解构赋值使得输入语句非常清晰。
const { SourceMapConsumer, SourceNode } = require("source-map");
4、字符串扩展
- includes(), startsWith(), endsWith()
传统上,JavaScript 只有indexOf
方法,可以用来确定一个字符串是否包含在另一个字符串中。ES6 又提供了三种新方法。
- includes():返回布尔值,表示是否找到了参数字符串。
- startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。
- endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部。
let s = 'Hello world!'; s.startsWith('Hello') // true
s.endsWith('!') // true
s.includes('o') // true
这三个方法都支持第二个参数,表示开始搜索的位置。
let s = 'Hello world!'; s.startsWith('world', 6) // true
s.endsWith('Hello', 5) // true
s.includes('Hello', 6) // false
- repeat()
repeat
方法返回一个新字符串,表示将原字符串重复n
次.
'x'.repeat(3) // "xxx"
'hello'.repeat(2) // "hellohello"
'na'.repeat(0) // ""
如果repeat
的参数是字符串,则会先转换成数字。
'na'.repeat(2.9) // "nana"
'na'.repeat(Infinity)
// RangeError
'na'.repeat(-1)
// RangeError
'na'.repeat(-0.9) // ""
'na'.repeat('na') // ""
'na'.repeat('3') // "nanana"
- padStart() padEnd()
ES2017 引入了字符串补全长度的功能。如果某个字符串不够指定长度,会在头部或尾部补全。padStart()
用于头部补全,padEnd()
用于尾部补全。
'x'.padStart(5, 'ab') // 'ababx'
'x'.padStart(4, 'ab') // 'abax' 'x'.padEnd(5, 'ab') // 'xabab'
'x'.padEnd(4, 'ab') // 'xaba'
padStart()
的常见用途是为数值补全指定位数。下面代码生成 10 位的数值字符串。
'1'.padStart(10, '0') // "0000000001"
'12'.padStart(10, '0') // "0000000012"
'123456'.padStart(10, '0') // "0000123456"
另一个用途是提示字符串格式。
'12'.padStart(10, 'YYYY-MM-DD') // "YYYY-MM-12"
'09-12'.padStart(10, 'YYYY-MM-DD') // "YYYY-09-12"
- 模板字符串(template string)
传统的 JavaScript 语言,输出模板通常是这样写的(下面使用了 jQuery 的方法)。
$('#result').append(
'There are <b>' + basket.count + '</b> ' +
'items in your basket, ' +
'<em>' + basket.onSale +
'</em> are on sale!'
);
上面这种写法相当繁琐不方便,ES6 引入了模板字符串解决这个问题。
$('#result').append(`
There are <b>${basket.count}</b> items
in your basket, <em>${basket.onSale}</em>
are on sale!
`);
模板字符串(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}?`
上面代码中的模板字符串,都是用反引号表示。如果在模板字符串中需要使用反引号,则前面要用反斜杠转义。
let greeting = `\`Yo\` World!`;
如果使用模板字符串表示多行字符串,所有的空格和缩进都会被保留在输出之中。
$('#list').html(`
<ul>
<li>first</li>
<li>second</li>
</ul>
`);
上面代码中,所有模板字符串的空格和换行,都是被保留的,比如<ul>
标签前面会有一个换行。如果你不想要这个换行,可以使用trim
方法消除它。
$('#list').html(`
<ul>
<li>first</li>
<li>second</li>
</ul>
`.trim());
模板字符串中嵌入变量,需要将变量名写在${}
之中。
function authorize(user, action) {
if (!user.hasPrivilege(action)) {
throw new Error(
// 传统写法为
// 'User '
// + user.name
// + ' is not authorized to do '
// + action
// + '.'
`User ${user.name} is not authorized to do ${action}.`);
}
}
大括号内部可以放入任意的 JavaScript 表达式,可以进行运算,以及引用对象属性。
let x = 1;
let y = 2; `${x} + ${y} = ${x + y}`
// "1 + 2 = 3" `${x} + ${y * 2} = ${x + y * 2}`
// "1 + 4 = 5" let obj = {x: 1, y: 2};
`${obj.x + obj.y}`
// "3"
模板字符串之中还能调用函数。
function fn() {
return "Hello World";
} `foo ${fn()} bar`
// foo Hello World bar
如果大括号中的值不是字符串,将按照一般的规则转为字符串。比如,大括号中是一个对象,将默认调用对象的toString
方法。
// 变量place没有声明
let msg = `Hello, ${place}`;
// 报错 `Hello ${'World'}`
// "Hello World"
模板字符串甚至还能嵌套。
const tmpl = addrs => `
<table>
${addrs.map(addr => `
<tr><td>${addr.first}</td></tr>
<tr><td>${addr.last}</td></tr>
`).join('')}
</table>
`;
上面代码中,模板字符串的变量之中,又嵌入了另一个模板字符串,使用方法如下。
const data = [
{ first: '<Jane>', last: 'Bond' },
{ first: 'Lars', last: '<Croft>' },
]; console.log(tmpl(data));
// <table>
//
// <tr><td><Jane></td></tr>
// <tr><td>Bond</td></tr>
//
// <tr><td>Lars</td></tr>
// <tr><td><Croft></td></tr>
//
// </table>
如果需要引用模板字符串本身,在需要时执行,可以写成函数。
let func = (name) => `Hello ${name}!`;
func('Jack') // "Hello Jack!"
ES6 入门的更多相关文章
- ES6入门笔记
ES6入门笔记 02 Let&Const.md 增加了块级作用域. 常量 避免了变量提升 03 变量的解构赋值.md var [a, b, c] = [1, 2, 3]; var [[a,d] ...
- es6入门4--promise详解
可以说每个前端开发者都无法避免解决异步问题,尤其是当处理了某个异步调用A后,又要紧接着处理其它逻辑,而最直观的做法就是通过回调函数(当然事件派发也可以)处理,比如: 请求A(function (请求响 ...
- es6入门3--箭头函数与形参等属性的拓展
对函数拓展兴趣更大一点,优先看,前面字符串后面再说,那些API居多,会使用能记住部分就好. 一.函数参数可以使用默认值 1.默认值生效条件 在变量的解构赋值就提到了,函数参数可以使用默认值了.正常我们 ...
- Vue+koa2开发一款全栈小程序(1.课程介绍+2.ES6入门)
1.课程介绍 1.课程概述 1.做什么? Vue+koa2开发一款全栈小程序 2.哪些功能? 个人中心.图书列表.图书详情.图书评论.个人评论列表 3.技术栈 小程序.Vue.js.koa2.koa- ...
- es6入门5--class类的基本用法
在ES6之前,准确来说JavaScript语言并无类的概念,却有模拟类的做法.相比在类似java这类传统面向对象语言中通过类来生成实例,js则通过构造函数模拟类来生成实例. 这是因为在JS设计初期,作 ...
- es6入门6--数组拓展运算符,Array.from()基本用法
本文只是作为ES6入门第九章学习笔记,在整理知识点的同时,会加入部分个人思考与解答,若想知道更详细的介绍,还请阅读阮一峰大神的ES6入门 一.拓展运算符 ES6中新增了拓展运算(...)三个点,它的作 ...
- ES6入门之let和const命令
前言 大家好,我是一只流浪的kk,当你看到这边博客的时候,说明你已经进入了ES6学习的领域了,从本篇博客开始,我将会将自己学习到ES6的相关知识进行整理,方便大家参考和学习,那么我将带你进入第一节的内 ...
- ES6入门之变量的解构赋值(二)
前言 在上一章 ES6入门之let和const命令中我们对ES6的相关语法已经有了初步了解,上一章中我们主要学习了三大部分的内容,let命令的使用,块级作用域,const命令的使用,那么从本篇博客将进 ...
- ES6入门十二:Module(模块化)
webpack4打包配置babel7转码ES6 Module语法与API的使用 import() Module加载实现原理 Commonjs规范的模块与ES6模块的差异 ES6模块与Nodejs模块相 ...
- es6入门7--Set Map数据结构
本文作为ES6入门第十三章的学习整理笔记,可能会包含少部分个人的理解推测,若想阅读更详细的介绍,还请阅读原文ES6入门 一.set数据结构 1.set不接受重复值 ES6新增了Set构造函数用于创建s ...
随机推荐
- 监督学习Supervised Learning
In supervised learning, we are given a data set and already know what our correct output should look ...
- 第二章 微服务构建:Spring Boot
此处介绍Spring Boot的目的除了它是Spring Cloud的基础外,也由于其自身的各项优点,如自动化配置.快速开发.轻松部署等,非常适合用作微服务架构中各项具体微服务的开发框架. 本章内容: ...
- mysql 开发进阶篇系列 39 mysql日志之二进制日志(binlog)
一.概述 二进制日志(binlog)记录了所有的DDL(数据定义语言)语句和DML(数据操纵语言)语句,但是不包括数据查询语句, 语句以"事件"的形式保存,它描述了数据的更改过程, ...
- 逆向知识之CS1.6辅助/外挂专题.1.实现CS1.6主武器副武器无限子弹
逆向知识之CS辅助/外挂专题.1.实现CS主武器副武器无限子弹 PS: 相信大家CS1.6这类的FPS应该玩过.现在我们通过外挂手法.讲解逆向的本质.以及应用. 关于CS1.6的下载.网络百度下载即可 ...
- [译]初试C# 8.0
原文地址: https://blogs.msdn.microsoft.com/dotnet/2018/12/05/take-c-8-0-for-a-spin/ 初试C# 8.0 昨天我们宣布了Visu ...
- net4log 添加自定义变量
在log4net.config中 <parameter> <parameterName value="@czyid" /> <dbType value ...
- 《Microsoft SQL Server 2012 T-SQL Fundamentals》
书名 <SQL Server 2012 T-SQL基础教程> 图片 时间 2017-8 学习 每章后面有习题很适合我,看完写sql的能力有质的飞跃好书 http://tsql.soli ...
- 菜鸟入门【ASP.NET Core】5:命令行配置、Json文件配置、Bind读取配置到C#实例、在Core Mvc中使用Options
命令行配置 我们通过vs2017创建一个控制台项目CommandLineSample 可以看到现在项目以来的是dotnet core framework 我们需要吧asp.net core引用进来 ...
- Python全栈学习_day007作业
Day7作业及默写 .把列表中所有姓周的人的信息删掉(升级题:此题有坑, 请慎重): 第一种方法:lst = ['周老二', '周星星', '麻花藤', '周扒皮'] # 结果: lst = ['麻花 ...
- canvas-star0.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...