let
不属于顶层对象window
使用var和不使用var声明的变量一样吗?
==> 是不一样的
使用var声明『当前作用域内』的变量(如果是在函数中声明,那它就是个局部变量)
而不使用var,相当于在顶层对象window上定义了个属性,并对这个属性进行赋值
delete只能删除对象的属性,不能删除变量
通过这点就可以验证上面的结论
var a = 5
console.log(a)
delete a
console.log(a)
b = 6
console.log(b)
delete b
console.log(b)
运行结果,说明b已经被删除
JS遗留的问题
JS在设计的时候将顶层对象的属性同全局变量进行了挂钩
var a = 5
console.log(a)
console.log(window.a)
b = 6
console.log(b)
console.log(window.b)
这就会造成一个问题:如果项目中声明了很多的全局变量,都被挂在window下面
导致window这个对象越来越大
就造成了污染全局变量
let - 解决了污染全局变量的问题
let a = 5
console.log(a)
window.log(window.a)
注意
webapck会对src下面的代码进行打包编译, 对static下面的代码不会打包编译,而是原封不动的移过去 webpack有模块机制,它将src下面的文件进行打包编译的时候,会自动处理一些存在的问题(如:可能会用es6的逻辑处理es5代码中存在的问题)
不允许重复声明
var
var a = 5
var a = 6
console.log(a)
let
let a = 5
let a = 6
console.log(a)
这样的好处就是在多人合作时,避免相同变量名的重复声明和对值的覆盖
不存在变量提升
var
console.log(a)
var a = 5
// 相当于
var a
console.log(a)
a = 5
let
console.log(a)
let a = 5
暂时性死区
只要块级作用域内存在 let 命令,它所声明的变量就绑定在了这个区域,不再受外部的影响
在代码块内,使用 let 命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”
// 不报错
var a = 5
if(true){
a = 6
var a
}
// 报错
var a = 5
if(true){
a = 6
let a
}
块级作用域
用var定义的变量,没有块级作用域
只有全局作用域和函数作用域
let 具有块级作用域(在大括号内),作用域内声明的变量只能在块级作用域内访问
let实际上为 JavaScript 新增了块级作用域
{
let a = 5
}
console.log(a) // undefined
a 变量是在代码块 {} 中使用 let 定义的,它的作用域是这个代码块内部,外部无法访问
没有块级作用域(一个大括号)导致的问题
var
// var中声明的变量i是全局变量i
for(var i = 0;i < 3;i++){
console.log('循环内:' + i)
}
console.log('循环外:' + i)
// 相当于
var i
for(i = 0;i < 3;i++){
console.log('循环内:' + i)
}
console.log('循环外:' + i)
这样其实不安全,本来是想让变量i,只能在大括号中访问,结果在大括号外面也能访问
let
for(let i = 0;i < 3;i++){
console.log('循环内:' + i)
}
console.log('循环外:' + i)
再看个例子: es6中的块级作用域必须有“{}”
// 不报错
if(true) var a = 5
// 报错: 词法声明不能出现在单个语句的上下文中
if(true) let a = 5
// 应改为
if(true){
let a = 5
}
面试题
for (var i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i)
})
}
// 3、3、3
setTimeout是异步的操作,而for循环是同步的、一瞬间完成的,当setTimeout执行的时候,for循环已经结束了
解决方法1: 闭包: 在函数内访问函数外的变量,那么这个变量连同这个函数就构成了闭包
for (var i = 0; i < 3; i++) {
(function(j) {
setTimeout(function() {
console.log(j)
})
})(i)
}
解决方法2: 使用let
for (let i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i)
})
}
const
定义常量
ES5中定义常量
// 在window上定义属性PI
Object.defineProperty(window,'PI',{
value: 3.14,
writable: false
})
console.log(PI)
PI = 6
console.log(PI)
const定义的变量不允许进行重新赋值
内存在存JS的对象时,实际上是在栈内存中存的对象的地址,而堆内存中存的才是对象本身
const定义的基本数据类型不能被重新赋值,而引用数据类型可以被重新赋值
1.const定义基本数据类型
const a=5
a = 6
2.const定义引用数据类型
const obj = {
name:'lee',
age: 18
}
console.log(obj);
obj.名族 = '汉'
console.log(obj);
const 声明常量和赋值须同时进行
const a
a =5
数组也是一样
const规定定义的变量的值不得改动,这个值包括基本数据类型的值,也包括引用数据类型中内存地址的值不得改变
如何让对象或者数组这种引用数据类型也不被改变呢?
Object.freeze(obj) // 只能传普通的对象,不能传数组
注意
Object.freeze() 只是浅层冻结,只会对外层的对象进行冻结,并不会对嵌套的子对象冻结。
如果也想冻结嵌套的子对象就要手动的再写一次,如:Object.freeze(obj.child)
其他的特性和let相同