Heim  >  Artikel  >  Web-Frontend  >  Detaillierte Erläuterung der Verwendung des Befehls let in js ES6

Detaillierte Erläuterung der Verwendung des Befehls let in js ES6

零下一度
零下一度Original
2017-07-09 09:34:561605Durchsuche

ES6 fügt einen neuen let-Befehl zum Deklarieren von Variablen hinzu. Seine Verwendung ähnelt var, aber die deklarierte Variable ist nur innerhalb des Codeblocks gültig, in dem sich der let-Befehl befindet

letBefehl

Grundlegende Verwendung

Neu in ES6 Der let-Befehl wird zum Deklarieren von Variablen verwendet. Seine Verwendung ähnelt der von var, die deklarierte Variable ist jedoch nur innerhalb des Codeblocks gültig, in dem sich der let-Befehl befindet.

{
 let a = 10;
 var b = 1;
}

a // ReferenceError: a is not defined.
b // 1

Der obige Code befindet sich im Codeblock und deklariert zwei Variablen mit let bzw. var. Dann werden diese beiden Variablen außerhalb des Codeblocks aufgerufen. Infolgedessen meldet die von let deklarierte Variable einen Fehler und die von var deklarierte Variable gibt den korrekten Wert zurück. Dies zeigt, dass die von let deklarierte Variable nur in dem Codeblock gültig ist, in dem sie sich befindet.

Für den Schleifenzähler ist die Verwendung des let-Befehls sehr gut geeignet.

for (let i = 0; i < 10; i++) {}

console.log(i);
//ReferenceError: i is not defined

Im obigen Code ist der Zähler i nur innerhalb des Körpers der for-Schleife gültig und es wird ein Fehler gemeldet, wenn außerhalb der Schleife darauf verwiesen wird.

Wenn der folgende Code var verwendet, ist die endgültige Ausgabe 10.

var a = [];
for (var i = 0; i < 10; i++) {
 a[i] = function () {
  console.log(i);
 };
}
a[6](); // 10

Im obigen Code wird die Variable i von var deklariert und ist im globalen Bereich gültig. Bei jeder Schleife überschreibt der neue i-Wert den alten Wert, sodass die endgültige Ausgabe der Wert von i in der letzten Runde ist.

Wenn let verwendet wird, ist die deklarierte Variable nur innerhalb des Bereichs auf Blockebene gültig und die endgültige Ausgabe ist 6.

var a = [];
for (let i = 0; i < 10; i++) {
 a[i] = function () {
  console.log(i);
 };
}
a[6](); // 6

Im obigen Code wird die Variable i durch let deklariert. Das aktuelle i ist nur in diesem Zyklus gültig, daher ist i in jedem Zyklus tatsächlich eine neue Variable, sodass die endgültige Ausgabe 6 ist.

Keine variable Förderung

let leidet nicht unter „variabler Förderung“ wie var. Daher müssen Variablen nach der Deklaration verwendet werden, andernfalls wird ein Fehler gemeldet.

console.log(foo); // 输出undefined
console.log(bar); // 报错ReferenceError

var foo = 2;
let bar = 2;

Im obigen Code wird die Variable foo mit dem Befehl var deklariert und die Variablenheraufstufung erfolgt. Das heißt, wenn das Skript ausgeführt wird, ist die Variable foo bereits vorhanden, hat aber keinen Wert. daher wird undefiniert ausgegeben. Die Variable bar wird mit dem let-Befehl deklariert und es findet keine Variablenheraufstufung statt. Dies bedeutet, dass die Variable bar vor der Deklaration nicht vorhanden ist und bei Verwendung ein Fehler ausgegeben wird.

Temporäre Totzone

Solange der let-Befehl im Bereich auf Blockebene vorhanden ist, sind die von ihm deklarierten Variablen in diesem Bereich „verbindlich“ und werden nicht verwendet nicht mehr durch den let-Befehl beeinflusst werden.

var tmp = 123;

if (true) {
 tmp = &#39;abc&#39;; // ReferenceError
 let tmp;
}

