let

  • Revision slug: Web/JavaScript/Reference/Statements/let
  • Revision title: let
  • Revision id: 417059
  • Created:
  • Creator: Sheppy
  • Is current revision? No
  • Comment +tag (NeedsBrowserCompatibility)Moved From JavaScript/Reference/Statements/let to Web/JavaScript/Reference/Statements/let

Revision Content

{{js_minversion_header("1.7")}}

Summary

Declares a block scope local variable, optionally initializing it to a value.

Syntax

let definition:

let var1 [= value1] [, var2 [= value2]] [, ..., varN [= valueN]];

let expression:

let (var1 [= value1] [, var2 [= value2]] [, ..., varN [= valueN]]) expression;

let statement:

let (var1 [= value1] [, var2 [= value2]] [, ..., varN [= valueN]]) statement;

Parameters

Parameter Description
var1, var2, …, varN Variable name. It can be any legal identifier.
value1, value2, …, valueN Initial value of the variable. It can be any legal expression.
expression Any legal expression.
statement Any legal statement.

Description

let allows you to declare variables, limiting its scope to the block, statement, or expression on which it is used. This is unlike the var keyword, which defines a variable globally, or locally to an entire function regardless of block scope.

Block scoping

let declared variables are hoisted to the beginning of the enclosing block.

Redeclaration of the same variable in the same block scope raises a TypeError.

if (x) {
  let foo;
  let foo; // TypeError thrown.
}

However, function bodies do not have this limitation!

function do_something() {
  let foo;
  let foo; // This works fine.
}
Warning: ECMAScript 6 drafts (as of April, 2012) make this behavior illegal. That means that future versions of JavaScript will likely be consistent and raise a TypeError. if you do this, so you should avoid this practice!

You may encounter errors in switch statements because there is only one underlying block.

switch (x) {
  case 0:
    let foo;
    break;
    
  case 1:
    let foo; // TypeError for redeclaration.
    break;
}

Examples

A let expression limits the scope of the declared variable to only that expression.

var a = 5;
let(a = 6) alert(a); // 6
alert(a); // 5

Used inside a block, let limits the variable's scope to that block. Note the difference between var whose scope is inside the function where it is declared

var a = 5;
var b = 10;

if (a === 5) {
  let a = 4; // The scope is inside the if-block
  var b = 1; // The scope is inside the function

  console.log(a);  // 4
  console.log(b);  // 1
} 

console.log(a); // 5
console.log(b); // 1

You can use the let keyword to bind variables locally in the scope of loops instead of using a global variable (defined using var) for that.

for (let i = 0; i<10; i++) {
  alert(i); // 1, 2, 3, 4 ... 9
}

alert(i); // i is not defined

When you are dealing with constructors you can use the let statement in order to create a private interface without using closures:

/*\
|*|
|*|  :: A public and reusable API for constructors ... ::
|*|
\*/

let (
  switchScope = function (oOwner, fConstructor) {
    return oOwner && oOwner.constructor === fConstructor ? oOwner : this;
  }
) {
  function buildIndoors (fConstructor) {
    const oPrivate = new fConstructor(this);
    this.getScope = oPrivate.getScope = switchScope.bind(this, oPrivate);
    return oPrivate;
  }
}

/*\
|*|
|*|  :: Use of the *let* statement in order to create a private interface without closures... ::
|*|
\*/

let (

  /* "Secrets" is the constructor of the private interface */

  Secrets = function Secrets (oPublic /* (the public interface) */) {
    /* setting a private property... */
    this.password = Math.floor(Math.random() * 1e16).toString(36);
    /* you can also store the public interface into a private property... */
    /* this.publicInterface = oPublic; */
    alert("I\'m getting a public property from a private constructor...: somePublicProperty: " + oPublic.somePublicProperty);
  }

) {

  /* "User" is the constructor of the public interface */

  function User (sNick) {
    /* setting a public property... */
    this.somePublicProperty = "Hello World!";
    const oPrivate = this.createScope(Secrets); /* (the private interface) */
    /* setting a public property... */
    this.user = sNick;
    alert("I\'m getting a private property from a public constructor...: password: " + oPrivate.password);
  }

  User.prototype.somePublicMethod = function () {
    const oPrivate = this.getScope(Secrets); /* (the private interface) */
    alert("I\'m getting a public property from a public method...: user: " + this.user);
    alert("I\'m getting a private property from a public method...: password: " + oPrivate.password);
    oPrivate.somePrivateMethod();
  };

  Secrets.prototype.somePrivateMethod = function () {
    const oPublic = this.getScope(); /* (the public interface) */
    alert("I\'m getting a public property from a private method...: user: " + oPublic.user);
    alert("I\'m getting a private property from a private method...: password: " + this.password);
  };

  /* ...creating a mutual access... */

  User.prototype.createScope = buildIndoors;
}

