前言
我们将开启一个全新系列--ES6(ECMAScript 6)新特性! 开启我们的征程吧!
随着ECMAScript 6(ES6)的推出,JavaScript迎来了一系列强大的语言特性,其中let
和const
关键字以及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
我们发现这样也会直接抛出一个错误,以上例子都能让我们发现let
和const
的两个特性!
let
声明的变量只在声明的代码块当中发挥作用!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引入了 let
和 const
关键字,并改变了这一行为。使用 let
或 const
声明的变量不再成为顶层对象的属性。
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,内容安全策略),那么 eval
、new Function
这些方法可能会受到限制,无法正常使用。
综合来看,使用 this
关键字虽然是一种通用的获取顶层对象的方法,但在不同环境和使用场景下存在一些细微的差异和限制。
好啦,我们今天的学习就到这里为止啦!接下来,我都会更新一系列有关ES6的文章,大家感兴趣可以关注我哦~
如果你有任何想法和意见欢迎大家评论留言哦~
点个小小的赞鼓励支持一下吧!!!