[ES6新特性]什么时候了ES6你还不学?顶层对象,const,let

前言

我们将开启一个全新系列--ES6(ECMAScript 6)新特性! 开启我们的征程吧!

随着ECMAScript 6(ES6)的推出,JavaScript迎来了一系列强大的语言特性,其中letconst关键字以及globalThis对象为我们提供了更加灵活和可靠的编程工具。这些特性的引入旨在提高代码的可读性、可维护性,并解决一些在之前版本中存在的问题。让我们一起学习了解这些功能。

正文

let命令

在ES6中新增了let命令,方便我们声明对象,用法大体上与var类似,但又有不同!我们使用let声明的变量有点类似c语言(包括其他强)中声明变量的方式,比如:要先声明再使用,只能在let所在的代码块运行等等。

我们来看这个案例:

js 复制代码
{
    let a = 2;
}
console.log(a);//输出:ReferenceError: a is not defined
console.log(b);//输出:ReferenceError: Cannot access 'b' before initialization
let b = 10;

在这一段代码里面,我们把变量a单独放在一个代码块当中,在这个代码块之外对他进行调用,我们发现这样会直接抛出一个错误

同样的,我们先使用再let声明变量b我们发现这样也会直接抛出一个错误,以上例子都能让我们发现letconst的两个特性!

  1. let声明的变量只在声明的代码块当中发挥作用!
  2. let声明的变量必须先声明,再使用!

同时,如果我们在for循环当中又会发现一些新的东西!

我们看看案例:

js 复制代码
for(var i = 0;i<5;i++){
    setTimeout(()=>{
        console.log(i);
    },1000)
}
输出:
5
5
5
5
5

在这个案例当中,我们声明了一个循环,在这个循环体当中,我们用了一个setTimeout定时器,规定一秒后输出for循环中的i值。

其实,在没有学习相关知识之前,我们第一时间都会认为应该输出0,1,2,3,4这样的一个结果!其实不然,这与var存在的声明提升相关!相当于,这个i变量是一个全局的变量,在最后一次结束循环,i的值被赋成了5,最后,所有定时器输出的i就都获取这个i最后的赋值,也就是5

如果,我们想要实现我们所期待的值又该怎么操作呢?这个时候,let就应该发挥它的作用了!我们来看看这个案例!

js 复制代码
for(let i = 0;i<5;i++){
    setTimeout(()=>{
        console.log(i);
    },1000)
}
输出:
0
1
2
3
4

为什么把变量的声明方式改为let就会实现我们期待的效果呢?

因为i是由let声明的,每次声明的i都只会在本轮循环中生效!每次循环i其实都是一个新的变量!那我们的定时器,又是如何保存获取它要输出的i值呢?就相当于,每次循环都会给循环体开辟一个块级空间,每次循环都会有一个块级空间,而每个块级空间都是不同的,而每个空间都有它对应的i值。

let声明的变量不存在提升!

上面的案例,我们提到了var的声明提升问题,即变量使用var声明的时候,可以先使用后声明,值为undefined,其实这很不符合我们人类的正常思维!所以我的官方大大为了解决这种奇怪的现象为我们添加了let

js 复制代码
console.log(a);//输出:undefined
var a = 1
console.log(b);//输出:ReferenceError: Cannot access 'b' before initialization
let b =2

也就是说,我们用let声明的对象不可以通过先使用后声明,这样我们的代码会直接抛出一个错误!

块级作用域

let关键字引入了块级作用域的概念,即变量只在声明它的块内部可见。在ES6之前,使用var声明的变量在整个函数内部都是可见的,这可能导致一些意料之外的情况发生

js 复制代码
function fn() {
  if (true) {
    let a = 10;
    console.log(a); // 10 a在这个块级作用域内可见
  }
  console.log(a); // ReferenceError: a is not defined
}

let的块级作用域有效地解决了变量泄漏和不同作用域之间的命名冲突问题,使得代码更加清晰和可维护性增强!

不可以重复声明

let关键字声明的对象不允许重复声明!

js 复制代码
let a = 1
let a = 2//编译器会直接报错!不允许重新声明块范围变量a
暂时性死区

只要在块级作用域存在let声明的变量,那么它所声明的变量就"绑定"在这个区域,不再受外部的影响!

在JavaScript中,let的设计者为了避免意外的行为,让变量在声明语句之前是不可访问的。这个时间段就叫做"暂时性死区",也就是变量似乎被卡在这个区域里,没法被访问。

js 复制代码
let b = 99;
if (true) {
  console.log(b); // 这里也不行!会抛出ReferenceError: Cannot access 'b' before initialization
  let b = 100;
}

这里b明明在if语句之前就定义了,为什么还是不行呢?因为在console.log(b)这里,let b的声明已经在这个作用域中存在了,但是它在console.log之前就被引用了,所以就掉入了"死区"。

其实关于死区还有很多知识,大家可以学习一下阮一峰老师的《ECMAScript 6 入门》的相关知识点!

const命令

在ES6中引入了一种新的声明方式const,我们可以用它来声明一个只读变量!也就是常量,一旦声明,就不能再更改了!

我们来看看这个案例:

js 复制代码
const a = 4
a = 5
console.log(a);//输出:TypeError: Assignment to constant variable.

上述案例说明:常量一旦声明不能修改,因为,常量一旦声明就不能修改,所以我们一旦声明就要里面初始化!

也就是说:

js 复制代码
const str//我们不初始化的话,编译器会立马报错:'const' declaration must be initialized

