首页 > JavaScript > let”和“var”有什么区别?

let”和“var”有什么区别?

上一篇 下一篇

网友问题:
ECMAScript 6 引入了该语句。
let

我听说它被描述为局部变量,但我仍然不太确定它的行为与 var 关键字有何不同。

有什么区别?何时应使用代替 ?letvar

分割线

网友回答:

let也可用于避免闭包问题。它绑定新值,而不是保留旧引用,如以下示例所示。

for(var i=1; i<6; i++) {
  $("#div" + i).click(function () { console.log(i); });
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>Clicking on each number will log to console:</p> 
<div id="div1">1</div>
<div id="div2">2</div>
<div id="div3">3</div>
<div id="div4">4</div>
<div id="div5">5</div>

上面的代码演示了一个经典的 JavaScript 闭包问题。对变量的引用存储在单击处理程序闭包中,而不是 的实际值中。ii

每个单击处理程序都将引用相同的对象,因为只有一个计数器对象可容纳 6,因此每次单击都会获得 <> 个。

一般解决方法是将其包装在匿名函数中并作为参数传递。现在也可以通过使用下面的代码所示来避免此类问题。iletvar

(在Chrome和Firefox 50中测试)

for(let i=1; i<6; i++) {
  $("#div" + i).click(function () { console.log(i); });
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>Clicking on each number will log to console:</p> 
<div id="div1">1</div>
<div id="div2">2</div>
<div id="div3">3</div>
<div id="div4">4</div>
<div id="div5">5</div>

分割线

网友回答:

范围规则

主要区别在于范围规则。关键字声明的变量的作用域为直接函数体(因此为函数作用域),而变量的作用域为由(因此称为块作用域)表示的直接封闭块。varlet{ }

function run() {
  var foo = "Foo";
  let bar = "Bar";

  console.log(foo, bar); // Foo Bar

  {
    var moo = "Mooo"
    let baz = "Bazz";
    console.log(moo, baz); // Mooo Bazz
  }

  console.log(moo); // Mooo
  console.log(baz); // ReferenceError
}

run();

关键字被引入语言的原因是函数作用域令人困惑,并且是JavaScript中错误的主要来源之一。let

看看另一个堆栈溢出问题中的例子:

var funcs = [];
// let's create 3 functions
for (var i = 0; i < 3; i++) {
  // and store them in funcs
  funcs[i] = function() {
    // each should log its value.
    console.log("My value: " + i);
  };
}
for (var j = 0; j < 3; j++) {
  // and now let's run each one to see
  funcs[j]();
}

My value: 3每次调用时都输出到控制台,因为匿名函数绑定到同一变量。funcs[j]();

人们必须立即创建调用的函数来从循环中捕获正确的值,但这也很麻烦。

提升

虽然用关键字声明的变量被提升(在代码运行之前初始化),这意味着即使在声明它们之前,它们也可以在它们的封闭范围内访问:varundefined

function run() {
  console.log(foo); // undefined
  var foo = "Foo";
  console.log(foo); // Foo
}

run();

let在计算变量的定义之前,不会初始化变量。在初始化之前访问它们会产生 .该变量被称为从块开始到初始化被处理的“时间死区”。ReferenceError

function checkHoisting() {
  console.log(foo); // ReferenceError
  let foo = "Foo";
  console.log(foo); // Foo
}

checkHoisting();

创建全局对象属性

在顶层,与 不同,不会在全局对象上创建属性:letvar

var foo = "Foo";  // globally scoped
let bar = "Bar"; // not allowed to be globally scoped

console.log(window.foo); // Foo
console.log(window.bar); // undefined

重新声明

在严格模式下,将允许您在同一作用域中重新声明相同的变量,同时引发语法错误。varlet

'use strict';
var foo = "foo1";
var foo = "foo2"; // No problem, 'foo1' is replaced with 'foo2'.

let bar = "bar1"; 
let bar = "bar2"; // SyntaxError: Identifier 'bar' has already been declared

分割线

网友回答:

和 有什么区别?letvar

  • 使用语句定义的变量从函数的开头开始,在整个定义它的函数中都是已知的。var(*)
  • 使用语句定义的变量仅在定义它的块中已知,从定义它的那一刻起。let(**)

若要了解差异,请考虑以下代码:

// i IS NOT known here
// j IS NOT known here
// k IS known here, but undefined
// l IS NOT known here

function loop(arr) {
    // i IS known here, but undefined
    // j IS NOT known here
    // k IS known here, but has a value only the second time loop is called
    // l IS NOT known here

    for( var i = 0; i < arr.length; i++ ) {
        // i IS known here, and has a value
        // j IS NOT known here
        // k IS known here, but has a value only the second time loop is called
        // l IS NOT known here
    };

    // i IS known here, and has a value
    // j IS NOT known here
    // k IS known here, but has a value only the second time loop is called
    // l IS NOT known here

    for( let j = 0; j < arr.length; j++ ) {
        // i IS known here, and has a value
        // j IS known here, and has a value
        // k IS known here, but has a value only the second time loop is called
        // l IS NOT known here
    };

    // i IS known here, and has a value
    // j IS NOT known here
    // k IS known here, but has a value only the second time loop is called
    // l IS NOT known here
}

loop([1,2,3,4]);

for( var k = 0; k < arr.length; k++ ) {
    // i IS NOT known here
    // j IS NOT known here
    // k IS known here, and has a value
    // l IS NOT known here
};

for( let l = 0; l < arr.length; l++ ) {
    // i IS NOT known here
    // j IS NOT known here
    // k IS known here, and has a value
    // l IS known here, and has a value
};

loop([1,2,3,4]);

// i IS NOT known here
// j IS NOT known here
// k IS known here, and has a value
// l IS NOT known here

在这里,我们可以看到我们的变量只在第一个 for 循环中是已知的,而不是在之前和之后。然而,我们的变量在整个函数中是已知的。ji

此外,请考虑块范围的变量在声明之前是未知的,因为它们没有被提升。您也不允许在同一块中重新声明相同的块范围变量。这使得块范围的变量比全局或功能范围的变量更不容易出错,全局或功能范围的变量是吊装的,在多个声明的情况下不会产生任何错误。


今天使用安全吗?let

有些人会争辩说,将来我们只会使用 let 语句,而 var 语句将变得过时。JavaScript 大师 Kyle Simpson 写了一篇非常详细的文章,解释了为什么他认为情况并非如此。

然而,今天,情况绝对不是这样。事实上,我们实际上需要问问自己使用该语句是否安全。该问题的答案取决于您的环境:let

如果您正在编写服务器端 JavaScript 代码 (Node.js),则可以安全地使用该语句。let

如果您正在编写客户端 JavaScript 代码并使用基于浏览器的转译器(如 Traceur 或 babel-standalone),则可以安全地使用该语句,但是您的代码在性能方面可能不是最佳的。let

如果您正在编写客户端 JavaScript 代码并使用基于 Node 的转译器(如 traceur shell 脚本或 Babel),则可以安全地使用该语句。而且,由于您的浏览器只会知道转译的代码,因此性能缺陷应该受到限制。let

如果您正在编写客户端 JavaScript 代码并且不使用转译器,则需要考虑浏览器支持。

仍然有一些浏览器根本不支持:let


如何跟踪浏览器支持

有关在您阅读此答案时哪些浏览器支持该声明的最新概述,请参阅此“我可以使用”页面。let


(*) 全局和功能范围的变量可以在声明之前进行初始化和使用,因为 JavaScript 变量是被提升的。这意味着声明始终移动到范围的顶部。

(**)块范围的变量不被提升

模板简介:该模板名称为【let”和“var”有什么区别?】,大小是暂无信息,文档格式为.编程语言,推荐使用Sublime/Dreamweaver/HBuilder打开,作品中的图片,文字等数据均可修改,图片请在作品中选中图片替换即可,文字修改直接点击文字修改即可,您也可以新增或修改作品中的内容,该模板来自用户分享,如有侵权行为请联系网站客服处理。欢迎来懒人模板【JavaScript】栏目查找您需要的精美模板。

相关搜索
  • 下载密码 lanrenmb
  • 下载次数 752次
  • 使用软件 Sublime/Dreamweaver/HBuilder
  • 文件格式 编程语言
  • 文件大小 暂无信息
  • 上传时间 02-08
  • 作者 网友投稿
  • 肖像权 人物画像及字体仅供参考
栏目分类 更多 >
热门推荐 更多 >
微信模板 自适应 html5 微信文章 企业网站 微信图片 微信公众平台 微信素材 单页式简历模板 响应式
您可能会喜欢的其他模板