La variable enveloppée dans es6 compte-t-elle comme à l'intérieur du bloc ?

青灯夜游
Libérer: 2022-11-21 16:21:58
original
1400 Les gens l'ont consulté

es6 Dans le bloc de calcul des variables enveloppé par if. Il existe une nouvelle portée au niveau du bloc dans es6. Le code enveloppé par "{ }" est la portée au niveau du bloc ; l'instruction if et le code dans la boucle for de la fonction appartiennent tous au bloc ; portée de niveau et sont calculés dans le bloc. Dans ES6, les portées au niveau du bloc peuvent être imbriquées arbitrairement. La portée externe ne peut pas lire les variables de la portée interne ; la portée interne peut définir des variables portant le même nom que la portée externe.

La variable enveloppée dans es6 compte-t-elle comme à l'intérieur du bloc ?

L'environnement d'exploitation de ce tutoriel : système Windows 7, ECMAScript version 6, ordinateur Dell G3.

Qu'est-ce que la portée au niveau du bloc ?

La portée au niveau du bloc est nouvelle dans ES6. La portée du bloc est enveloppée par { }. Le { } dans l'instruction if et l'instruction for appartiennent également. à la portée du bloc. ES6 中新增了块级作用域。块作用域由 { } 包裹,if 语句和 for 语句里面的 { } 也属于块作用域。

函数中的{},if语句,for循环,也是属于块级作用域,let与const定义的变量只能在作用域有效。

为什么需要块级作用域

第一种场景:内部变量会覆盖外部变量

var time = new Date()
function fx () {
    console.log(time) // undefined
    if (false) {
        var time = 'hello'
    }
}
fx()
Copier après la connexion
{
    var a = 1
    console.log(a) // 1
}
console.log(a) // 1
// 通过var定义的变量可以跨块作用域访问到。
Copier après la connexion

第二种场景:用来计数的循环变量泄漏为全局变量

for 循环中的用 var 定义的变量在外部作用域可以访问

for (var i = 0; i < 3; i++) {

}

for (let j = 0; j < 3; j++) {

}
// 3
console.log(i);
// Uncaught ReferenceError: j is not defined
console.log(j);
Copier après la connexion

if 语句中 var 定义的变量在外部作用域可以访问

if(true)if (false) 的区别

  • if(true) 中的赋值语句会被执行,所以 a 打印出来是 3
  • if(false) 中的赋值语句不会被执行,但声明的变量 var b 会由于变量提升,提升到作用域的顶层,所以打印出来是 undefined
if (true) {
	var a = 3
}

if (false) {
	var b = 3
}
// 3
console.log(a);
// undefined
console.log(b);

if (true) {
	let c = 3
}
// Uncaught ReferenceError: c is not defined
console.log(c);
Copier après la connexion

块级作用域(ES6 提供 let & const 变量实现块级作用域)

function fxFn () { // 这是一个块级作用域
    let fx = 'fx is a great girl'
    if (true) { // 这是一个块级作用域
        let fx = 'fx is 18 years old'
    }
    console.log(fx) // fx is a great girl
}
fxFn()
 
// 块级作用域之间相互不影响
Copier après la connexion

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

{{{{
  {
    let fnn = 'Hello'
  }
  console.log(fnn); // 报错
}}}};
Copier après la connexion

上面代码使用了一个五层的块级作用域,每一层都是一个单独的作用域。第四层作用域无法读取第五层作用域的内部变量。

  • 内层作用域可以定义外层作用域的同名变量。
{{{{
  let fnn = 'Hello';
  {
    let fnn = 'Hello'
  }
}}}};
Copier après la connexion

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

// IIFE 写法
(function () {
  var tmp = '...';
  // ...
}());
 
// 块级作用域写法
{
  let tmp = '...';
  // ...
}
Copier après la connexion

块级作用域与函数声明

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

// 情况一
if (true) {
  function f() {}
}
 
// 情况二
try {
  function f() {}
} catch(e) {
  // ...
}
Copier après la connexion

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

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

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

function f() { console.log('I am outside!'); }
 
(function () {
  if (false) {
    // 重复声明一次函数f
    function f() { console.log('I am inside!'); }
  }
 
  f();
}());
Copier après la connexion

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

// ES5 环境
function f() { console.log('I am outside!'); }
 
(function () {
  function f() { console.log('I am inside!'); }
  if (false) {
  }
  f();
}());
Copier après la connexion

