function add(x = y, y = 1) {
return x + y;
}
add(); // ReferenceError
在上面的代码中,就是如此,给函数赋默认值时,使用后面的值赋值给前面的 x,而这时候 y 还没有定义,所以会报错。
不允许重复声明
var 变量是允许进行重复声明的,但是 let 变量是不允许的。
来,上代码。
var a = 10;
var a = 20;
console.log(a); // 20
var b = 10;
let b = 20;
console.log(b); // 20
let c = 10;
var c = 20;
// 报错
let d = 10;
let d = 20;
// 报错
const 命令
const 命令 声明一个只读的常量。一旦声明,常量的值就不能改变
基本用法
const PI = 3.14159
console.log(PI); // 3.14159
PI = 3.14 // TypeError: Assignment to constant variable
const 声明时,必须立即进行初始化,不能进行赋值。
cosnt PI; // 报错 SyntaxError
const 只声明,不赋值就会报错。
const 作用域与 let 相同:只在声明所在的块级作用域内有效。
{
const PI = 3.14159
}
console.log(PI); //Uncaught ReferenceError
Let 和 const 命令
let 命令
简单实用
ES6 中新增了
let
命令,用来声明变量。使用方式同var
命令,但是let
命令只在所在的代码块内有效。在上面的使用案例中,我们可以看出
let
命令只在代码块中生效,而在代码块以外使用则无效。for循环中使用
我们来看看在
for
循环中使用var
命令.下面这段代码,打印出来的会是什么呢?可以跑一下代码,看一下控制台。
好了,你会发现,所有的打印都是
5
,为什么呢?是因为var
命令是在全局范围内有效,所以全局只有一个变量i
,每一次循环,变量i
的值都会发生改变,所以当你打印是,打印的就是全局的i
,也就是经过多次变化赋值的5
。上面代码中,我在外面打印了一下
i
,来证明var
定义的是一个全局变量。来,让我们将
var
改成let
,现在打印的结果又是什么呢?当然,我想很多人都猜到了结果,就是
0 1 2 3 4
,那么这里又是为什么呢?let
变量只在所在的代码块内有效,在子代码块中依然有效。在上述循环中i
只在本轮循环内有效,所以每一次循环的i
其实都是一个新定义的变量,所以会输出当前i
的值,每次循环对应输出。当然,这里可能会出现一个问题,每轮的变量都是一个新变量,那它是怎么知道上一轮循环的值的?稍做解释:JS 引擎(v8)内部会记住上一轮循环的值,初始化本轮的变量时,就在上一轮循环的基础上进行计算。
上面我们说,
let
命令在子代码块中也有效,可以从for
循环上来看,()
内部其实就是一个父级作用域,而{}
内部就是一个单独的子作用域。不存在变量提升
变量提升,即变量可以在声明之前使用,值为
undefined
,var
命令存在,而let
命令并没有变量提升,照样,我们来看看使用的案例。可以在控制台中跑一下这段代码,进行尝试。你会发现,
a
变量进行了变量提升,而b
变量没有发生,这表明了在声明之前使用,变量b
是不存在的。暂时性死区
代码块中,使用
let
命令声明变量之前,该变量都是不可用的。在外部有一个全局变量
x
,但是在内部使用let
声明了一个x
,于是内部的x
绑定了这个代码块,不受部影响。但是在内部,声明变量之前的这个区域就是暂时性死区,我们来从下面的代码来看。
暂时性死区的存在,也就意味着
typeof
的操作会变的不安全,在没有声明变量时,使用typeof
并不会报错,返回一个undefined
,然而因为暂时性死区,会使得typeof
报错ReferenceError
。在函数默认值中也存在暂时性死区,而且会不容易发现。
在上面的代码中,就是如此,给函数赋默认值时,使用后面的值赋值给前面的
x
,而这时候y
还没有定义,所以会报错。不允许重复声明
var
变量是允许进行重复声明的,但是let
变量是不允许的。来,上代码。
const 命令
const
命令 声明一个只读的常量。一旦声明,常量的值就不能改变基本用法
const
声明时,必须立即进行初始化,不能进行赋值。const
只声明,不赋值就会报错。const
作用域与let
相同:只在声明所在的块级作用域内有效。const
命令也不存在变量提升,但是存在暂时性死区,只能在声明后使用。与
let
一样,不可进行重复声明。本质
首先,我们来看一个对象的例子:
由上面可以看出,常量
obj
储存的是一个地址,这个地址指向一个对象。不可变的只是这个地址,即不能把 obj 指向另一个地址,但对象本身是可变的,所以依然可以添加新属性。再来看一个数组的例子:
同对象,常量
arr
是一个数组,这个数组本身是可写的,但是如果将另一个数组赋值给arr
,就会报错。由此可见
const
保证的 实际上并不是变量的值不改动,而是变量指向的那个内存地址所保存的数据不得改动。const
只能保证这个指针式固定的,至于他指向的数据结构是不是可变的,就完全不能控制了。