什么是ECMAScript
ECMAScript 是一种由 ECMA国际(前身为欧洲计算机制造商协会)通过 ECMA-262 标准化的脚本程序设计语言。
ECMAScript 是一种可以在宿主环境中执行计算并能操作可计算对象的基于对象的程序设计语言。ECMAScript 最先被设计成一种 Web 脚本语言,用来支持 Web 页面的动态表现以及为基于 Web 的客户机—服务器架构提供服务器端的计算能力。但作为一种脚本语言, ECMAScript 具备同其他脚本语言一样的性质,即“用来操纵、定制一个已存在系统所提供的功能,以及对其进行自动化”。
Javascript,JScript,ActionScript 等脚本语言都是基于 ECMAScript 标准实现的。
所以,ECMAScript 实际上是一种脚本在语法和语义上的标准。实际上 JavaScript 是由 ECMAScript,DOM 和 BOM 三者组成的。 所以说,在 JavaScript,JScript 和 ActionScript 中声明变量,操作数组等语法完全一样,因为它们都是 ECMAScript。但是在操作浏览器对象等方面又有各自独特的方法,这些都是各自语言的扩展。
ECMAScript 和 JavaScript 的关系
JavaScript是ECMAScript最流行的实现之一,JavaScript的核心功能基于ECMAScript标准,但JavaScript还具有ECMAScript标准中没有的其他功能。所以两者密不可分。
JavaScript 一种直译式脚本语言,是一种动态类型、弱类型、基于原型的语言,内置支持类型。它的解释器被称为 JavaScript 引擎,为浏览器的一部分,广泛用于客户端的脚本语言,最早是在 HTML(标准通用标记语言下的一个应用)网页上使用,用来给 HTML 网页增加动态功能。
ECMAScript 是一种由 Ecma 国际(前身为欧洲计算机制造商协会,European Computer Manufacturers Association)通过 ECMA-262 标准化的脚本程序设计语言。这种语言在万维网上应用广泛,它往往被称为 JavaScript 或 JScript,但实际上后两者是 ECMA-262 标准的实现和扩展。
ECMAScript 和 JavaScript 的关系是,前者是后者的规格,后者是前者的一种实现。
ECMAScript各版本新增特性
ES6新增特性
1、let 与 const
在之前 JS 是没有块级作用域的,const与 let 填补了这方便的空白,const与 let 都是块级作用域。
// 1、var可以重复声明,let不可以
var a = 1;
var a = truelet a = 1;
let a = true; // 未编译已经提示出错//var和let都具备函数作用域function check() {var a = "yes"let b = "no"
}
console.log(a) // 报错
console.log(b) // 报错// var let 都不存在变量提升console.log(a) // 输出undefined
var aconsole.log(a) // 报错:Cannot access 'a' before initialization
let a//1. 初始化时需要赋值
const A = "yes"
//2. 初始化后值不能改变
A = "no" // 报错:Assignment to constant variable.
//3. 命名规范:大写字母和下划线
const CONSOLE_O = "o"//4. 当常量的地址不变时,可以添加值
const TAME = ['yyt', 'zy', 'vh']
TAME.push('zyjaaa')
console.log(TAME)TAME = 1 // 报错:TypeError: Assignment to constant variable.
2、类
ES6 引入了 class(类),让 JavaScript 的面向对象编程变得更加简单和易于理解。
class Animal{constructor() {console.log("I'm a Animal");}cat() {console.log('cat!');}static eat() {console.log("Eat Now.");}
}console.log(typeof Animal); // function
let animal= new Animal(); // "I'm a Animal."
animal.cat(); // "cat!"
animal.eat(); // "Eat Now."
3、模块化
ES Modules 是用于处理模块的 ECMAScript 标准。 虽然 Node.js 长期使用 CommonJS 标准,但浏览器从未有过模块系统。 每个主要决策必须首先由 ECMAScript 标准化,然后由浏览器实施。
ES5 支持原生的模块化,在ES6中模块作为重要的组成部分被添加进来。模块的功能主要由 export 和 import 组成。每一个模块都有自己单独的作用域,模块之间的相互调用关系是通过 export 来规定模块对外暴露的接口,通过 import 来引用其它模块提供的接口。同时还为模块创造了命名空间,防止函数的命名冲突。
一、导出 export
假设我们有一个名为module.js的模块
export const CONSTANT = 2;export let variable = 2;
// 对外暴露的变量为只读
// 无法从外部修改
// 导出函数
export function fun() {console.log('fun');
}// 导出类
export class C extends Super {method() {console.log('method');}
}
二、导入 import
import { CONSTANT, variable } from './module.js';
// 导入由其他模块导出的“绑定”
// 这些绑定是动态的. 这里并非获取到了值的副本
// 而是当将要访问“variable”时
// 再从导入的模块中获取当前值import * as module from './module.js';
module.fun();
// 导入包含所有导出内容的“命名空间对象”import Super from './module.js';let super = new Super()
4、箭头函数
参数 => 函数体
=>不只是关键字 function 的简写,它还带来了其它好处。箭头函数与包围它的代码共享同一个 this,能帮你很好的解决this的指向问题。比如 var self = this;或 var that =this这种引用外围this的模式。但借助 =>,就不需要这种模式了。
() => 1v => v+1(a,b) => a+b() => {alert("foo");
}e => {if (e == 0){return 0;}return 1000/e;
}//声明一个函数
let fn = function(a){return a + 10
}//箭头函数
let fn = (a) => {return a + 10
}//简写
let fn = a => a + 10//调用函数
let result = fn(10)
console.log(result) // 20
5、模板字符串
ES6 支持 模板字符串,模板字符串相当于加强版的字符串,用反引号 `,使得字符串的拼接更加的简洁、直观。
//不使用模板字符串
var name = 'Your name is ' + first + ' ' + last + '.'
//使用模板字符串
var name = `Your name is ${first} ${last}.`
6、解构赋值
解构赋值语法是 JavaScript 的一种表达式,可以方便的从数组或者对象中快速提取值赋给定义的变量。
// 对象
const student = {name: 'Sam',age: 22,sex: '男'
}
// ES5;
const name = student.name;
const age = student.age;
const sex = student.sex;
console.log(name + ' --- ' + age + ' --- ' + sex);// ES6
// 对象
const { name, age, sex } = student;
console.log(name + ' --- ' + age + ' --- ' + sex);// 数组
// 数组结构
const F4 = ['小沈阳', '刘能', '赵四', '宋小宝']
// es5
let shenyang = F4[0]
let liunneng = F4[1]
//es6
let [shenyang, liunneng, zhaosi, songxiaobao] = F4 // 使用中括号
7、延展操作符
延展操作符...可以在函数调用/数组构造时, 将数组表达式或者 string 在语法层面展开;还可以在构造对象时, 将对象表达式按 key-value 的方式展开。
//在函数调用时使用延展操作符
function sum(x, y, z) {return x + y + z
}
const numbers = [1, 2, 3]
console.log(sum(...numbers))//数组
const stuendts = ['Jine', 'Tom']
const persons = ['Tony', ...stuendts, 'Aaron', 'Anna']
conslog.log(persions)
8、Promise
Promise是ES6中提供的优化异步操作的解决方案。解决了ES6之前异步操作,反复嵌套回调函数所导致的回调地狱问题。
从语法上来讲,Promise是一个构造函数,它可以获取异步操作的请求,且返回一个结果。Promise有三种状态:pending(等待),fulfiled(成功),rejected(失败)。状态一旦改变,就不会再变。创造Promise实例后,它会立即执行。
Promise 是异步编程的一种解决方案,比传统的解决方案 callback 更加的优雅。它最早由社区提出和实现的,ES6 将其写进了语言标准,统一了用法,原生提供了 Promise 对象。
// 实例化Promise对象:
// Promise对象有三个状态:初始化,成功,失败
// resolve:函数类型的参数,可以将Promise的状态改为成功
// rejecg:函数类型的参数,可以将Promise的状态改为失败const p = new Promise((resolve, reject) => {if (true) {resolve('Success Promise');} else {reject('Error Promise');}
})// 调用Promise的方法
// then:当Promise状态成功时调用执行
// catch:当Promise状态失败时调用执行
p.then(response => {console.log(response.toString())
}).catch(error => {console.log('出错了')console.error(error)
})
ES7新增特性
1、新增数组方法includes()
Array.prototype.includes() : includes()方法是用来判断数组是否存在某个元素,存在则返回true,不存在则返回false。
includes()和indexOf()两个方法的区别:
includes()方法可以检测NaN数据,但是对于数组元素为空属性的情况,检测不正确,会检测为undefined类型,并且该数 组方法返回的是布尔值,不是元素的索引值。
indexOf() 无法检测NaN类型,而includes()方法可以检测。
[1, 2, 3].includes(-1) // false
[1, 2, 3].includes(1) // true
[1, 2, 3].includes(3, 4) // false
[1, 2, 3].includes(3, 3) // false
[1, 2, NaN].includes(NaN) // true
['foo', 'bar', 'quux'].includes('foo') // true
['foo', 'bar', 'quux'].includes('norf') // falselet list = [1,'a',NaN,null,undefined];console.log(list.indexOf(NaN));//-1
console.log(list.indexOf(1));//0
console.log(list.indexOf(null));//3
console.log(list.indexOf(undefined));//4
console.log(list.indexOf(2));//-1
2、新增取幂运算符(**)
在 ES7 中引入了指数运算符 , 具有与 Math.pow(..)等效的计算结果。使用指数运算符 **,就像 +、- 等操作符一样。
let a = 3;
console.log(a**2);//9,相当于a*a
ES8新增特性
1、async/await
引入了async和await关键字,简化异步操作的编写方式,使代码更易读和理解。
async function asyncFunction() {try {const result = await asyncOperation();console.log(result);} catch (error) {console.error(error);}
}
异步函数返回一个AsyncFunction对象并通过事件循环异步操作。
function delay(ms) {return new Promise(resolve => setTimeout(resolve, ms));
}async function fetchData() {console.log('Start');await delay(5000);console.log('Data fetched');await delay(3000);console.log('Processing complete');
}fetchData(); // 输出: Start -> (等待5秒) -> Data fetched -> (等待3秒) -> Processing complete
2、Object.getOwnPropertyDescriptors()方法
Object.getOwnPropertyDescriptors()函数用来获取一个对象的所有自身属性的描述符,如果没有任何自身属性,则返回空对象。
let myObj = {property1: 'foo',property2: 'bar',property3: 42,property4: () => console.log('prop4')
}Object.getOwnPropertyDescriptors(myObj)/*
{ property1: {…}, property2: {…}, property3: {…}, property4: {…} }property1: {value: "foo", writable: true, enumerable: true, configurable: true}property2: {value: "bar", writable: true, enumerable: true, configurable: true}property3: {value: 42, writable: true, enumerable: true, configurable: true}property4: {value: ƒ, writable: true, enumerable: true, configurable: true}__proto__: Object
*/const obj = {prop1: 42,prop2: 'hello',
};const descriptors = Object.getOwnPropertyDescriptors(obj);
console.log(descriptors.prop1.value); // 输出: 42
console.log(descriptors.prop2.writable); // 输出: true
3、字符串填充方法(String padding)
在 ES8 中 String 新增了两个实例函数 String.prototype.padStart和 String.prototype.padEnd,允许将空字符串或其他字符串添加到原始字符串的开头或结尾。
const str = 'Hello';console.log(str.padStart(10, '-'));
// "-----Hello"console.log(str.padEnd(10, '*'));
// "Hello*****"const str = 'Hello';
const paddedStr = str.padEnd(8, ' World');
console.log(paddedStr); // 输出: 'Hello World'
4、Object.values()
Object.values()是一个与 Object.keys()类似的新函数,但返回的是 Object 自身属性的所有值,不包括继承的值。
const obj = { a: 1, b: 2, c: 3 }
//不使用 Object.values()
const vals = Object.keys(obj).map((key) => obj[key])
console.log(vals) // 1 2 3//使用 Object.values()
const values = Object.values(obj1)
console.log(values) // 1 2 3
5、Object.entries()
Object.entries()函数返回一个给定对象自身可枚举属性的键值对的数组。
//不使用 Object.entries()
Object.keys(obj).forEach((key) => {console.log('key:' + key + ' value:' + obj[key])
})
//key:b value:2//使用 Object.entries()
for (let [key, value] of Object.entries(obj1)) {console.log(`key: ${key} value:${value}`)
}
//key:b value:2
ES9新增特性
以下是JavaScript ES9引入的一些新特性。每个特性都有助于简化开发过程、提高代码效率,并提供更强大的功能。
1、async iterators
ES9 引入异步迭代器(asynchronous iterators), await可以和 for...of循环一起使用,以串行的方式运行异步操作。
//如果在 async/await中使用循环中去调用异步函数,则不会正常执行
async function demo(arr) {for (let i of arr) {await handleDo(i);}
}//ES9
async function demo(arr) {for await (let i of arr) {handleDo(i);}
}
2、Promise.finally()、Promise.catch() (可以省略)
一个 Promise 调用链要么成功到达最后一个 .then(),要么失败触发 .catch()。在某些情况下,你想要在无论 Promise 运行成功还是失败。
finally()方法在Promise被解决或拒绝后,无论如何都会执行。它允许你指定在Promise结束时必须执行的清理逻辑。
function doThing() {thing1().then((res) =>{console.log(res)}).catch((err) => {console.log(err)}).finally(() => {}) // 失败成功都会走这步
}
3、Rest/Spread属性
Rest:对象解构赋值的其余属性。
Spread:对象解构赋值的传播属性。
//rest
const { x, y, ...rest } = { x: 1, y: 2, z: 3, a: 4 };
console.log(x); // 1
console.log(y); // 2
console.log(rest); // { z: 3, a: 4 }//Spread
let info = {fname, lname, ...rest };
info; // { fname: "Hemanth", lname: "HM", location: "Earth", type: "Human" }
4、Object spread syntax(对象扩展语法)
可以使用…语法将一个对象的属性扩展到另一个对象中,并创建一个新对象。
const obj1 = { a: 1, b: 2 };
const obj2 = { c: 3, ...obj1 };
console.log(obj2); // { c: 3, a: 1, b: 2 }
ES10新增特性
1、Array的 flat()方法和 flatMap()方法
这两个方法可以简化多维数组的处理。flat()方法可将多维数组展平为一维数组,而flatMap()方法在展平数组的同时还可以对每个元素执行映射操作。
let arr = ['a', 'b', ['c', 'd']];
let flattened = arr.flat();console.log(flattened); // => ["a", "b", "c", "d"]arr = ['a', , 'b', ['c', 'd']];
flattened = arr.flat();console.log(flattened); // => ["a", "b", "c", "d"]arr = [10, [20, [30]]];console.log(arr.flat()); // => [10, 20, [30]]
console.log(arr.flat(1)); // => [10, 20, [30]]
console.log(arr.flat(2)); // => [10, 20, 30]
console.log(arr.flat(Infinity)); // => [10, 20, 30]
2、String的 trimStart()方法和 trimEnd()方法
这两个方法用于去除字符串开头或结尾的空白字符。它们分别是trim()方法的单独扩展。
const str = " string ";
console.log(str.trimStart()); // => "string "
console.log(str.trimEnd()); // => " string"
3、Object.fromEntries()
这个静态方法允许将键值对列表转换为对象。它接收一个键值对的可迭代对象(如数组)作为参数,并返回一个新的对象。
const myArray = [['one', 1], ['two', 2], ['three', 3]];
const obj = Object.fromEntries(myArray);console.log(obj); // => {one: 1, two: 2, three: 3}