是否使用let或const声明了变量?

2020/10/08 07:21 · javascript ·  · 0评论

我玩ES6已经有一段时间了,我注意到虽然声明的变量var按预期悬挂了...

console.log(typeof name); // undefined
var name = "John";

...用提升声明letconst似乎有一些提升问题的变量

console.log(typeof name); // ReferenceError
let name = "John";

console.log(typeof name); // ReferenceError
const name = "John";

这是否意味着使用letconst声明的变量被吊起?这到底是怎么回事?是否有任何区别let,并const在此问题?

@thefourtheye的正确说法是在声明它们之前不能访问这些变量但是,这要复杂得多。

是否用letconst声明变量这到底是怎么回事?

所有声明varletconstfunctionfunction*class被“悬挂”在JavaScript。这意味着,如果在范围内声明了名称,则在该范围内,标识符将始终引用该特定变量:

x = "global";
// function scope:
(function() {
    x; // not "global"

    var/let/… x;
}());
// block scope (not for `var`s):
{
    x; // not "global"

    let/const/… x;
}

对于函数作用域和块作用域1都是如此

之间的差var/ function/function*声明和let/ const/class声明是初始化在绑定的顶部创建绑定时,

可以使用
undefined或(生成器)函数对前者进行初始化但是,按词法声明的变量保持未初始化状态这意味着ReferenceError您尝试访问它时将引发异常。它只会得到当初始化let/ const/class这就是所谓的(上述)之前声明进行评估,一切时间盲区

x = y = "global";
(function() {
    x; // undefined
    y; // Reference error: y is not defined

    var x = "local";
    let y = "local";
}());

请注意,一条let y;语句用undefinedlikelet y = undefined;初始化变量

时间盲区不是语法的位置,而是时间的变量(范围)的创建和初始化之间。只要未执行该代码(例如,函数体或简单的死代码),就可以在声明上方的代码中引用该变量不是错误,并且如果在初始化之前访问变量,即使访问该变量,也会引发异常。代码位于声明下方(例如,在过早调用的提升函数声明中)。

是否有任何区别let,并const在此问题?

不,就吊装而言,它们的作用相同。它们之间的唯一区别是,const蚂蚁必须并且只能在声明的初始化程序部分中分配(const one = 1;const one;以及以后的重新分配one = 2都无效)。

1:当然,var声明仍然仅在功能级别上起作用

引述的ECMAScript 6(ECMAScript的2015)规范的,letconst声明部分,

实例化包含变量的Lexical Environment时会创建变量,但是在评估变量的LexicalBinding之前,不能以任何方式对其进行访问

因此,要回答你的问题,是的,letconst葫芦,但实际申报在运行时计算之前,你不能访问它们。

ES6介绍Let附带的变量block level scoping直到ES5我们没有了block level scoping,所以在块内声明的变量始终处于hoisted函数级作用域。

基本上Scope是指变量在程序中的可见位置,它决定了允许在何处使用声明的变量。ES5global scope,function scope and try/catch scopeES6我们还使用Let来获得块级作用域。

  • 当您使用var关键字定义变量时,从定义函数起就知道整个函数。
  • 当您使用let语句定义变量时,仅在定义的块中知道该变量

     function doSomething(arr){
         //i is known here but undefined
         //j is not known here
    
         console.log(i);
         console.log(j);
    
         for(var i=0; i<arr.length; i++){
             //i is known here
         }
    
         //i is known here
         //j is not known here
    
         console.log(i);
         console.log(j);
    
         for(let j=0; j<arr.length; j++){
             //j is known here
         }
    
         //i is known here
         //j is not known here
    
         console.log(i);
         console.log(j);
     }
    
     doSomething(["Thalaivar", "Vinoth", "Kabali", "Dinesh"]);
    

如果您运行代码,则可以看到该变量j仅在loop和之前是未知的然而,从定义变量的那一刻起,我们的变量i就为人所知entire function

