ECMAScript6是继ECMAScript5之后发布的JavaScript语言的新以带标准,加入了很多的新特性和语法,该标准与2015年6月17日发布了正式版本。
因此在这里介绍标准中的一些特性和常用的语法。
块作用域构造let和const
块作用域存在于:
- 函数内部
- 块中(字符“{”和“}”之间的区域)
let声明
let的用法和var相同,但是let声明的变量不会被提升,可以把变量的作用域限制在当前代码块中。
{
var a = 1;
}
console.log("a = "+ a);//此处可以访问a变量,输出a = 1
{
let a = 1;
}
console.log("a = "+ a);//此处不能访问变量a,报错a is not defined
function changeState(flag){
if(flag){
var color = "red";
}
else{
console.log(color);//此处可以访问color,其值为undefined
return null;
}
}
changeState(false);
function changeState(flag){
if(flag){
let color = "red";
}
else{
console.log(color);//此处可以访问color,报错:color is not defined
return null;
}
}
changeState(false);
for(var i = 0; i < 10;i++){
}
console.log("i = " + i);//此处可以访问变量,输出i=10
for(let i = 0; i < 10;i++){
}
console.log("i = " + i);//此处可以访问变量,报错:i isnot defined
var index = 0;
var index = 10;//ok
let index = 100;//报错:Identifier'index'has already been declared
const声明
每个通过const关键字声明的变量必须在声明的同时进行初始化。
const sizeOfPage = 10;//正确
const maxItems;
maxItems = 200;
使用const声明对象,对象本身的绑定不能修改,但对象的属性和值是可以修改的。
const person = {
name:"zhangsan"
};
person.name = "lisi";
person.age = 20;
//错误,报错:Assignment to constant variable
person = {
name:"wangwu"
};
全局块作用域绑定
var greeting = "Welcome";
console.log(window.greeting);//Welcome
console.log(window.Screen);//function Screen(){[native code]}
var Screen = "liquid crystal";
console.log(window.Screen);//liquid crystal
let greeting = "Welcome";
console.log(window.greeting);//undefined
const Screen = "liquid crystal";
console.log(Screen === window.Screen);//false
模板字面量
模板字面量(Template Literals),对字符串的操作进行了增强操作:
- 多行字符串
- 字符串占位符
模板字面量的基础语法就是用反引号(`)来替换字符串的单、双引号。
let message = `hello World`;
//若想在字符串中使用反引号,则使用反斜杠转义
let message = `Hello \` Worle`;
//在ECMAScript5可以使用以下两种方式进行承接下一行的代码 前者利用JavaScript的语法bug 后者拼接字符串
let message = "Hello \
World";
let greeting = "Welcome"
+ "you";
//若想真正换行
let message = "Hello \n\
World";
let greeting = "Welcome"
+"\n"
+"you";
//下面介绍ECMAScript6
let message = `Hello
World`;
//以上方式即可直接换行 反引号中所有的空白字符都属于字符串的一部分(不限于空格、换行、制表符)
字符占位符
在一个模板字面量中,可以JavaScript变量或者任何合法的JavaScript表达式嵌入占位符中并将其作为字符串的一部分输出到结果中。
占位符由一个左侧“${”和右侧"}"符号组成,中间可以包含变量或JavaScript表达式。
let name = "zhangsan";
let message = `Hello,${name}`;
let amount = 5;
let price = 86.5;
let total = `The total price is ${amount * amount}`;
let name = "lisi";
let message = `Hello,${
`my name is ${name}`
}`
默认参数
在ECMAScript5中,没有直接在函数的参数列表中指定参数默认值的语法,想为函数参数指定默认值,只能通过以下方式。
function makeRedirect(url, timeout)
{
url = url || "/home";
timeout = timeout || 2000;//这种方式如果传入0会认为值是合法但是会视为假值,最终为2000
url = (typeof url != "undefined") ? url : "/home";//更加安全的做法判断是否为undefined
timeout = (typeof timeout != "undefined") ? timeout: 2000;
//函数的其余部分
}
在ECMAScript6中,简化了为形参提供默认值的过程,可以直接在参数列表为形参指定默认值。
function makeRedirect(url = "/home", timeout = 2000, callback)
{
console.log(url);
console.log(timeout);
console.log(callback);
}
//使用url和timeout的默认值
makeRedirect();
//使用url和timeout的默认值
makeRedirect(undefined, undefined, function(){});
//使用timeout的默认值
makeRedirect("/login");
//不是用timeout的默认值
makeRedirect("/login", null, function(){});
rest参数
我们知道JavaScript函数有个特别的地方,无论在函数定义中声明多少形参,都可以传入任意数量的参数,在函数内部可以通过arguments对象来接受传入的参数。ECMAScript6引入了rest参数,在函数的命名参数前面添加三个点(...),就表明这是一个rest参数,用于获取函数的多余参数。rest参数是一个数组,包含着自它之后传入的所有参数,通过数组名即可访问,注意:res参数一定要写在最后一个。
function calculate(op){
if(op === "+"){
let result = 0;
for(let i = 1; i < arguments.length; i++){
result += arguments[i];
}
return result;
}
else if(op === "*"){
let result = 1;
for(let i = 1; i < arguments.length; i++){
result *= arguments[i];
}
return result;
}
}
function calculate(op, ...data){//我们使用rest参数重写上面函数
if(op === "+"){
let result = 0;
for(let i = 0; i < data.length; i++){
result += data[i];
}
return result;
}
else if(op === "*"){
let result = 1;
for(let i = 0; i < data.length; i++){
result *= data[i];
}
return result;
}
}
console.log(calculate("*", 2, 3, 4));
function calculate(op, ...data, last){
}
展开运算符
展开运算符在语法上与rest参数是相似的,也是三个点(...),它可以将一个数组转换为各个独立的参数,也可用于取出对象的所有可遍历属性,而rest是让你指定多个独立的参数,并通过整合后的数组来访问。
let arr = [1, 2, 3];
console.log(...arr);
function sum(a, b, c){
return a + b + c;
}
let arr = [1, 2, 3];
sum(...arr);
console.log(sum(...arr));
let arr1 = [1, 2, 3];
let arr2 = arr1; //arr2与arr1是同一个数组对象
let arr3 = [...arr1]; //arr3与arr1是两个不同的数组对象
arr1[0] = 4;
console.log(arr2[0]); //arr2中的元素同时被改变,输出:4
console.log(arr3[0]); //输出:1*/
let arr1 = ['a'];
let arr2 = ['b', 'c'];
let arr3 = ['d', 'e'];
console.log([...arr1, ...arr2, ...arr3]); //[ 'a', 'b', 'c', 'd', 'e' ]*/
let book = {
tille: "Vue无难事",
price: 98
}
let bookDetail = {...book, desc: "a fine book"}
console.log(bookDetail); //{ tille: 'Vue无难事', price: 98, desc: 'a fine book' }
对象字面量语法扩展
对象字面量在ECMAScript6中,通过下面的几种语法,让对象字面量变得更加强大、更加简洁。
//ECMAScript5及其更早版本,对象字面量只是简单的键值对集合
function createCar(color, doors){
return {
color : color,
doors : doors
}
}
//冒号右边是属性赋值的变量 左边是对象的属性名称
//ECMAScript6中,通过使用属性初始值的简写语法,可以消除这种属性名称与本地变量之间的重复书写。
function createCar(color, doors){
return {
// 有同名的参数,只写属性名即可
color,
doors
}
}
let car = createCar("red", 4);
console.log(car);
let name = "zhangsan";
let age = 18;
// 有同名的本地变量,只写属性名即可
var person = {name, age};
console.log(person);
对象方法的简写语法
ECMAScript6也改进了为对象字面量定义的语法。ECMAScript5及其早先版本中,如果为对象添加方法,必须通过指定名称并完整定义函数来实现。
//ECMASript5
var car = {
color: "red",
doors: 4,
showColor: function(){
console.log(this.color);
}
}
//ECMASript6
var car = {
color: "red",
doors: 4,
showColor(){
console.log(this.color);
}
}
car.showColor();
console.log(car.showColor.name);
//通过对象方法的简写语法创建的方法有一个name属性,其值为圆括号前面的值
可计算的属性名
在JavaScript中,访问对象的属性,可以通过点号或者方括号,如果属性名包含了特殊字符或中文,亦或者需要通过计算得到属性名,则只能使用方括号。
let suffix = "name";
let person = {};
person["first name"] = "san"; // 属性名中有空格
person["last " + suffix] = "zhang"; // 属性名由表达式计算得到
person.age = 20; // 常规的属性可以直接通过点号访问
console.log(person); // { 'first name': 'san', 'last name': 'zhang', age: 20 }
let suffix = "name";
let person = {
["first " + suffix] : "san",
["last " + suffix]: "zhang",
age: 20
}
console.log(person); // { 'first name': 'san', 'last name': 'zhang', age: 20 }
解构赋值
在JavaScript的ECMAScript5中,我们经常需要从某个对象或者数组中提取特点的数据赋值给变量,这种操作重复且无趣。
// 真实应用场景中,book对象通常是从服务器端得到的数据
let book = {
title: "Vue无难事",
isbn: "9787121362217",
price: 98,
category: {
id: 1,
name: "Web前端"
}
}
// 提取对象中的数据赋给变量
let title = book.title;
let isbn = book.isbn;
let price = book.price;
let category = book.category.name;
// 提取数组中的数据赋给变量
let arr = [1, 2, 3];
let a = arr[0], b = arr[1], c=arr[2];
ECMAScript6中为对象和数组提供了解构功能,允许按照一定模式从对象和数组中提取值,对变量进行赋值。
对象解构
对象解构的语法形式是在一个赋值操作符的左边放置一个对象字面量。
let book = {
title: "Vue无难事",
isbn: "9787121362217",
price: 98
}
let {title, isbn, price} = book;//必须提供初始化语句
console.log(title); // Vue无难事
console.log(isbn); // 9787121362217
console.log(price); // 98*/
let book = {
title: "Vue无难事",
isbn: "9787121362217",
price: 98
}
let title, isbn, price;
{title, isbn, price} = book; // 语法错误
({title, isbn, price} = book); // 正确 圆括号代表一个表达式 花括号标识一个代码块
let book = {
title: "Vue无难事",
isbn: "9787121362217",
price: 98
}
let title, isbn;
function outputBookInfo(book){
console.log(book);
}
// 给title、isbn变量赋值后,因解构表达式的值是=右侧的值,
// 所以此处向outputBookInfo()函数传递的参数就是book对象
outputBookInfo({title, isbn} = book);
console.log(title); // Vue无难事
console.log(isbn); // 9787121362217
//新设置一个局部变量
let book = {
title: "Vue无难事",
isbn: "9787121362217",
price: 98
}
let {title, isbn, salesVolume = 0} = book;
console.log(title); // Vue无难事
console.log(isbn); // 9787121362217
console.log(salesVolume); // 0
//给属性名设置局部变量名
let book = {
title: "Vue无难事",
isbn: "9787121362217",
price: 98
}
let {title: bookTitle, isbn: bookIsbn} = book;
console.log(bookTitle); // Vue无难事
console.log(bookIsbn); // 9787121362217
//当对象出现嵌套时
let book = {
title: "Vue无难事",
isbn: "9787121362217",
price: 98,
category: {
id: 1,
name: "Web前端"
}
}
//let {category: {name}} = book; //局部变量名为name
let {title, isbn, category: {name: category}} = book;
console.log(title); // Vue无难事
console.log(isbn); // 9787121362217
console.log(category); // Web前端
下面重点介绍展开夫和对象解构结合起来一起使用。
let person = {
name: '张三',
age: 18
}
let {...newObject} = person;
let {anotherObjct} = person;
let{name, age, gendar} = {...person, gendar: '男'};
console.log(newObject); // { name: '张三', age: 18 }
console.log(anotherObjct); // undefined
console.log(name); // 张三
console.log(gendar); // 男
注意两个赋值语句,后者时提取person对象中anotherObject属性赋并赋值给anotherObject变量,由于person对象没有该属性,因此未undefined。
数组解构
与对象解构的语法不同,数据解构使用方括号。此外,由于数据解构本质上的不同,数组解构没有对象属性名的问题,因而在语法上更为简单。
let arr = [1, 2, 3];
let a, b, c;
[a, b, c] = arr; //OK
console.log(c);
let arr = [1, 2, 3];
let [a, b, c, d = 0] = arr;//新设置值
console.log(d);
let categories = ["C/C++", ["Vue", "React"], "Java"];
let [language1, [, language2]] = categories;//只复制第一个值和第三个值
console.log(language1); // C/C++
console.log(language2); // React
重点介绍和展开运算符一起使用的方式
let arr = [1, 2, 3];
let [a, ...others] = arr;
let [...newArr] = arr; // 数组复制的另一种实现方式
console.log(a); // 1
console.log(others); // [ 2, 3 ]
console.log(others[0]) // 2
console.log(newArr); // [ 1, 2, 3 ]
let person = {
name: '张三',
age: 18
}
let {...newObject} = person;
let {anotherObjct} = person;
let{name, age, gendar} = {...person, gendar: '男'};
console.log(newObject); // { name: '张三', age: 18 }
console.log(anotherObjct); // undefined
console.log(name); // 张三
console.log(gendar); // 男
箭头函数
ECMAScript6允许使用“箭头”(=>)定义函数,箭头函数的语法多变,根据实际的使用场景由多种形式,但都需要由函数参数、箭头和函数体组成。
单一函数、函数体只有一条语句的箭头函数
let welcome = msg => msg;
//相当于
function welcome(msg){
return msg;
}
console.log(welcome("welcome you.")); // welcome you.
如果函数由多于一个的参数,则需要在参数的两侧添加一对圆括号。
let welcome = (user, msg) => `${user}, ${msg}`;
//相当于
function welcome(user, msg){
return user + ", " + msg;
}
console.log(welcome("zhangasan", "welcome you.")); // zhangasan, welcome you.
如果函数没有参数,则需要使用一对空的圆括号。
let welcome = () => "welcome you.";
//相当于
function welcome(){
return "welcome you.";
}
console.log(welcome("welcome you.")); // welcome you.
如果函数体由多条语句,则需要用花括号包裹函数体。
let add = (a, b) => {
let c = a + b;
return c;
}
//相当于
function add(a, b){
let c = a + b;
return c;
}
console.log(add(5, 3)); // 8
如果创建空函数,则需要写一对没有内容的圆括号代表参数部分,一对没有内容的花括号代表空的函数体。
let emptyFunction = () => {};
//相当于
function emptyFunction(){}
如果箭头函数的返回值时一个对象字面量,则需要将该字面量包裹在圆括号中。
let createCar = (color, doors) => ({color: color, doors: doors});
//相当于
function createCar(color, doors){
return {
color: color,
doors: doors
}
}
console.log(createCar("black", 4)); // { color: 'black', doors: 4 }
重点,箭头函数和对象解构结合使用。
let personInfo = ({name, age}) => `${name}'s age is ${age} years old.`;
//相当于
function personInfo({name, age}){
return `${name}'s age is ${age} years old.`;
}
let person = {name: "zhangsan", age: 18};
console.log(personInfo(person)); // zhangsan's age is 18 years old.
箭头函数与this
JavaScript中的this引用或this指针不同的时,JavaScript中的this并不是指向对象本身,其指向可以改变。
var greeting = "Welcome";
function sayHello(user){
alert(this.greeting + ", " + user);
}
var obj = {
greeting: "Hello",
sayHello: sayHello
}
sayHello("zhangsan"); //Welcome, zhangsan
obj.sayHello("lisi"); //Hello, lisi
var sayHi = obj.sayHello;
sayHi("wangwu"); //Welcome, wangwu
var obj = {
greeting: "Hello",
sayHello: function(){
setTimeout(function(){
alert(this.greeting);//这样会打印undefined 在window对象中没有greeting属性
}, 2000);
}
}
obj.sayHello(); // undefined
var greeting = "Welcome";
var greeting = "Welcome";
function sayHello(user){
alert(this.greeting + ", " + user);
}
var obj = {
greeting: "Hello",
sayHello: sayHello
}
var sayHi = obj.sayHello.bind(obj);
sayHi("wangwu"); //Hello, wangwu
var obj = {
greeting: "Hello",
sayHello: function(){
setTimeout((function(){//使用bind()方法,将this明确地绑定到某个对象上
alert(this.greeting);
}).bind(this), 2000);
}
//sayHello: function(){
// var that = this;
// setTimeout(function(){
// alert(that.greeting);//此时访问的时外部函数的this
// }, 2000);
//}
}
obj.sayHello(); // Hello
使用箭头函数,箭头函数没有this绑定,必须通过查找作用域来决定其值,如果箭头函数被非箭头函数包含,则this绑定地时最近一层非箭头函数的this;否则,this的值会被设置为全局对象。
var obj = {
greeting: "Hello",
sayHello: function(){
setTimeout(() => alert(this.greeting), 2000);
}
}
obj.sayHello(); // Hello
var sayHi = obj.sayHello;
sayHi();
类
在ECMAScript6中引入了class的概念,新的class写法让对象原型的写法更加清楚,使其更像传统的面向对象编程语言的写法。
定义类
function Car(sColor,iDoors)
{
this.color= sColor;
this.doors= iDoors;
}
Car.prototype.showColor=function(){
console.log(this.color);
};
let oCar=new Car("red",4);
oCar.showColor();
class Car{
// 等价于Car构造函数
constructor(sColor,iDoors){
this.color= sColor;
this.doors= iDoors;
}
// 等价于Car.prototype.showColor
showColor(){
console.log(this.color);
}
}
let oCar = new Car("red",4);
oCar.showColor();
let Car = class {
// 等价于Car构造函数
constructor(sColor,iDoors){
this.color= sColor;
this.doors= iDoors;
}
// 等价于Car.prototype.showColor
showColor(){
console.log(this.color);
}
}
let oCar = new Car("red",4);
oCar.showColor();
let car = new class {
// 等价于Car构造函数
constructor(sColor,iDoors){
this.color= sColor;
this.doors= iDoors;
}
// 等价于Car.prototype.showColor
showColor(){
console.log(this.color);
}
}("red", 4);
car.showColor();
访问器属性
class Car{
constructor(sName, iDoors){
this._name= sName;
this.doors= iDoors;
}
// 只读属性
get desc(){
return `${this.name} is worth having.`;
}
get name(){
return this._name;
}
set name(value){
this._name = value;
}
}
let car = new Car("Benz", 4);
console.log(car.name); // Benz
console.log(car.desc); // Benz is worth having.
car.name = "Ferrari";
console.log(car.name); // Ferrari
car.prototype.desc = "very good"; //TypeError: Cannot set property 'desc' of undefined
静态方法
class Car{
constructor(sName, iDoors){
this.name= sName;
this.doors= iDoors;
}
showName(){
console.log(this.name);
}
static createDefault(){
return new Car("Audi", 4);
}
}
let car = Car.createDefault();
car.showName(); // Audi
car.createDefault(); // TypeError: car.createDefault is not a function
类的继承
class Person{
constructor(name){
this.name = name;
}
work(){
console.log("working...");
}
}
class Student extends Person{
constructor(name, no){
super(name); //调用父类的constructor(name)
this.no = no;
}
}
let stu = new Student("zhangsan", 1);
stu.work(); // woking...
class Person{
constructor(name){
this.name = name;
}
work(){
console.log("working...");
}
}
class Teacher extends Person{
//没有构造函数
}
//等价于
class Teacher extends Person{
constructor(...args){
super(...args);
}
}
let teacher = new Teacher("lisi");
teacher.work(); //working...
class Person{
constructor(name){
this.name = name;
}
work(){
console.log("working...");
}
}
class Student extends Person{
constructor(name, no){
super(name); //调用父类的constructor(name)
this.no = no;
}
// 覆盖Person.prototype.work()方法
work(){
super.work();
console.log("studying...");
}
}
let stu = new Student("zhangsan", 1);
stu.work(); // working...
// studying...
模块
ECMAScript5及其更早版本中,一直没有模块(model)体系,使得无法将一个复杂的应用拆解分成不同的功能模块,再组合起来使用。为此,JavaScript社区制定了一些模块加载方案,最主要的有CommonJS和AMD两种。ECMAScript6在语言标准的层面,实现了模块功能,而且实现得相当简单,完全可以取代CommonJS和AMD规范,成为浏览器和服务器通用得模块解决方案。
一个模块通常是一个独立的JS文件,该文件内部定义的变量和函数除非被导出,否则不能被外部访问。
下面介绍使用export语句:
// 导出数据
export var color = "red";
export let name = "module";
export const sizeOfPage = 10;
// 导出函数
export function sum(a, b){
return a + b;
}
// 将在模块末尾进行导出
function subtract(a, b){
return a - b;
}
// 将在模块末尾进行导出
function multiply(a, b){
return a * b;
}
// 将在模块末尾进行导出
function divide(a ,b){
if(b !== 0)
return a / b;
}
// 导出类
export class Car {
constructor(sColor, iDoors){
this.color = sColor;
this.doors = iDoors;
}
showColor(){
console.log(this.color);
}
}
// 模块私有的变量
var count = 0;
// 模块私有的函数
function changeCount(){
count++;
}
// 导出multiply函数
export {multiply};
// subtract是本地名称,sub是导出时使用的名称
export {subtract as sub}
// 导出模块默认值
export default divide;
export {multiply, subtract as sub, divide as default};
// 第二种语法形式
// 使用default关键字导出一个函数作为模块的默认值,
// 因为导出的函数被模块所代表,所以它不需要一个名称
export default function(a ,b){
if(b !== 0)
return a / b;
}
// ----------------------- //
function divide(a ,b){
if(b !== 0)
return a / b;
}
// 第三种语法形式
export {divide as default}
下面是通过使用import关键字来引入其他模块导出的功能。
// 导入模块默认值
import divide from "./Modules.js";
// 导入多个绑定
import {color, name, sizeOfPage} from "./Modules.js";
// 导入单个绑定
import {multiply} from "./Modules.js";
// 因Modules模块中导出subtract函数时使用了名称sub,这里导入也要用该名称
import {sub} from "./Modules.js";
// 导入时重命名导入的函数
import {sum as add} from "./Modules.js";
// 导入类
import {Car} from "./Modules.js";
// 导入整个模块
import * as example from "./Modules.js";
console.log(color); //red
console.log(name); //module
console.log(sizeOfPage); //10
// 只能用add而不能用sum了
console.log(add(6, 2)); //8
console.log(sub(6, 2)); //4
console.log(multiply(6, 2)); //12
console.log(divide(6, 2)); //3
let car = new Car("black", 4);
car.showColor(); //black
console.log(example.name); //module
// 注意这里是sum,而不是add
console.log(example.sum(6, 2)); // 8
// count是Modules模块中私有的变量,在外部不能访问
console.log(example.count); //undefined
// changeCount()函数是Modules模块中私有的函数,在外部不能访问
console.log(example.changeCount()); //TypeError: example.changeCount is not a function
export和import语句必须在其他语句或者函数之外使用,换句话说,import和export语句只能在模块的顶层使用。
promise
事件循环是JavaScriptu引擎中的一段程序,负责监控代码执行并管理任务队列。
随着应用的负责复杂,事件和回调函数无法完全满足开发者想要做的事情,为此,ECMAScript6给出了promise这一强大的异步编程解决方案。
一个promise可以通过promise构造函数来创建,这个构造函数只接受一个参数:包含初始化promise代码的执行器(executor)函数,在该函数内包含需要异步执行的代码。执行器函数接受两个参数,分别为resole函数和reject函数,这两个函数由JavaScript引擎提供,不需要我们自己编写。异步操作结束成功时调用resolve函数,失败时调用reject函数。
const promise = new Promise(function(resolve, reject) {
// 开启异步操作
if ( 异步操作成功 ){
resolve(result);
} else {
reject(error);
}
});
const promise = new Promise(function(resolve, reject) {
console.log("executor");
resolve();
});
promise.then(function(){
console.log("then");
})
const promise = new Promise(function(resolve, reject) {
// 开启异步操作
setTimeout(function(){
try{
let c = 6 / 0 ;
// 执行成功调用resolve函数
resolve(c);
}catch(ex){
// 执行失败调用reject函数
reject(ex);
}
}, 1000);
});
promise.then(function(value){
// 完成
console.log(value); // 3
},function(err){
// 拒绝
console.error(erro.message);
})
promise.then(null,function(err){
// 拒绝
console.error(err.message);
})
prommise.catch(function (err){
console.error(err.message);
})
promise.then(function(value){
// 完成
console.log(value); // 3
}).catch(function (err){
// 拒绝
console.error(err.message);
});
promise.then(value => console.log(value))
.catch(err => console.error(err.message));
const promise = new Promise((resolve, reject) => {
// 调用setTimeout模拟异步操作
setTimeout( ()=> {
let intArray = new Array(20);
for(let i=0; i<20; i++){
intArray[i] = parseInt(Math.random() * 20, 10);
}
// 成功后调用resolve
resolve(intArray);
},1000);
// 该代码会立即执行
console.log("开始生成一个随机数的数组")
});
promise.then(value => {
value.sort((a,b) => a-b);
return value;
}).then(value => console.log(value));
const promise = new Promise((resolve, reject)=>{
resolve("Hello Word");
});
promise.then((value) => {
console.log(value);
throw new Error("错误");
}).catch(err => console.error(err.message));