关于javascript:varletconst块级作用域TDZ变量提升

5次阅读

共计 2986 个字符,预计需要花费 8 分钟才能阅读完成。

概览

ES6 新增了两个定义变量的关键字:letconst,它们简直取代了 ES5 定义变量的形式:varlet是新的 var,const 简略的常量申明。

function f() {
  {
    let x;
    {
      // okay, block scoped name
      const x = "sneaky";
      // error, const
      x = "foo";
    }
    // error, already declared in block
    let x = "inner";
  }
}

letconst实现块级作用域

let,const创立的变量都是 块级作用域:它们只存在突围它们的最深代码块中。

function func() {if (true) {
        let tmp = 123;
        // const tmp = 123;
    }
    console.log(tmp); // ReferenceError: tmp is not defined
}
console.log(tmp);// ReferenceError: tmp is not defined

相比之下,var申明的是函数域。

function func() {if (true) {var tmp = 123;}
    console.log(tmp); // 123
}
func()
console.log(tmp); // tmp is not defined

面试题:循环中定时器闭包

for(var i = 0; i < 5; i++) {setTimeout(() => {console.log(i) //5, 5, 5, 5, 5
  }, 0)
}
console.log(i) //5 i 跳出循环体净化内部函数

// 将 var 改成 let 之后
for(let i = 0; i < 5; i++) {setTimeout(() => {console.log(i) // 0,1,2,3,4
  }, 0)
}
console.log(i)//i is not defined i 无奈净化内部函数

在 for 循环中应用 var 申明的循环变量,会跳出循环体净化以后的函数。

letconst暂时性死区(temporal dead zone)

let,const申明的变量领有 暂时性死区 :当进入它的作用域,它不能被拜访(获取或设置)直到执行达到申明。
简略形容:

if (true) {
  // 这块区域是 TDZ
  console.log(a) // Uncaught ReferenceError: Cannot access 'a' before initialization
  let a = 1
  // const a = 1
}
if (true) { // enter new scope, TDZ starts
    // Uninitialized binding for `tmp` is created

    tmp = 'abc'; // ReferenceError
    console.log(tmp); // ReferenceError

    let tmp; // TDZ ends, `tmp` is initialized with `undefined`
    console.log(tmp); // undefined

    tmp = 123;
    console.log(tmp); // 123
}

上面示例将演示死区(dead zone)是真正短暂工夫的(基于工夫)和不受空间条件限度(基于地位)

if (true) { // enter new scope, TDZ starts
    const func = function () {console.log(myVar); // OK!
    };

    // Here we are within the TDZ and
    // accessing `myVar` would cause a `ReferenceError`

    let myVar = 3; // TDZ ends
    func(); // called outside TDZ}

var变量晋升

JavaScript 中,咱们通常说的作用域是函数作用域,应用 var 申明的变量,无论是在代码的哪个中央申明的,都会晋升到以后作用域的最顶部,这种行为叫做 变量晋升(Hoisting)

上面代码,演示了函数的变量晋升:

{ // Enter a new scope

    console.log(foo()); // hello, due to hoisting
    function foo() {return 'hello';}
}

也就是说,如果在函数外部申明的变量,都会被晋升到函数结尾,而在全局的申明,就会晋升到全局作用域的顶部。

function test() {console.log('1:', a) //undefined
    if (false) {var a = 1}
    console.log('3:', a) //undefined
}

test()

理论执行时,下面的代码中的变量 a 会晋升到函数顶部申明,即便 if 语句的条件是 false,也一样不影响 a 的晋升。

function test() {
    var a
    // a 申明没有赋值
    console.log('1:', a) //undefined
    if (false) {a = 1}
    // a 申明没有赋值
    console.log('3:', a) //undefined
}

在嵌套函数的状况,变量只会晋升到最近一个函数的顶部,而不会到内部函数。

// b 晋升到函数 a 顶部,但不会晋升到函数 test。function test() {function a() {if (false) {var b = 2}
    }
    console.log('b:', b)
}

test() //b is not defined

let不容许反复申明

let不容许在雷同作用域内,反复申明同一个变量。

// 报错
function func() {
  let a = 10;
  var a = 1;
}

// 报错
function func() {
  let a = 10;
  let a = 1;
}

因而在函数外部不能从新申明函数

function func(arg) {let arg;}
func() // 报错 Identifier 'arg' has already been declared

function func(arg) {
  {let arg;}
}
func() // 不报错

const命令

个别应用场景:

const start = 'hi all';

const getName = () => {return 'jelly';};

const conf = {fav: 'Coding'};

// 模板
const msg = `${start}, my name is ${getName()}, ${conf.fav} is my favourite`;

你可能不晓得的事:

// 1. 与引号混用
const wantToSay = `I'm a"tbfed"`;

// 2. 反对多行文本
const slogan = 
`
I have a dream today!
`;

// 比拟适宜写 HTML
const resultTpl = 
`
  <section>
    <div>...</div>
  </section>
`;

varletconst有什么区别

  • 相同点 var,let,const 申明的变量,是不能被 delete 的;
  • 区别

变量晋升 var 申明的变量存在变量晋升,即变量能够在申明之前调用,值为 undefined;
let,const不存在变量晋升,即它们申明的变量肯定要在申明后应用,否则会报错。

暂时性死区 var 不存在暂时性死区;letconst存在暂时性死区,只有等申明变量后,才能够获取和应用该变量。

反复申明 var 容许反复申明;latconst在同一作用域不容许反复申明。

批改申明的变量 varlet能够批改申明的变量;const申明一个只读常量,一旦申明,常量的值就不能扭转。

var/let/const、块级作用域、TDZ、变量晋升

正文完
 0