ECMAScript 与JavaScript 的区别 及ECMAScript 新特性

简单来说,两者的区别:ECMAScript 是语言规范,JavaScript 是编程语言

ECMAScript 的新特性:不同的时间有不同的新特性加入,比如ES5、ES6/ES2015、ES7/ES2016、ES2018等等,常被大家熟知的ES6是一个重要的更新,所以这个比较重要。

目录

一、ECMAScript 与JavaScript 的区别

二、ECMAScript的新特性

1.引入新变量——let、const

2.面向对象编程——class

3.模板字符串

4.解构语法

5.箭头函数

6.生成器 generator

7.异步处理

8.Reflect

9.BigInt 

总结


一、ECMAScript 与JavaScript 的区别

我之前在学习ES6时,看过一个网站,这个网站里的学习内容很丰富,从JS的制造者开始讲,将ECMA的起源讲清楚,这里也很直白地解释两者的关系,分享链接如下:

阮一峰 ECMAScript 6 (ES6) 标准入门教程 第三版

两者的区别,总计一句话就是我开头说的那样。

稍微详细来说:

ECMAScript

  • ECMAScript 是由 Ecma International 组织标准化的脚本语言规范。它定义了脚本语言的语法、类型、对象模型等核心特性。

  • ECMAScript 是 JavaScript 的标准化基础,也就是说 JavaScript 是 ECMAScript 的一种实现。每当 ECMAScript 标准更新时,JavaScript 就会添加这些新的特性。

  • ECMAScript 的版本——ES6 是一个重要的更新,带来了很多新的特性,如箭头函数、模板字符串、let 和 const 关键字、类和模块等。

JavaScript:

  • JavaScript 是一种编程语言,最初由 Netscape 公司在 1995 年开发,用于在浏览器中添加动态内容。
  • JavaScript 是 ECMAScript 标准的最广泛的实现之一。除了遵循 ECMAScript 标准,JavaScript 还添加了一些浏览器相关的特性和 API,比如 DOM 操作、事件处理等。
  • JavaScript 是在 Web 开发中使用最广泛的编程语言,几乎所有现代浏览器都支持它。

总结:ECMAScript 是一套语言规范,而 JavaScript 是 ECMAScript 规范的实现。ECMAScript 定义了这门语言的基础,而 JavaScript 则在此基础上扩展并添加了一些浏览器特性。 


二、ECMAScript的新特性

这里只对特性进行简单总结,也算是我自己学习的查漏补缺。

1.引入新变量——let、const

总所周知,ES6之前只有var,所以引入了let const。为什么引入?从使用var来定义变量存在的问题的角度来讲——块级作用域、不可重复声明、暂时性死区:

1.变量提升(Hoisting):被提升到函数或全局作用域 的顶部,但不会提升赋值。也就是说,变量可以在声 明之前被访问,但值为 undefined。

2.作用域:var 定义的变量是函数作用域或全局作用 域,不是块作用域。也就是说,即使在块级作用域内 (例如,if 或 for 语句内)声明的变量,依然可以在块外访问,引入了let const能避免不必要的变量污染和冲突(前者是块级作用域的局部变量,后者是块级作用域只读常量)

3.重复声明:使用 var 可以重复声明同一个变量,不会报错,这可能导致意外的错误和难以调试的问题。

相比之下,let 和 const 引入了块级作用域和更严格的 变量管理,避免了上述问题:块级作用域、不可重复声明、let 和 const 在声明之前不可访问,避免了变量提升带来的问题——暂时性死区(Temporal Dead Zone),也更安全、简洁和规范。

let const 实现原理:

let(const差不多同理)的底层实现涉及 JavaScript 引擎在编译和执行代码时如何处理变量声明和作用域。在 JavaScript 引擎中,每一个变量都会被封装在一个称为“变量对象”的容器中,这个对象包含了所有当前上下文中定义的变量与函数。虽然具体的实现细节因引擎而异,但基本的过程可以概括为以下几个步骤:

1. 编译阶段

在 JavaScript 代码执行之前,JavaScript 引擎会先进行编译。这个阶段主要包括:

  • 创建作用域:引擎会为每个作用域(全局作用域、函数作用域、块级作用域)创建一个“环境记录”(Environment Record),用来存储变量和函数声明。
  • 识别变量声明:在这一步,let 声明的变量会被添加到其所在的块级作用域中,但不会被初始化。这与 var 不同,var 声明的变量在编译阶段就被提升并初始化为 undefined
  • 暂时性死区(TDZ):在作用域内,从变量声明开始到变量被初始化的这段时间,被称为“暂时性死区”(Temporal Dead Zone)。在 TDZ 内,访问 let 声明的变量会导致运行时错误(ReferenceError)。