/* out of the *let* statement you have not access to the private interface! */

const johnSmith = new User("John Smith");
johnSmith.somePublicMethod();

See also

Revision Source

<div>
  {{js_minversion_header("1.7")}}</div>
<h2 id="Summary" name="Summary">Summary</h2>
<p>Declares a block scope local variable, optionally initializing it to a value.</p>
<h2 id="Syntax" name="Syntax">Syntax</h2>
<p><code>let</code> definition:</p>
<pre class="syntaxbox">
let var1 [= value1] [, var2 [= value2]] [, ..., varN [= valueN]];</pre>
<p><code>let</code> expression:</p>
<pre class="syntaxbox">
let (var1 [= value1] [, var2 [= value2]] [, ..., varN [= valueN]]) expression;</pre>
<p><code>let</code> statement:</p>
<pre class="syntaxbox">
let (var1 [= value1] [, var2 [= value2]] [, ..., varN [= valueN]]) statement;</pre>
<h3 id="Parameters" name="Parameters">Parameters</h3>
<table class="standard-table">
  <thead>
    <tr>
      <th scope="col">Parameter</th>
      <th scope="col">Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code>var1</code>, <code>var2</code>, …, <code>varN</code></td>
      <td>Variable name. It can be any legal identifier.</td>
    </tr>
    <tr>
      <td><code>value1</code>, <code>value2</code>, …, <code>valueN</code></td>
      <td>Initial value of the variable. It can be any legal expression.</td>
    </tr>
    <tr>
      <td><code>expression</code></td>
      <td>Any legal <a href="/en-US/docs/JavaScript/Guide/Expressions_and_Operators#Expressions" title="JavaScript/Guide/Expressions and Operators#Expressions">expression</a>.</td>
    </tr>
    <tr>
      <td><code>statement</code></td>
      <td>Any legal <a href="/en-US/docs/JavaScript/Reference/Statements" title="JavaScript/Reference/Statements">statement</a>.</td>
    </tr>
  </tbody>
</table>
<h2 id="Description" name="Description">Description</h2>
<p><code>let</code> allows you to declare variables, limiting its scope to the block, statement, or expression on which it is used. This is unlike the <a href="/en-US/docs/JavaScript/Reference/Statements/var" title="JavaScript/Reference/Statements/var"><code>var</code></a> keyword, which defines a variable globally, or locally to an entire function regardless of block scope.</p>
<h2 id="Block_scoping" name="Block_scoping">Block scoping</h2>
<p><code>let</code> declared variables are hoisted to the beginning of the enclosing block.</p>
<p>Redeclaration of the same variable in the same block scope raises a <code><a href="/en-US/docs/JavaScript/Reference/Global_Objects/TypeError" title="TypeError">TypeError</a></code>.</p>
<pre class="brush: js">
if (x) {
  let foo;
  let foo; // TypeError thrown.
}</pre>
<p>However, function bodies do not have this limitation!</p>
<pre class="brush: js">
function do_something() {
  let foo;
  let foo; // This works fine.
}</pre>
<div class="warning">
  <strong>Warning:</strong> ECMAScript 6 drafts (as of April, 2012) make this behavior illegal. That means that future versions of JavaScript will likely be consistent and raise a <code><a href="/en-US/docs/JavaScript/Reference/Global_Objects/TypeError" title="TypeError">TypeError</a></code>. if you do this, so you should avoid this practice!</div>
<p>You may encounter errors in <a href="/en-US/docs/JavaScript/Reference/Statements/switch" title="switch"><code>switch</code></a> statements because there is only one underlying block.</p>
<pre class="brush: js">
switch (x) {
  case 0:
    let foo;
    break;
    
  case 1:
    let foo; // TypeError for redeclaration.
    break;
}</pre>
<h2 id="Examples" name="Examples">Examples</h2>
<p>A <em>let expression</em> limits the scope of the declared variable to only that expression.</p>
<pre class="brush: js">
var a = 5;
let(a = 6) alert(a); // 6
alert(a); // 5</pre>
<p>Used inside a block, <em>let</em> limits the variable's scope to that block. Note the difference between <em>var </em>whose scope is inside the function where it is declared</p>
<pre class="brush: js">
var a = 5;
var b = 10;

if (a === 5) {
  let a = 4; // The scope is inside the if-block
  var b = 1; // The scope is inside the function

  console.log(a);  // 4
  console.log(b);  // 1
} 

console.log(a); // 5
console.log(b); // 1</pre>
<p>You can use the <em>let</em> keyword to bind variables locally in the scope of loops instead of using a global variable (defined using <em>var</em>) for that.</p>
<pre class="brush: js">
for (let i = 0; i&lt;10; i++) {
  alert(i); // 1, 2, 3, 4 ... 9
}

alert(i); // i is not defined</pre>
<p>When you are dealing with constructors you can use the <code>let</code> statement in order to create a <em>private interface</em> without using closures:</p>
<pre class="brush: js">
/*\
|*|
|*|&nbsp; :: A public and reusable API for constructors ... ::
|*|
\*/

let (
&nbsp; switchScope = function (oOwner, fConstructor) {
&nbsp;&nbsp;&nbsp; return oOwner &amp;&amp; oOwner.constructor === fConstructor ? oOwner : this;
&nbsp; }
) {
&nbsp; function buildIndoors (fConstructor) {
&nbsp;&nbsp;&nbsp; const oPrivate = new fConstructor(this);
&nbsp;&nbsp;&nbsp; this.getScope = oPrivate.getScope = switchScope.bind(this, oPrivate);
&nbsp;&nbsp;&nbsp; return oPrivate;
&nbsp; }
}

/*\
|*|
|*|&nbsp; :: Use of the *let* statement in order to create a private interface without closures... ::
|*|
\*/

let (

&nbsp; /* "Secrets" is the constructor of the private interface */

&nbsp; Secrets = function Secrets (oPublic /* (the public interface) */) {
&nbsp;&nbsp;&nbsp; /* setting a private property... */
&nbsp;&nbsp;&nbsp; this.password = Math.floor(Math.random() * 1e16).toString(36);
&nbsp;&nbsp;&nbsp; /* you can also store the public interface into a private property... */
&nbsp;&nbsp;&nbsp; /* this.publicInterface = oPublic; */
&nbsp;&nbsp;&nbsp; alert("I\'m getting a public property from a private constructor...: somePublicProperty: " + oPublic.somePublicProperty);
&nbsp; }

) {

&nbsp; /* "User" is the constructor of the public interface */

&nbsp; function User (sNick) {
&nbsp;&nbsp;&nbsp; /* setting a public property... */
&nbsp;&nbsp;&nbsp; this.somePublicProperty = "Hello World!";
&nbsp;&nbsp;&nbsp; const oPrivate = this.createScope(Secrets); /* (the private interface) */
&nbsp;&nbsp;&nbsp; /* setting a public property... */
&nbsp;&nbsp;&nbsp; this.user = sNick;
&nbsp;&nbsp;&nbsp; alert("I\'m getting a private property from a public constructor...: password: " + oPrivate.password);
&nbsp; }

&nbsp; User.prototype.somePublicMethod = function () {
&nbsp;&nbsp;&nbsp; const oPrivate = this.getScope(Secrets); /* (the private interface) */
&nbsp;&nbsp;&nbsp; alert("I\'m getting a public property from a public method...: user: " + this.user);
&nbsp;&nbsp;&nbsp; alert("I\'m getting a private property from a public method...: password: " + oPrivate.password);
&nbsp;&nbsp;&nbsp; oPrivate.somePrivateMethod();
&nbsp; };

&nbsp; Secrets.prototype.somePrivateMethod = function () {
&nbsp;&nbsp;&nbsp; const oPublic = this.getScope(); /* (the public interface) */
&nbsp;&nbsp;&nbsp; alert("I\'m getting a public property from a private method...: user: " + oPublic.user);
&nbsp;&nbsp;&nbsp; alert("I\'m getting a private property from a private method...: password: " + this.password);
&nbsp; };

&nbsp; /* ...creating a mutual access... */

&nbsp; User.prototype.createScope = buildIndoors;
}

/* out of the *let* statement you have not access to the private interface! */

const johnSmith = new User("John Smith");
johnSmith.somePublicMethod();</pre>
<h2 id="See_also" name="See_also">See also</h2>
<ul>
  <li><a href="/en-US/docs/JavaScript/Reference/Statements/var" title="JavaScript/Reference/Statements/var"><code>var</code></a></li>
  <li><a href="/en-US/docs/JavaScript/Reference/Statements/const" title="JavaScript/Reference/Statements/const"><code>const</code></a></li>
  <li><a href="/en-US/docs/JavaScript/New_in_JavaScript/1.7#Block_scope_with_let_(Merge_into_let_Statement)" title="JavaScript/New in JavaScript/1.7#Block scope with let (Merge into let Statement)">New in JavaScript 1.7</a></li>
</ul>
Revert to this revision