使用let的另一个好处是,它创建了新的词汇环境,并且绑定了新的值,而不是保留旧的引用。

for(var i=1; i<6; i++){
   setTimeout(function(){
      console.log(i);
   },1000)
}

for(let i=1; i<6; i++){
   setTimeout(function(){
      console.log(i);
   },1000)
}

第一个for循环始终会打印最后一个值,并let创建一个新的作用域并绑定新值以打印us 1, 2, 3, 4, 5

来到constants,它基本上像一样工作let,唯一的区别是它们的值不能改变。在常量中,允许突变,但不允许重新分配。

const foo = {};
foo.bar = 42;
console.log(foo.bar); //works

const name = []
name.push("Vinoth");
console.log(name); //works

const age = 100;
age = 20; //Throws Uncaught TypeError: Assignment to constant variable.

console.log(age);

如果常量引用object,则它将始终引用,object但是其object本身可以更改(如果它是可变的)。如果您想拥有一个不变的东西object,可以使用Object.freeze([])

MDN网站文档中:

在ECMAScript 2015中,let并且const已吊起但未初始化。在变量声明之前引用块中的变量会导致a,ReferenceError因为变量从块的开始一直到声明被处理为止都处于“临时死区”。

console.log(x); // ReferenceError
let x = 3;

在es6中,当我们使用let或const时,必须在使用它们之前声明变量。例如。1-

// this will work
u = 10;
var u;

// this will give an error 
k = 10;
let k;  // ReferenceError: Cannot access 'k' before initialization.

例如。2

// this code works as variable j is declared before it is used.
function doSmth() {
j = 9;
}
let j;
doSmth();
console.log(j); // 9

根据ECMAScript®2021

允许和禁止声明

  • let和const声明定义范围为运行中执行上下文的LexicalEnvironment的变量。
  • 实例化包含其的环境记录时将创建变量,但是在评估变量的LexicalBinding之前,不能以任何方式对其进行访问。
  • 由LexicalBinding与Initializer定义的变量在评估LexicalBinding时而不是在创建变量时被分配其Initializer的AssignmentExpression的值
  • 如果let声明中的LexicalBinding没有初始化程序,则在评估LexicalBinding时,将为变量分配未定义的值

块声明实例化

  • 当评估Block或CaseBlock时,将创建一个新的声明性环境记录,并在环境记录中实例化该块中声明的每个块作用域变量,常量,函数或类的绑定。
  • 不管控制如何离开LexicalEnvironment,总是将其恢复为以前的状态

顶级词汇声明名称

在函数或脚本的顶层,将函数声明视为var声明,而不是词汇声明。

结论

  • let和const被吊起但未初始化。

    在变量声明之前引用块中的变量会导致ReferenceError,因为变量从块的开始一直到声明被处理为止都处于“临时死区”

以下示例清楚地说明了“ let”变量在词法作用域/嵌套词法作用域中的行为。

例子1

var a;
console.log(a); //undefined

console.log(b); //undefined
var b;


let x;
console.log(x); //undefined

console.log(y); // Uncaught ReferenceError: y is not defined
let y; 

变量“ y”给出了referenceError,这并不意味着它没有被提升。实例化包含环境时创建该变量。但是由于它处于无法访问的“临时死区”,可能无法访问它。

例子2

let mylet = 'my value';
 
(function() {
  //let mylet;
  console.log(mylet); // "my value"
  mylet = 'local value';
})();

例子3

let mylet = 'my value';
 
(function() {
  let mylet;   
  console.log(mylet); // undefined
  mylet = 'local value';
})();

在示例3中,函数内部新声明的“ mylet”变量在log语句之前没有初始化程序,因此值为“ undefined”。

资源

ECMA
MDN

本文地址:http://javascript.askforanswer.com/shifoushiyonglethuoconstshengminglebianliang.html
文章标签: ,   ,   ,   ,  
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!