ES6 就完全不一样了,理论上会得到“I am outside!”。因为块级作用域内声明的函数类似于 let,对作用域之外没有影响。
但是,如果你真的在 ES6 浏览器中运行一下上面的代码,是会报错的,这是为什么呢?

// 浏览器的 ES6 环境
function f() { console.log('I am outside!'); }
 
(function () {
  if (false) {
    // 重复声明一次函数f
    function f() { console.log('I am inside!'); }
  }
 
  f();
}());
// Uncaught TypeError: f is not a function
Copier après la connexion

上面的代码在 ES6 浏览器中,都会报错。

原来,如果改变了块级作用域内声明的函数的处理规则,显然会对老代码产生很大影响。为了减轻因此产生的不兼容问题,ES6 规定,浏览器的实现可以不遵守上面的规定,有自己的行为方式

  • 允许在块级作用域内声明函数。
  • 函数声明类似于 var,即会提升到全局作用域或函数作用域的头部。
  • 同时,函数声明还会提升到所在的块级作用域的头部。

注意,上面三条规则只对 ES6 的浏览器实现有效,其他环境的实现不用遵守,还是将块级作用域的函数声明当作 let 处理。

根据这三条规则,浏览器的 ES6 环境中,块级作用域内声明的函数,行为类似于 var

{}, les instructions if et les boucles for dans les fonctions appartiennent également à la portée au niveau du bloc. Les variables définies par let et const ne peuvent être valides que dans la portée.

🎜🎜Pourquoi une portée au niveau du bloc est nécessaire🎜🎜🎜Premier scénario : les variables internes écraseront les variables externes🎜
// 浏览器的 ES6 环境
function f() { console.log('I am outside!'); }
(function () {
  var f = undefined;
  if (false) {
    function f() { console.log('I am inside!'); }
  }
 
  f();
}());
// Uncaught TypeError: f is not a function
Copier après la connexion
// 块级作用域内部的函数声明语句,建议不要使用
{
  let a = 'secret';
  function f() {
    return a;
  }
}
 
// 块级作用域内部,优先使用函数表达式
{
  let a = 'secret';
  let f = function () {
    return a;
  };
}
Copier après la connexion
Copier après la connexion
🎜Deuxième scénario : La variable de boucle utilisée pour compter les fuites en tant que variable globale 🎜🎜 Les variables définies avec var dans la boucle for sont accessibles dans la portée externe 🎜
// 第一种写法,报错
if (true) let x = 1;
 
// 第二种写法,不报错
if (true) {
  let x = 1;
}
Copier après la connexion
Copier après la connexion
🎜var dans l'instruction <code>if Les variables définies par code> sont accessibles dans la portée externe🎜🎜🎜La différence entre if(true) et if (false)🎜🎜
  • L'instruction d'affectation dans if(true)