2. 执行阶段

在执行阶段,JavaScript 引擎会逐行执行代码:

  • 初始化变量:当执行到 let 声明的那一行时,引擎会为该变量分配内存,并根据赋值操作进行初始化。此时,变量离开了暂时性死区,可以正常访问了。
  • 块级作用域let 声明的变量在其所在的块级作用域内有效,不会影响到块外。每次进入新的块作用域时,都会创建新的环境记录,let 声明的变量存储在这个新的环境中。

此外,letvar 的区别

  • var 在编译阶段会被提升并初始化为 undefined,而 let 只会被提升但不会初始化
  • let 声明的变量在 TDZ 内无法被访问,而 var 声明的变量即使在声明前访问,值也只是 undefined
  • let 遵循块级作用域,而 var 仅遵循函数作用域。

2.面向对象编程——class

这里也推荐去阅读这个文档,更清晰:
Class 的基本语法

简单来说,JavaScript 的类最终也是一种函数, class 语法只是语法糖——简化了原型继承 的写法。类的构造函数 (constructor)用于初始化对象的 属性,类的方法定义在构造函数的 prototype 上,并且不可枚举。尽管语法上更为简洁,但本质上仍然 基于原型继承机制。并且使用 class 关键字创建的类会被编译成一个函数,因此其底层原理与函数有一些相似之处。

关键字:类、静态方法、属性、继承、可枚举——这些听起来是不是很像JAVA?这也是class引入原因之一

此处,插播一条:for of 和 for in 的区别——主要在,可枚举属性

for...of 和 for...in 是 JavaScript 中的两种循环语法,用于遍历对象或集合。它们有不同的用途和行为。

for...in 用途:for...in 用于遍历对象的可枚举属性。它不仅可以遍 历对象的自有属性,还可以遍历继承自原型链的属性。 行为:遍历对象的键(属性名)。 不会遍历 Symbol 属性。 遍历顺序不一定按插入顺序,特别是在不同的 JavaScript 引擎中,可能会有所不同。 不适用于 Array、Map、Set 等集合类型,它主要用于对 象。

for...of 用途:for...of 用于遍历可迭代对象(iterable objects), 如 Array、String、Map、Set 等。它不会遍历对象的属 性。 行为:遍历可迭代对象的值。 只能用于可迭代对象。普通对象(如字面量对象)不能使 用 for...of。 遍历顺序按对象的实际顺序。

3.模板字符串

ES6 引入的一种字符串表示方式,提供了多行字符串、内插表达式和标签模板等功能。

底层原理

  • 在编译阶段,JavaScript 引擎会识别模板字符串中的插值表达式 ${} 并将其拆分为静态字符串插值部分
  • 在执行阶段,插值表达式内的代码会被求值,求值结果将被转换为字符串,并插入到模板字符串中相应的位置。

 上面是普通的模板字符串的原理,还有一种高级的模板字符串——标签模板

允许你在模板字符串之前加上一个函数,用来处理模板字符串和插值表达式:

function tag(strings, ...values) {
  console.log(strings); // ["Hello, ", "!"]
  console.log(values);  // ["Alice"]
}

const name = "Alice";
tag`Hello, ${name}!`;

 底层原理

  • 在编译阶段,模板字符串会被分解为一个字符串数组(包含静态部分)和一个值数组(包含插值表达式的求值结果)。
  • 标签函数 tag 在执行阶段被调用,接收这些数组作为参数,开发者可以在函数中自定义处理逻辑。

4.解构语法

JavaScript 的解构是 ES6 中新增的一个语法特性,它可以将数组或对象中的元素提取出来并赋值给变量。解构语法使得对数组和对象的操作更加灵活和便捷。

关键词:数组解构、对象解构、嵌套解构、混合解构、函数参数解构——如果以上都能理解,就看下面的原理吧。

底层原理

解构赋值的底层原理是基于对象和数组的迭代与属性访问:

  • 对于数组解构,JavaScript 引擎通过数组索引依次将值赋给变量。
  • 对于对象解构,引擎根据属性名称匹配对象中的属性,然后将对应的值赋给变量。

如果在解构过程中找不到对应的值,且没有提供默认值,则变量被赋值为 undefined