所以我们在使用const的时候一定呀对其赋值!

当然,const作用域也和let相同,只在声明的块级的作用域发挥作用!

js 复制代码
{
  const a = 5
}
console.log(a);//输出:ReferenceError: a is not defined

const命令声明的常量也不会提升,同样会存在暂时性死区,只能先声明后使用!同样的,const也不能重复声明,我们一旦重复声明,我们的编译器就会直接报错!

const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指向实际数据的指针,const只能保证这个指针是固定的(即总是指向另一个固定的地址),至于它指向的数据结构是不是可变的,就完全不能控制了。

我们可以来看看这个案例:

js 复制代码
const obj = {}
obj.name ="小明"
console.log(obj);//输出:{ name: '小明' }

在这个案例当中,obj是指向的是一个地址,也就是说我们用const声明的变量obj的地址是不可更改的,也就是说,我们不能让obj指向别的地址,但是对象本身还是可以更改的,我们可以为它添加属于自己的属性!

顶层对象

在JavaScript中,顶层对象是全局对象,具体的名称取决于执行环境。在浏览器中,顶层对象是 window 对象;在Node.js环境中,顶层对象是 global 对象。

ES6之前,使用 var 关键字声明的变量会成为顶层对象的属性。这意味着,如果你在浏览器环境中使用 var 声明一个变量,它就会成为 window 对象的属性。

javascript 复制代码
var x = 42;
console.log(window.x); // 42(在浏览器环境中)

这种行为存在一些问题,因为它使得全局命名空间变得拥挤,容易产生命名冲突。

ES6引入了 letconst 关键字,并改变了这一行为。使用 letconst 声明的变量不再成为顶层对象的属性。

javascript 复制代码
let y = 42;
console.log(window.y); // undefined(在浏览器环境中)

这样的改变有助于减少全局命名空间的污染,使得代码更加模块化和可维护。如果你希望将变量显式地添加到顶层对象的属性中,可以使用 window(在浏览器环境中)或 global(在Node.js环境中)。

javascript 复制代码
window.z = 42;
console.log(window.z); // 42(在浏览器环境中)

globalThis对象

在JavaScript中,存在一个顶层对象,它提供了全局环境,也就是代码运行的全局作用域。然而,这个顶层对象在不同的实现中并不统一。

在浏览器中,顶层对象是 window,但在 Node 和 Web Worker 中却没有 window。在浏览器和 Web Worker 中,self 也指向顶层对象,但在 Node 环境中却没有 self。而在 Node 中,顶层对象是 global,但其他环境并不支持它。

为了在不同环境中都能获取到顶层对象,通常使用 this 关键字。然而,这种方法也有一些局限性。

在JavaScript中,为了在各种环境中都能获取到顶层对象,通常会使用 this 关键字。然而,这种方法存在一些局限性。

在全局环境中,this 会返回顶层对象,这通常符合预期。但是,在Node.js模块中,this 返回的是当前模块,而在ES6模块中,this 返回的是 undefined,这就引入了一些不一致性。

当函数作为对象的方法运行时,函数内部的 this 会指向该对象。但是,如果函数作为独立的函数运行,而不是对象的方法,this 会指向顶层对象。需要注意的是,在严格模式下,这种情况下的 this 会返回 undefined,引入了一些额外的复杂性。

无论是在严格模式还是普通模式下,通过 new Function('return this')() 这种方式总是可以返回全局对象。但是需要注意的是,如果浏览器启用了 CSP(Content Security Policy,内容安全策略),那么 evalnew Function 这些方法可能会受到限制,无法正常使用。

综合来看,使用 this 关键字虽然是一种通用的获取顶层对象的方法,但在不同环境和使用场景下存在一些细微的差异和限制。

好啦,我们今天的学习就到这里为止啦!接下来,我都会更新一系列有关ES6的文章,大家感兴趣可以关注我哦~

如果你有任何想法和意见欢迎大家评论留言哦~

点个小小的赞鼓励支持一下吧!!!

引用参考:ES6 入门教程 - ECMAScript 6入门 (ruanyifeng.com)

个人gitee库:MycodeSpace: 主要应用的仓库,记录学习coding中的点点滴滴 (gitee.com)

相关推荐
下雪天的夏风2 分钟前
TS - tsconfig.json 和 tsconfig.node.json 的关系,如何在TS 中使用 JS 不报错
前端·javascript·typescript
diygwcom13 分钟前
electron-updater实现electron全量版本更新
前端·javascript·electron
volodyan16 分钟前
electron react离线使用monaco-editor
javascript·react.js·electron
^^为欢几何^^25 分钟前
lodash中_.difference如何过滤数组
javascript·数据结构·算法
Hello-Mr.Wang30 分钟前
vue3中开发引导页的方法
开发语言·前端·javascript
程序员凡尘1 小时前
完美解决 Array 方法 (map/filter/reduce) 不按预期工作 的正确解决方法,亲测有效!!!
前端·javascript·vue.js
编程零零七4 小时前
Python数据分析工具(三):pymssql的用法
开发语言·前端·数据库·python·oracle·数据分析·pymssql
北岛寒沫5 小时前
JavaScript(JS)学习笔记 1(简单介绍 注释和输入输出语句 变量 数据类型 运算符 流程控制 数组)
javascript·笔记·学习
everyStudy5 小时前
JavaScript如何判断输入的是空格
开发语言·javascript·ecmascript
(⊙o⊙)~哦6 小时前
JavaScript substring() 方法
前端