sera exécutée, donc a s'imprime sous la forme 3
  • if( false) L'instruction d'affectation dans ne sera pas exécutée, mais la variable déclarée var b sera promue au niveau supérieur de la portée en raison de la promotion de la variable, elle est donc imprimée comme undefined
  • // 不报错
    'use strict';
    if (true) {
      function f() {}
    }
     
    // 报错
    'use strict';
    if (true)
      function f() {}
    Copier après la connexion
    Copier après la connexion
    🎜
    🎜🎜Portée au niveau du bloc (ES6 fournit des variables let et const pour implémenter la portée au niveau du bloc)🎜🎜rrreee🎜ES6 permet intégration arbitraire d'un ensemble de portées au niveau du bloc. 🎜rrreee🎜Le code ci-dessus utilise une portée de bloc à cinq niveaux, et chaque niveau est une portée distincte. La portée de quatrième niveau ne peut pas lire les variables internes de la portée de cinquième niveau. 🎜
    • La portée interne peut définir des variables portant le même nom que la portée externe.
    rrreee🎜L'émergence de la portée au niveau du bloc rend en fait l'expression de fonction anonyme immédiatement exécutée largement utilisée (IIFE anonyme) n'est plus nécessaire. 🎜rrreee🎜
    🎜🎜Déclaration de portée et de fonction au niveau du bloc🎜🎜🎜ES5 stipule que les fonctions ne peuvent être déclarées que dans la portée de niveau supérieur et la portée de la fonction, pas dans le bloc Déclaration de portée de niveau-niveau. 🎜rrreee🎜Les deux déclarations de fonctions ci-dessus sont illégales selon ES5. 🎜🎜Cependant, les navigateurs ne respectent pas cette règle. Afin d'être compatibles avec l'ancien code, ils prennent toujours en charge la déclaration de fonctions dans des étendues au niveau du bloc. Par conséquent, les deux situations ci-dessus peuvent réellement s'exécuter sans signaler d'erreurs. 🎜🎜ES6 a introduit la portée au niveau du bloc, permettant explicitement de déclarer les fonctions dans la portée au niveau du bloc. ES6 stipule que dans la portée au niveau du bloc, les instructions de déclaration de fonction se comportent comme let et ne peuvent pas être référencées en dehors de la portée au niveau du bloc. 🎜rrreee🎜Lorsque le code ci-dessus est exécuté dans ES5, vous obtiendrez "Je suis à l'intérieur !" car la fonction déclarée dans <code>if f sera promu à la tête de la fonction, et le code en cours d'exécution est le suivant. 🎜rrreee🎜ES6 est complètement différent. En théorie, vous obtiendrez "Je suis dehors !". Étant donné que les fonctions déclarées dans la portée au niveau du bloc sont similaires à let, elles n'ont aucun effet en dehors de la portée.
    Cependant, si vous exécutez réellement le code ci-dessus dans le navigateur ES6, une erreur sera signalée. Pourquoi ? 🎜rrreee🎜Le code ci-dessus signalera une erreur dans le navigateur ES6. 🎜🎜Il s'avère que si les règles de traitement des fonctions déclarées dans la portée au niveau du bloc sont modifiées, cela aura évidemment un grand impact sur l'ancien code. Afin d'atténuer les problèmes d'incompatibilité qui en résultent, ES6 stipule que les implémentations de navigateurs ne peuvent pas se conformer aux réglementations ci-dessus et avoir leur propre comportement🎜
    • Autoriser la déclaration des fonctions dans une portée au niveau du bloc.
    • La déclaration de fonction est similaire à var, c'est-à-dire qu'elle sera promue en tête de la portée globale ou de la portée de la fonction.
    • Dans le même temps, la déclaration de fonction sera également promue au niveau de la tête de la portée au niveau du bloc où elle se trouve.
    🎜Notez que les trois règles ci-dessus ne sont valables que pour les implémentations de navigateur de ES6. Les implémentations dans d'autres environnements n'ont pas besoin d'être respectées. Les déclarations de fonctions au niveau du bloc doivent toujours être traitées. comme let handle. 🎜🎜Selon ces trois règles, dans l'environnement ES6 du navigateur, les fonctions déclarées dans la portée au niveau du bloc se comportent de la même manière que les variables déclarées dans var. Le code qui s'exécute réellement dans l'exemple ci-dessus est le suivant. 🎜rrreee🎜Considérant que le comportement provoqué par l'environnement est trop différent, il convient d'éviter de déclarer des fonctions dans une portée au niveau du bloc. Si cela est vraiment nécessaire, il doit être écrit sous forme d'expression de fonction au lieu d'une instruction de déclaration de fonction. 🎜
    // 块级作用域内部的函数声明语句,建议不要使用
    {
      let a = 'secret';
      function f() {
        return a;
      }
    }
     
    // 块级作用域内部,优先使用函数表达式
    {
      let a = 'secret';
      let f = function () {
        return a;
      };
    }
    Copier après la connexion
    Copier après la connexion

    ES6 的块级作用域必须有大括号

    如果没有大括号,JavaScript 引擎就认为不存在块级作用域。

    // 第一种写法,报错
    if (true) let x = 1;
     
    // 第二种写法,不报错
    if (true) {
      let x = 1;
    }
    Copier après la connexion
    Copier après la connexion

    上面代码中,第一种写法没有大括号,所以不存在块级作用域,而let只能出现在当前作用域的顶层,所以报错。第二种写法有大括号,所以块级作用域成立。

    函数声明也是如此,严格模式下,函数只能声明在当前作用域的顶层。

    // 不报错
    'use strict';
    if (true) {
      function f() {}
    }
     
    // 报错
    'use strict';
    if (true)
      function f() {}
    Copier après la connexion
    Copier après la connexion

    【推荐学习:javascript视频教程

    Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

    Étiquettes associées:
    source:php.cn
    Déclaration de ce site Web
    Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
    Tutoriels populaires
    Plus>
    Derniers téléchargements
    Plus>
    effets Web
    Code source du site Web
    Matériel du site Web
    Modèle frontal
    À propos de nous Clause de non-responsabilité Sitemap
    Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!