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

结果如下:
file

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);

发表评论

电子邮件地址不会被公开。 必填项已用*标注