前提是,如果右边(要解构的对象)是一个具有 Iterator 接口的对象,如果为无法解构的值(如 undefined 或 null),则抛出 TypeError。

5.箭头函数

JavaScript中的箭头函数新增的一种函数定义方式,它可以创建一个函数并赋值给变量,使用箭头语法'=>'。在箭头函数中,this 关键字的作用域与它周围代码作用域相同,因而有时也被称为“词法作用域函数”。

箭头函数的原理是基于JavaScript中的闭包、this和参数作用域。在箭头函数中,this关键字始终指向函数所在上下文的this指针,而不是所在作用域的this指针——这个不好理解的话,建议去看一个专题,仔细研究一下实例就能理解了。

虽然箭头函数在许多应用场景中表现出极大的优势,但在某些情况下还是不能正常使用。常见的限制场景如下:

  • 不能作为构造函数——不能使用new关键字来调用箭头函数来创建一个新对象。
  • 在箭头函数中,函数的参数为指定的参数,没有额外的 arguments 对象。如果需要使用 arguments 参数,必须使用常规的函数语法。

  • 对于箭头函数,它的 this 指针指向词法作用域中的this值,无法通过call()、apply()方法来修改。

6.生成器 generator

生成器(Generator)是 ES6 引入的一种可以在执行过程中暂停和恢复的函数。它们使用特殊的语法来定义,并提供了一个可以按需生成值的迭代器。这使得生成器特别适用于处理惰性计算、异步编程和复杂迭代等场景。
生成器与 yield 配合可以简化异步代码的书写,形成类似同步的代码风格(如与 Promiseasync/await 结合)。著名案例co Promise + generator 实现异步编程

7.异步处理

都知道callback是一种异步编程模式,通过回调函数的方式实现,但是有回调地狱。于是 ES6提供的一种处理异步操作的机制——Promise ,用于解决 callback 回调函数嵌套过多的问题,但是并没有很好地解决,因为有then,catch,写多了还是不美观简洁,当然它功能比callback,更加强大和易用。

于是 ES8 的新特性——async/await出现了 ,它是基于 Promise 的一种异步编程方式,它可以使异步代码看起来像同步代码(看起来像是链式调用),语法简单易懂,可读性较高。async 是用于定义一个异步函数,await 用于等待一个异步操作完成。async 函数返回一个 Promise 对象,await 关键字只能在 async 函数中使用。

8.Reflect

是 ES6 引入的一个全局对象,它提供了用于操作 JavaScript 对象的通用方法。它包含了一组与对象操作相关的静态方法,这些方法与 Object 对象中的方法类似,但 Reflect 中的方法设计得更一致,并且通常直接反映底层的 JavaScript 引擎操作,并且好像有看过,说是Object 对象中的方法,Reflect 都有,甚至还要慢慢替换它。

Reflect API 实现了对象的反射、代理等功能,它为我们提供了一些强大而便捷的工具,使得我们可以在运行时动态地查看、检查和修改对象的属性和行为。Reflect 反射在 JavaScript 中的应用非常广泛,可以用于类似响应式编程、面向对象编程等各种场景。

著名案例,vue3的响应式原理:

基于ProxyReflect 实现的,Reflect 在 Vue 3 的响应式系统中起到了关键作用,主要用于拦截和执行对象属性的操作,可以拦截到数组索引的修改、长度变化等操作。这与 Vue 2 使用的 Object.defineProperty 方法有很大的不同,它只能拦截对象的属性修改,对于数组的索引操作无法直接侦听,只能通过特定的方法(如 pushsplice)来触发更新

9.BigInt 

JavaScript Number 类型的限制——2^53 - 1,在某些场景下,数不够用,所以在 ES10 中引入的一种新类型,它可以用来表示任意大的整数,不受 JavaScript 中 Number 类型的 2^53 - 1 限制。

算上这个,现在JS的变量类型,一共可以分为以下几种:

  • 原始类型(7种):numberstringbooleanundefinednullsymbolbigint
  • 对象类型(若干):objectarrayfunctiondateregexpmapsetweakmapweaksetproxyreflect

对了还有,在 ES2021中引入了一种新特性,允许在数字字面量中使用下划线 (_) 作为分隔符,以提高数字的可读性。这并不是 ES6 中的特性,而是更晚一些版本的 ECMAScript 中加入的。


总结

这里主要对ES6以来的一些新特性进行了总结和记录,查漏补缺吧。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值