1.let
ES6新增了let命令,用来声明变量。它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效。
可以简单的理解为,var声明的是全局变量,let声明的局部变量。
function f1() {
var n = 5;
if (true) {
var n = 10;
}
console.log(n);
}
f1();//输出结果为10
function f2() {
var n = 5;
if (true) {
let n = 10;
}
console.log(n);
}
f2();//输出结果为5
2. const
const声明一个只读的常量。一旦声明,常量的值就不能改变。
这意味着,const一旦声明变量,就必须立即初始化,不能留到以后赋值。
但对于复合类型的变量,变量名不指向数据,而是指向数据所在的地址。const命令只是保证变量名指向的地址不变,并不保证该地址的数据不变,所以将一个对象声明为常量必须非常小心。
3. 模板字符串
传统的JavaScript语言,输出模板通常是这样写的($('#xxx')
是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`);
// 字符串中嵌入变量
var name = "Bob";
var time = "today";
//模板字符串中嵌入变量,需要将变量名写在${}之中。
var nameTime = `Hello ${name}, how are you ${time}?`;
console.log(nameTime);//输出:Hello Bob, how are you today?
//大括号内部可以放入任意的JavaScript表达式,可以进行运算,以及引用对象属性。
var x = 1;
var y = 2;
`${x} + ${y} = ${x + y}`// "1 + 2 = 3"
`${x} + ${y * 2} = ${x + y * 2}`// "1 + 4 = 5"
var obj = {x: 1, y: 2};
`${obj.x + obj.y}`// 3
//模板字符串之中还能调用函数。
function fn() {
return "Hello World";
}
`foo ${fn()} bar`// foo Hello World bar
4. 标签模板
模板字符串的功能,不仅仅是上面这些。它可以紧跟在一个函数名后面,该函数将被调用来处理这个模板字符串。这被称为“标签模板”功能(tagged template)。
alert`123`
// 等同于
alert(123)
“标签模板”的一个重要应用,就是过滤HTML字符串,防止用户输入恶意内容。
var sender = '<script>alert("abc")</script>'; // 恶意代码
var message = SaferHTML`<p>${sender} has sent you a message.</p>`;//SaferHTML是个自定义函数。
console.log(message);// <p><script>alert("abc")</script> has sent you a message.</p>
5. 对象扩展
ES6允许在对象之中,只写属性名,不写属性值。这时,属性值等于属性名所代表的变量。下面是另一个例子。
function f(x, y) {
return {x, y};
}
// 等同于
function f(x, y) {
return {x: x, y: y};
}
f(1, 2) // Object {x: 1, y: 2}
6. Module
6.1 解决Javascript的模块化问题。
早期的Javascript,最让人头痛的就是js代码无法互相引用的问题。这对于大型项目而言就像噩梦一般。
ES6原生了代码引用功能,从根本上解决了js代码模块化的问题。
6.2 export和import语法。
6.2.1 使用export暴露模块。
// profile.js
var firstName = 'Michael';
var lastName = 'Jackson';
var year = 1958;
function v1() { ... }
export {
firstName,
lastName,
year,
v1 as streamV1,
};
6.2.2 使用export default暴露模块
export default function foo() {
console.log('foo');
}
//等同于
function foo() {
console.log('foo');
}
export default foo;
每个模块只能有一个export default
6.2.3 使用import使用模块。
// 使用export default输出
export default function crc32() {
// ...
}
// 针对export default的输入语法
import anyName from 'crc32';
// 使用普通export输出
export function crc32() {
// ...
};
// 针对普通export的输入语法
import {crc32} from 'crc32';
上面代码的两组写法,第一组是使用export default时,对应的import语句不需要使用大括号;第二组是不使用export default时,对应的import语句需要使用大括号。
export default命令用于指定模块的默认输出。显然,一个模块只能有一个默认输出,因此export deault命令只能使用一次。所以,import命令后面才不用加大括号,因为只可能对应一个方法。
本质上,export default就是输出一个叫做default的变量或方法,然后系统允许你为它取任意名字。
6.4 ECMAScript6和CommonJS在模块化上的区别
参考:https://www.w3cschool.cn/ecmascript/ueqp1q5g.html
6.4.1 Node.js不支持ES6的模块语法
做这个比较主要是由于Node.js不支持ES6的import和export功能导致的。说来也奇怪,Node.js已经支持了92%的ES6语法,唯独对ES6这个最重要的模块功能不支持。这一点可以通过安装ES-Checker模块来查看Node.js对ES6的支持:
$ npm install -g es-checker
$ es-checker
结果如下:
6.4.2 Node.js使用CommonJS解决模块问题
在Node.js中默认集成了CommonJS,所以一般都用CommonJS来实现模块的输入输出。
CommonJS的模块语法是使用require和exports。
exports示例如下:
// ./utils/util.js
var textHello = "Hello World!";
function addFun(a,b){
return a+b;
}
function sayHello(){
return "Say Hello!";
}
//完整写法:module.exports.在外面被引用的名字 = 模块内的名字
module.exports.textHello = textHello;
//简写:exports.在外面被引用的名字 = 模块内的名字
exports.addFun = addFun;
//在外面被引用的名字和模块内的名字可以不一样
exports.sayH = sayHello;
//上面三个export语句等同于下面一句
module.exports = {
textHello:textHello, //完整写法 - 在外面被引用的名字:模块内的名字
addFun, //简写 - 在外面被引用的名字和模块内的名字相同,可以只写一个
sayH:sayHello //如在外面被引用的名字与模块内的名字不同,则必须用:方式
}
require示例如下:
// main.js
moduleUtil = require("./utils/util");
console.log(moduleUtil.textHello);
console.log(moduleUtil.addFun(2,3));
console.log(moduleUtil.sayH());
/*以上三行输出:
Hello World!
5
Say Hello!
*/
当然,如果你必须要在Node.js中使用ES6原生的import和export也是可以的,前提是必须借助Babel这类的转换器。
6.4.3 两者的区别
ES6模块加载的机制,与CommonJS模块完全不同。CommonJS模块输出的是一个值的拷贝,而ES6模块输出的是值的引用。
CommonJS模块输出的是被输出值的拷贝,也就是说,一旦输出一个值,模块内部的变化就影响不到这个值。
ES6模块的运行机制与CommonJS不一样,它遇到模块加载命令import时,不会去执行模块,而是只生成一个动态的只读引用。等到真的需要用到时,再到模块里面去取值,换句话说,ES6的输入有点像Unix系统的“符号连接”,原始值变了,import输入的值也会跟着变。
7. 属性和方法的简写
var name = "Tom";
var app = {
name = name,
run:function(){
console.log(`${name} is running!`);
}
}
等同于:
var name = "Tom";
var app = {
name, //前提是属性名和属性值相同
run(){
console.log(`${name} is running!`);
}
}
8. 箭头函数
箭头函数可以理解为是对匿名函数的一种缩写。但是与匿名函数不同的是,箭头函数里面的this指向的是上下文。
8.1 极简示例。
function (x) {
return x * x;
}
等同于
(x)=>{return x * x;}
8.2 另一个示例。
setTimeout(function(){
console.log("Hello!There!");
},1000);
等同于
setTimeout(()=>{
console.log("Hello!There2!");
},1000);