let 和 const 命令

let

  • 基本用法
    • let只在代码块中有效
// let声明的变量只在代码块中有效
{
    let i = 1;
    var j = 2;
}
console.log(i)  // 报错
console.log(j)  // 2

for(let i = 0; i < 10; i++){}
i // i is not defined
for(var i = 0; i < 10; i++){}
i // 10
    • for循环中的经典使用
var a = []
// var定义的i全局有效
for(var i = 0; i < 10; i++){
    a[i] = function(){
        console.log(i)
    }
}
a[5]()    //10
// 循环生成10个子块级作用域,相互独立
for(let i = 0; i < 10; i++){
    a[i] = function(){
        console.log(i)
    }
}
a[7]()    // 7
// 或者使用闭包
var array  = []
for(var i = 0; i < 10; i++){
    // 块级作用域的出现,取代了匿名立即执行函数
    (function(i){
        array[i] = function(){
            console.log(i)
        }
    })(i)
}
array[7]()  // 7
// 父作用域与子作用域相互独立
// 父作用域
for(let i = 0; i < 3; i++){
    // 子作用域,相互独立
    let i = 'abc'
    console.log(i)   // abc(3次)
}
  • 不允许变量提升
console.log(bar)      // undefined
var bar = 2

console.log(bar)      // Uncaught ReferenceError: bar is not defined
let bar = 2
const bar = 111
  • 暂时性死区(在代码块内,let声明变量之前,该变量不可用,不会受外部的影响)
tmp = '222'
if(true){
    tmp = 'abc'
    console.log(tmp)     // Uncaught ReferenceError: Cannot access 'tmp' before initialization

    let tmp
    console.log(tmp)     // undefined

    tmp = 123
    console.log(tmp)     // 123
}
    • 因为暂时性死区的原因,typeof不是一个百分百安全的操作,因为申明之前不可用
    typeof x                // 报错 Uncaught ReferenceError: a is not defined
    let x
    
    // 直接对未声明的变量使用typeof反而不会报错
    typeof a           // undefined
    
    // 参数x等于参数y,此时y还没有声明,属于“死区“
    function bar(x = y, y = 2){
        return [x,y]
    }
    bar()     // VM1986:1 Uncaught ReferenceError: Cannot access 'y' before initialization              
    
    function bar(x = 2, y = x){
        return [x,y]
    }
    bar()   // [2, 2]
    
    var x = x;  // 不报错
    // 变量未声明就使用
    let x = x;  // Uncaught ReferenceError: x is not defined
    
  • 不允许重复声明
// 不报错
function foo(){
    var a = 10;
    var a = 20;
}

// Uncaught SyntaxError: Identifier 'a' has already been declared
function foo(){
    var a = 10;
    let a = 20;
}
// Uncaught SyntaxError: Identifier 'a' has already been declared
function foo(){
    let a = 10;
    let a = 20;
}
// Uncaught SyntaxError: Identifier 'a' has already been declared
function foo () {
    let a = 10
    var a = 20
}
// 因此函数内部不能重复声明
function fn(arg){
    let arg
}
fn()        // Uncaught SyntaxError: Identifier 'arg' has already been declared

function fn(arg){
    {
        let arg
    }
}
fn()        //不报错
为什么使用let替代var

因为let有块级作用域的限制,var没有,容易造成变量污染

  • 场景一:内层变量覆盖外层变量
var tmp = new Date()
function f() {
    console.log(tmp)
    if (false) {
        var tmp = 'Hello world'   // var tmp 变量提升覆盖外层变量
    }
}
f()  // undefined
  • 场景二:用来计数的循环变量泄漏为全局变量
var s = 'hello'
for (var i = 0; i < s.length; i++) {
    console.log(s[i])
}
console.log(i)  // 5
let只能出现在当前作用域的顶层
if (true) let x = 1   // Uncaught SyntaxError: Lexical declaration cannot appear in a single-statement context

// 严格模式下,函数只能申明在当前作用域的顶层
'use strict'
if (true) function f() {}    // Uncaught SyntaxError: In strict mode code, functions can only be declared at top level or inside a block.

'use strict'
if (true) {    function f() {} } // undefined
顶层对象的属性

顶层对象:在浏览器指的是window,在Node指的是global。而window实体含义是浏览器的窗口对象,顶层对象也有一个实体含义,混为一谈不合适

  • ES5中,顶层对象的属性和全局变量是一样的,这也是javascript语言设计最大的败笔之一
  • ES6中,作出改变:var和function申明的全局变量,依旧是顶层对象的属性,let、const、class 申明的全局变量不属于顶层对象的属性,全局变量逐步与顶层对象的属性脱钩
var a = 111
window.a  // 111

let b = 222
window.b. // undefined
globalThis 对象

JavaScript 语言存在一个顶层对象,它提供全局环境(即全局作用域),所有代码都运行在这个环境,使用this 可以拿到这个顶层对象,但是不同环境的this 不同

  • 全局环境中
    • this 返回顶层对象
    • Node.js中,this 是当前模块
    • ES6中,this 返回的是 undefined
  • 函数里的this
    • 如果函数不是作为对象的方法运行,单纯作为函数运行,this 会指向顶层对象
    • 如果是严格模式下,this 返回 undefined

综上所述,很难找到一种方法,在所有情况下,都取到顶层对象,下面是两种可以勉强使用的方法

(typeof window !== 'undefined'
 ? window
 : (typeof process === 'object' &&
 typeof require === 'function' &&
 typeof global === 'object')
 ? global
 : this);
var getGlobal = function () {
 if (typeof self !== 'undefined') { return self; }
 if (typeof window !== 'undefined') { return window; }
 if (typeof global !== 'undefined') { return global; }
 throw new Error('unable to locate global object');
};

ES2020中,globalThis可以在任何环境中拿到顶层对象,指向全局环境下的this

const:指变量指向的内存地址的值不可修改,如果定义的是复合类型只是指针不可修改,不能保证对象的结构改变

  • const声明常量,值不可修改
const aaa = 111
aaa = 222
// Uncaught TypeError: Assignment to constant variable
  • 声明时必须立即初始化,否则报错
const bbb
bbb = 111
// Uncaught SyntaxError: Missing initializer in const declaration
  • 和let一样,不可重复声明
let bar = 100
const bar = 200
// VM1276:2 Uncaught SyntaxError: Identifier 'bar' has already been declared
  • 和let一样,存在块级作用域,未声明前不可用
if(true){
    const eee = 666
}
console.log(eee)
// Uncaught ReferenceError: eee is not defined

console.log(ddd)
const ddd = 100
// Uncaught ReferenceError: Cannot access 'ddd' before initialization

results matching ""

    No results matching ""