Im obigen Code gibt es eine globale Variable tmp, aber let deklariert eine lokale Variable tmp im Bereich auf Blockebene, was dazu führt, dass letzterer diesen Bereich auf Blockebene bindet, also bevor let deklariert Wenn Sie der Variablen tmp einen Wert zuweisen, wird ein Fehler gemeldet.

ES6 legt klar fest, dass, wenn ein Block let- und const-Befehle enthält, die von diesen Befehlen in diesem Block deklarierten Variablen von Anfang an einen geschlossenen Bereich bilden. Jede Verwendung dieser Variablen vor der Deklaration führt zu einem Fehler.

Kurz gesagt, innerhalb des Codeblocks ist die Variable erst verfügbar, wenn sie mit dem let-Befehl deklariert wird. Grammatisch wird dies als „temporäre Totzone“ (TDZ) bezeichnet.

if (true) {
 // TDZ开始
 tmp = &#39;abc&#39;; // ReferenceError
 console.log(tmp); // ReferenceError

 let tmp; // TDZ结束
 console.log(tmp); // undefined

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

Bevor der let-Befehl im obigen Code die Variable tmp deklariert, gehört sie zur „toten Zone“ der Variablen tmp.

Die „vorübergehende Totzone“ bedeutet auch, dass es sich bei diesem Typ nicht mehr um einen 100 % sicheren Betrieb handelt.

typeof x; // ReferenceError
let x;

Im obigen Code wird die Variable x mit dem let-Befehl deklariert, sodass sie vor der Deklaration zur „toten Zone“ von x gehört Fehler wird gemeldet. Daher löst typeof beim Ausführen einen ReferenceError aus.

Zum Vergleich: Wenn eine Variable überhaupt nicht deklariert ist, wird bei Verwendung von typeof kein Fehler gemeldet.

typeof undeclared_variable // "undefined"

Im obigen Code ist undeclared_variable ein Variablenname, der nicht existiert, und das Ergebnis ist „undefiniert“. Daher war typeofoperator vor let, 100 % sicher und meldete niemals einen Fehler. Das stimmt nicht mehr. Dieses Design soll jedem helfen, gute Programmiergewohnheiten zu entwickeln. Variablen müssen nach ihrer Deklaration verwendet werden, andernfalls wird ein Fehler gemeldet.

Einige „tote Zonen“ sind versteckt und schwer zu finden.

function bar(x = y, y = 2) {
 return [x, y];
}
bar(); // 报错

Im obigen Code wird beim Aufruf der Balkenfunktion ein Fehler gemeldet (einige Implementierungen melden möglicherweise keinen Fehler), weil der Standardwert von Parameter x gleich einem anderen Parameter y ist. und y wurde zu diesem Zeitpunkt noch nicht deklariert und gehört zur „Dead Zone“. Wenn der Standardwert von y x ist, wird kein Fehler gemeldet, da x zu diesem Zeitpunkt deklariert wurde.

function bar(x = 2, y = x) {
 return [x, y];
}
bar(); // [2, 2]

ES6 legt fest, dass in temporären Totzonen und let- und const-Anweisungen keine Variablenheraufstufung erfolgt. Dies dient hauptsächlich dazu, Laufzeitfehler zu reduzieren und zu verhindern, dass die Variable verwendet wird, bevor sie deklariert wird, was zu unerwartetem Verhalten führt . . Solche Fehler kommen in ES5 sehr häufig vor, und mit dieser Bestimmung ist es jetzt einfach, solche Fehler zu vermeiden.

Kurz gesagt, das Wesen der temporären Totzone besteht darin, dass die Variable, die Sie verwenden möchten, bereits vorhanden ist, sobald Sie den aktuellen Bereich betreten, aber nicht verfügbar ist. Sie können sie nur dann abrufen und abrufen Die Codezeile, die die Variable deklariert, wird angezeigt. Verwenden Sie diese Variable.

Erlaubt keine wiederholten Deklarationen

let erlaubt keine wiederholten Deklarationen derselben Variablen im selben Bereich.

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

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

Daher können Parameter nicht innerhalb einer Funktion neu deklariert werden.

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

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

Bereich auf Blockebene

Warum brauchen wir einen Bereich auf Blockebene?

ES5 verfügt nur über einen globalen Bereich und einen Funktionsbereich, aber keinen Bereich auf Blockebene, was viele unzumutbare Szenarien mit sich bringt.

Im ersten Szenario kann die innere Variable die äußere Variable überschreiben.

var tmp = new Date();

function f() {
 console.log(tmp);
 if (false) {
  var tmp = "hello world";
 }
}

f(); // undefined

上面代码中,函数f执行后,输出结果为undefined,原因在于变量提升,导致内层的tmp变量覆盖了外层的tmp变量。

第二种场景,用来计数的循环变量泄露为全局变量。

var s = &#39;hello&#39;;

for (var i = 0; i < s.length; i++) {
 console.log(s[i]);
}

console.log(i); // 5

上面代码中,变量i只用来控制循环,但是循环结束后,它并没有消失,泄露成了全局变量。

ES6的块级作用域

let实际上为JavaScript新增了块级作用域。

function f1() {
 let n = 5;
 if (true) {
  let n = 10;
 }
 console.log(n); // 5
}

上面的函数有两个代码块,都声明了变量n,运行后输出5。这表示外层代码块不受内层代码块的影响。如果使用var定义变量n,最后输出的值就是10。

ES6允许块级作用域的任意嵌套。

{{{{{let insane = &#39;Hello World&#39;}}}}};

上面代码使用了一个五层的块级作用域。外层作用域无法读取内层作用域的变量。

{{{{
 {let insane = &#39;Hello World&#39;}
 console.log(insane); // 报错
}}}};

内层作用域可以定义外层作用域的同名变量。

{{{{
 let insane = &#39;Hello World&#39;;
 {let insane = &#39;Hello World&#39;}
}}}};

块级作用域的出现,实际上使得获得广泛应用的立即执行函数表达式(IIFE)不再必要了。

// IIFE 写法
(function () {
 var tmp = ...;
 ...
}());

// 块级作用域写法
{
 let tmp = ...;
 ...
}

块级作用域与函数声明

函数能不能在块级作用域之中声明,是一个相当令人混淆的问题。

ES5规定,函数只能在顶层作用域和函数作用域之中声明,不能在块级作用域声明。

// 情况一
if (true) {
 function f() {}
}

// 情况二
try {
 function f() {}
} catch(e) {
}

上面代码的两种函数声明,根据ES5的规定都是非法的。

但是,浏览器没有遵守这个规定,为了兼容以前的旧代码,还是支持在块级作用域之中声明函数,因此上面两种情况实际都能运行,不会报错。不过,“严格模式”下还是会报错。

// ES5严格模式
&#39;use strict&#39;;
if (true) {
 function f() {}
}
// 报错

ES6 引入了块级作用域,明确允许在块级作用域之中声明函数。


// ES6严格模式
&#39;use strict&#39;;
if (true) {
 function f() {}
}
// 不报错

ES6 规定,块级作用域之中,函数声明语句的行为类似于let,在块级作用域之外不可引用。

function f() { console.log(&#39;I am outside!&#39;); }
(function () {
 if (false) {
  // 重复声明一次函数f
  function f() { console.log(&#39;I am inside!&#39;); }
 }

 f();
}());

上面代码在 ES5 中运行,会得到“I am inside!”,因为在if内声明的函数f会被提升到函数头部,实际运行的代码如下。

// ES5版本
function f() { console.log(&#39;I am outside!&#39;); }
(function () {
 function f() { console.log(&#39;I am inside!&#39;); }
 if (false) {
 }
 f();
}());

ES6 的运行结果就完全不一样了,会得到“I am outside!”。因为块级作用域内声明的函数类似于let,对作用域之外没有影响,实际运行的代码如下。

// ES6版本
function f() { console.log(&#39;I am outside!&#39;); }
(function () {
 f();
}());

很显然,这种行为差异会对老代码产生很大影响。为了减轻因此产生的不兼容问题,ES6在附录B里面规定,浏览器的实现可以不遵守上面的规定,有自己的行为方式。

允许在块级作用域内声明函数。
函数声明类似于var,即会提升到全局作用域或函数作用域的头部。
同时,函数声明还会提升到所在的块级作用域的头部。
注意,上面三条规则只对ES6的浏览器实现有效,其他环境的实现不用遵守,还是将块级作用域的函数声明当作let处理。

前面那段代码,在 Chrome 环境下运行会报错。

// ES6的浏览器环境
function f() { console.log(&#39;I am outside!&#39;); }
(function () {
 if (false) {
  // 重复声明一次函数f
  function f() { console.log(&#39;I am inside!&#39;); }
 }

 f();
}());
// Uncaught TypeError: f is not a function

上面的代码报错,是因为实际运行的是下面的代码。

// ES6的浏览器环境
function f() { console.log(&#39;I am outside!&#39;); }
(function () {
 var f = undefined;
 if (false) {
  function f() { console.log(&#39;I am inside!&#39;); }
 }

 f();
}());
// Uncaught TypeError: f is not a function

考虑到环境导致的行为差异太大,应该避免在块级作用域内声明函数。如果确实需要,也应该写成函数表达式,而不是函数声明语句。

// 函数声明语句
{
 let a = &#39;secret&#39;;
 function f() {
  return a;
 }
}

// 函数表达式
{
 let a = &#39;secret&#39;;
 let f = function () {
  return a;
 };
}

另外,还有一个需要注意的地方。ES6的块级作用域允许声明函数的规则,只在使用大括号的情况下成立,如果没有使用大括号,就会报错。

// 不报错
&#39;use strict&#39;;
if (true) {
 function f() {}
}

// 报错
&#39;use strict&#39;;
if (true)
 function f() {}

do 表达式

本质上,块级作用域是一个语句,将多个操作封装在一起,没有返回值。

{
 let t = f();
 t = t * t + 1;
}

上面代码中,块级作用域将两个语句封装在一起。但是,在块级作用域以外,没有办法得到t的值,因为块级作用域不返回值,除非t是全局变量。

现在有一个提案,使得块级作用域可以变为表达式,也就是说可以返回值,办法就是在块级作用域之前加上do,使它变为do表达式。


let x = do {
 let t = f();
 t * t + 1;
};

上面代码中,变量x会得到整个块级作用域的返回值。

JavaScript ES6 的 let 和 var 的比较

在javascript 1.7中, let 关键词被添加进来, 我听说它声明之后类似于”本地变量“, 但是我仍然不确定它和 关键词 var 的具体区别。

回答:
不同点在于作用域, var关键词的作用域是最近的函数作用域(如果在函数体的外部就是全局作用域), let 关键词的作用域是最接近的块作用域(如果在任何块意外就是全局作用域),这将会比函数作用域更小。
同样, 像var 一样, 使用let 声明的变量也会在其被声明的地方之前可见。

下面是Demo 例子。

全局(Global)

当在函数体之外它们是平等的。

let me = &#39;go&#39;; //globally scoped 
var i = &#39;able&#39;; //globally scoped

函数(Function)
当瞎下面这种, 也是平等的。

function ingWithinEstablishedParameters() { 
  let terOfRecommendation = &#39;awesome worker!&#39;; //function block scoped 
  var sityCheerleading = &#39;go!&#39;; //function block scoped 
};

块(Block)
这是不同点, let 只是在 for 循环中, var 却是在整个函数都是可见的。

function allyIlliterate() { 
  //tuce is *not* visible out here 
 
  for( let tuce = 0; tuce < 5; tuce++ ) { 
    //tuce is only visible in here (and in the for() parentheses) 
  }; 
 
  //tuce is *not* visible out here 
}; 
 
function byE40() { 
  //nish *is* visible out here 
 
  for( var nish = 0; nish < 5; nish++ ) { 
    //nish is visible to the whole function 
  }; 
 
  //nish *is* visible out here 
};

Das obige ist der detaillierte Inhalt vonDetaillierte Erläuterung der Verwendung des Befehls let in js ES6. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn