ES6

ECMAScript 6 入门

1.let 和 const

在ES6之前,js只有全局作用域和函数作用域,ES6中let关键字为其引入了块级作用域。

//{}代码块
{
var a = 5;
let b = 6;
}
console.log(a);     //5
console.log(b);     //b is undefined

let声明的变量只能在其所在的代码块内才能访问,var声明的变量由于是全局变量,因此可以在代码块外访问

const用来定义常量,相当于java中的final关键字。
并且const声明常量之后就必须立即初始化!

2.暂时性死区

var声明的变量可以在声明之前使用,相当于默认为其声明其值为undefined了;

但是,let声明的变量一旦用let声明,那么在声明之前,此变量都是不可用的,术语称为“暂时性死区”。

console.log(a);                     //undefined
var a=8;
console.log("----------");
console.log(b);                     //控制台报错
let b=9;

所以我们要养成变量先声明再使用的好习惯。

3.解构赋值

以前,为变量赋值,只能直接指定值。

let a = 1;
let b = 2;
let c = 3;

ES6 允许写成下面这样。可以理解为“模式匹配”。

let [a, b, c] = [1, 2, 3];

如果解构不成功,变量的值就等于undefined。

let [x, y, ...z] = ['a'];
x // "a"
y // undefined
z // []

另一种情况是不完全解构,即等号左边的模式,只匹配一部分的等号右边的数组。这种情况下,解构依然可以成功。

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

let [a, [b], d] = [1, [2, 3], 4];
a // 1
b // 2
d // 4

4.字符串的扩展

//Unicode表示法
"\u{码点}"
"\u{41}\u{42}\u{43}"                 //"ABC"

let str = "書剑恩仇录";
str.codePointAt(0).toString(16);    //返回字符的码点并由十进制转到16进制---66f8
String.fromCodePoint(0x66f8);       //返回码点对应的字符---書
for (let a of str){
   console.log(a);
}                                   //for...of循环遍历字符串中每个字符挨个输出字符
str.at(0);                          //返回指定位置的字符,目前只是提案
str.startsWith('書',0);             //从指定位置往后开始检查,是否以“書”开始,位置参数可省略,默认为0
str.endsWith('剑',1);               //从指定位置向前检查,是否以“剑”结束
str.includes('恩',1);               //同上,不再啰嗦
str.repeat(2);                      //字符串重复指定次数“書剑恩仇录書剑恩仇录”,小数取整,Infinity和负数报错
str.padStart(8,'ab');               //指定字符从前开始补直到字符串长度符合要求,"aba書剑恩仇录"
str.padEnd(8,'ab');                 //指定字符从后开始补直到字符串长度符合要求,"書剑恩仇录aba",若长度小于原长度,返回原字符串,上同
模板字符串

模板字符串采用反引号 ` 标识,并且模板字符串中的空格、换行将在输出时有所保留。
传统的 JavaScript 语言,输出模板通常是这样写的。

$('#result').append(
  'There are ' + basket.count + ' ' +
  'items in your basket, ' +
  '' + basket.onSale +
  ' are on sale!'
);

上面这种写法相当繁琐不方便,ES6 引入了模板字符串解决这个问题。

$('#result').append(`
  There are ${basket.count} items
   in your basket, ${basket.onSale}
  are on sale!
