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

Posted 易函123

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了var/let/const块级作用域TDZ变量提升相关的知识,希望对你有一定的参考价值。

概览

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、变量提升

以上是关于var/let/const块级作用域TDZ变量提升的主要内容,如果未能解决你的问题,请参考以下文章

var,let,const的区别和用法

关于var let const ~

var let const的区别

js-varletconst的区别

var let const 区别

var let const 的区别