`);
// 普通字符串
`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}?`

5.正则的扩展

RegExp 构造函数

在 ES5 中,RegExp构造函数的参数有两种情况。

//第一种情况是,参数是字符串,这时第二个参数表示正则表达式的修饰符(flag)。
var regex = new RegExp('xyz', 'i');
// 等价于
var regex = /xyz/i;

//第二种情况是,参数是一个正则表示式,这时会返回一个原有正则表达式的拷贝。
var regex = new RegExp(/xyz/i);
// 等价于
var regex = /xyz/i;

但是,ES5 不允许此时使用第二个参数添加修饰符,否则会报错。

var regex = new RegExp(/xyz/, 'i');
// Uncaught TypeError: Cannot supply flags when constructing one RegExp from another

ES6 改变了这种行为。如果RegExp构造函数第一个参数是一个正则对象,那么可以使用第二个参数指定修饰符。而且,返回的正则表达式会忽略原有的正则表达式的修饰符,只使用新指定的修饰符。

new RegExp(/abc/ig, 'i').flags
// "i"

上面代码中,原有正则对象的修饰符是ig,它会被第二个参数i覆盖。

6.数值的扩展

//从 ES5 开始,在严格模式之中,八进制就不再允许使用前缀0表示,ES6 进一步明确,要使用前缀0o表示。
//如果要将0b和0o前缀的字符串数值转为十进制,要使用Number方法。
Number('0b111')  // 7
Number('0o10')  // 8


//Number.isFinite()用来检查一个数值是否为有限的(finite),即不是Infinity。
Number.isFinite(0.1); // true
Number.isFinite(NaN); // false
Number.isFinite(Infinity); // false
Number.isFinite('0.1'); // false
Number.isFinite(true); // false
//传统方法会先调用Number()将非数值的值转为数值,再进行判断,而这两个新方法只对数值有效
isFinite("25") // true
Number.isFinite("25") // false


//Number.isNaN()用来检查一个值是否为NaN。
Number.isNaN(NaN) // true
Number.isNaN(15) // false
Number.isNaN('15') // false
Number.isNaN(true) // false
Number.isNaN(9/NaN) // true
Number.isNaN('true' / 0) // true
Number.isNaN('true' / 'true') // true
//传统方法会先调用Number()将非数值的值转为数值,再进行判断,而这两个新方法只对数值有效
isNaN("NaN") // true
Number.isNaN("NaN") // false


//ES6 将全局方法parseInt()和parseFloat(),移植到Number对象上面,行为完全保持不变。
// ES5的写法
parseInt('12.34') // 12
parseFloat('123.45#') // 123.45
// ES6的写法
Number.parseInt('12.34') // 12
Number.parseFloat('123.45#') // 123.45

//Number.isInteger()用来判断一个数值是否为整数。
Number.isInteger(25) // true
Number.isInteger(25.0) // true
Number.isInteger(25.1) // false
Number.isInteger() // false
Number.isInteger(null) // false
Number.isInteger('15') // false
Number.isInteger(true) // false

//ES6 在Number对象上面,新增一个极小的常量Number.EPSILON。根据规格,它表示 1 与大于 1 的最小浮点数之间的差。
Number.EPSILON === Math.pow(2, -52) // true
Number.EPSILON // 2.220446049250313e-16
Number.EPSILON.toFixed(20) // "0.00000000000000022204"

//ES6 引入了Number.MAX_SAFE_INTEGER和Number.MIN_SAFE_INTEGER这两个常量,用来表示这个范围的上下限。
Number.MAX_SAFE_INTEGER === Math.pow(2, 53) - 1// true
Number.MAX_SAFE_INTEGER === 9007199254740991// true
Number.MIN_SAFE_INTEGER === -Number.MAX_SAFE_INTEGER// true
Number.MIN_SAFE_INTEGER === -9007199254740991// true

//ES6 在 Math 对象上新增了 17 个与数学相关的方法。所有这些方法都是静态方法,只能在 Math 对象上调用。
Math.trunc(4.1) // 4    Math.trunc方法用于去除一个数的小数部分,返回整数部分。
Math.sign(-5) // -1     Math.sign方法用来判断一个数到底是正数、负数、还是零
Math.cbrt('8') // 2     Math.cbrt方法用于计算一个数的立方根。
//........

7.函数的扩展

参数默认值
ES5中的写法
function log(x, y) {
  //y = y || 'World';  --> 这种写法如果y是false则不起作用,所以用下面的方式复制
  if (typeof y === 'undefined') {
    y = 'World';
  }
  console.log(x, y);
}

log('Hello') // Hello World

ES6中的写法
function log(x, y = 'World') {
  console.log(x, y);
}
log('Hello') // Hello World
与解构赋值默认值的结合
function m1({x = 0, y = 0} = {}) {
  return [x, y];
}

作用域
let x = 1;

function f(y = x) {
  let x = 2;
  console.log(y);
}

f() // 1

参数y的默认值等于变量x。调用函数f时,参数形成一个单独的作用域。在这个作用域里面,默认值变量x指向第一个参数x,而不是全局变量x,所以输出是2。

name属性
function foo() {}
foo.name // "foo"
箭头函数
var f = v => v;
// 等同于
var f = function (v) {
  return v;
};

//如果箭头函数不需要参数或需要多个参数,就使用一个圆括号代表参数部分。
var f = () => 5;
// 等同于
var f = function () { return 5 };

8.数组的扩展

扩展运算符(spread)是三个点(…)。它好比rest参数的逆运算,将一个数组转为用逗号分隔的参数序列。

//----------------------------复制数组
// ES5的 写法
const a1 = [1, 2];
const a2 = a1.concat();
a2[0] = 2;
a1 // [1, 2]
// ES6的 写法
const a1 = [1, 2];
// 写法一
const a2 = [...a1];
// 写法二
const [...a2] = a1;

//-----------------------------合并数组
const arr1 = ['a', 'b'];
const arr2 = ['c'];
const arr3 = ['d', 'e'];
// ES5 的合并数组
arr1.concat(arr2, arr3);
// [ 'a', 'b', 'c', 'd', 'e' ]
// ES6 的合并数组
[...arr1, ...arr2, ...arr3]
// [ 'a', 'b', 'c', 'd', 'e' ]

Array.from方法用于将两类对象转为真正的数组

Array.from([1, 2, 3])// [1, 2, 3]

Array.of方法用于将一组值,转换为数组。

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

数组实例的copyWithin方法,在当前数组内部,将指定位置的成员复制到其他位置(会覆盖原有成员),然后返回当前数组。也就是说,使用这个方法,会修改当前数组。

//Array.prototype.copyWithin(target, start = 0, end = this.length)
[1, 2, 3, 4, 5].copyWithin(0, 3)
// [4, 5, 3, 4, 5]  --> 上面代码表示将从 3 号位直到数组结束的成员(4 和 5),复制到从 0 号位开始的位置,结果覆盖了原来的 1 和 2。

数组实例的find方法,用于找出第一个符合条件的数组成员。它的参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为true的成员,然后返回该成员。如果没有符合条件的成员,则返回undefined。

[1, 4, -5, 10].find((n) => n < 0)
// -5

[1, 5, 10, 15].find(function(value, index, arr) {
  return value > 9;
}) // 10

数组实例的findIndex方法的用法与find方法非常类似,返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1。

[1, 5, 10, 15].findIndex(function(value, index, arr) {
  return value > 9;
}) // 2

fill方法使用给定值,填充一个数组。

['a', 'b', 'c'].fill(7)
// [7, 7, 7]

new Array(3).fill(7)
// [7, 7, 7]

entries(),keys()和values()——用于遍历数组

for (let index of ['a', 'b'].keys()) {
  console.log(index);
}
// 0
// 1

for (let elem of ['a', 'b'].values()) {
  console.log(elem);
}
// 'a'
// 'b'

for (let [index, elem] of ['a', 'b'].entries()) {
  console.log(index, elem);
}
// 0 "a"
// 1 "b"

//如果不使用for...of循环,可以手动调用遍历器对象的next方法,进行遍历。
let letter = ['a', 'b', 'c'];
let entries = letter.entries();
console.log(entries.next().value); // [0, 'a']
console.log(entries.next().value); // [1, 'b']
console.log(entries.next().value); // [2, 'c']

includes方法返回一个布尔值,表示某个数组是否包含给定的值,与字符串的includes方法类似

[1, 2, 3].includes(2)     // true
[1, 2, 3].includes(4)     // false
[1, 2, NaN].includes(NaN) // true

数组的空位指,数组的某一个位置没有任何值。比如,Array构造函数返回的数组都是空位。

Array(3) // [, , ,]

0 in [undefined, undefined, undefined] // true
0 in [, , ,] // false

9.对象的扩展

//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}

//JavaScript 定义对象的属性,有两种方法。
// 方法一
obj.foo = true;

// 方法二
obj['a' + 'bc'] = 123;

var obj = {
  foo: true,
  abc: 123
};

10.Symbol

ES6 引入了一种新的原始数据类型Symbol,表示独一无二的值。它是 JavaScript 语言的第七种数据类型,前六种是:undefined、null、布尔值(Boolean)、字符串(String)、数值(Number)、对象(Object)。

let s = Symbol();

typeof s
// "symbol"

上面代码中,变量s就是一个独一无二的值。typeof运算符的结果,表明变量s是 Symbol 数据类型,而不是字符串之类的其他类型。

11.Set和Map

ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。

const s = new Set();

[2, 3, 5, 4, 5, 2, 2].forEach(x => s.add(x));

for (let i of s) {
  console.log(i);
}
// 2 3 5 4

ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说,Object 结构提供了“字符串—值”的对应,Map 结构提供了“值—值”的对应,是一种更完善的 Hash 结构实现。如果你需要“键值对”的数据结构,Map 比 Object 更合适。

const m = new Map();
const o = {p: 'Hello World'};

m.set(o, 'content')
m.get(o) // "content"

m.has(o) // true
m.delete(o) // true
m.has(o) // false

12.Proxy与Reflect

Proxy 用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种“元编程”(meta programming),即对编程语言进行编程

实例:使用 Proxy 实现观察者模式
观察者模式(Observer mode)指的是函数自动观察数据对象,一旦对象有变化,函数就会自动执行。

const person = observable({
  name: '张三',
  age: 20
});

function print() {
  console.log(`${person.name}, ${person.age}`)
}

observe(print);
person.name = '李四';
// 输出
// 李四, 20

13.Promise

Promise 是异步编程的一种解决方案,比传统的解决方案–回调函数和事件--更合理和更强大。它由社区最早提出和实现,ES6将其写进了语言标准,统一了语法,原生提供了Promise

所谓Promise ,简单说就是一个容器,里面保存着某个未来才回结束的事件(通常是一个异步操作)的结果。从语法上说,Promise是一个对象,从它可以获取异步操作的消息。
Promise 对象的状态不受外界影响

三种状态:

  • pending:进行中
  • fulfilled : 已经成功
  • rejected :已经失败

ajax的异步:

$(function(){
    $('#send').click(function(){
         $.ajax({
             type: "GET",
             url: "test.json",
             data: {username:$("#username").val(), content:$("#content").val()},
             dataType: "json",
             success: function(data){
                         $('#resText').empty();   //清空resText里面的所有内容
                         var html = ''; 
                         $.each(data, function(commentIndex, comment){
                               html += '
' + comment['username'] + ':

+ comment['content'] + '

'
; }); $('#resText').html(html); } }); }); });

上面的例子实现了一个类似于表单提交的功能。
Promise的异步:

let promise = new Promise(function(resolve, reject) {
  console.log('Promise');                        //实例化后立即执行
  resolve();                                     //任务(成功)完成
});

promise.then(function() {
  console.log('resolved.');                      //任务结束执行
});

console.log('Hi!');                              //在实例化promise的同时,执行

14.Iterator接口

for...in循环:只能获取对象的键名
for...of循环:可以获得键值,只返回具有数字索引的属性(键或值)

var arr = ['a', 'b', 'c', 'd'];
for (let a in arr) {
  console.log(a);                  // 0 1 2 3
}
for (let a of arr) {
  console.log(a);                  // a b c d
}

15.async函数

async就表示asynchronous(异步的),async函数会返回一个Promise对象,自然能够调用其方法:
promise.then(success()).catch(error()).finally(function(){});

async function getStockPriceByName(name) {
    const symbol = await getStockSymbol(name);
    const stockPrice = await getStockPrice(symbol);
    return stockPrice;             //stockPrice是一个promise对象
}

getStockPriceByName('goog').then(function (result) {
    console.log(result);
});

16.class

class ColorPoint extends Point {
  constructor(x, y, color) {
    super(x, y);                                // 调用父类的constructor(x, y)
    this.color = color;
  }

  toString() {
    return this.color + ' ' + super.toString(); // 调用父类的toString()
  }
}

17.模块化

//lib.js
var counter = 3;
function incCounter() {
  counter++;
}
module.exports = {
  counter: counter,
  incCounter: incCounter,
};

这是一个js模块,对外暴露两个属性counter(变量)、incCounter(函数),然后再去加载这个模块
这样就可以去调用该模块对外暴露的属性了:

// main.js
var mod = require('./lib');

console.log(mod.counter);  // 3
mod.incCounter();
console.log(mod.counter);  // 3

你可能感兴趣的:(JavaScript)