Let & Const

let 基础用法

很简单就能说明这个问题

if(false)
{
    var a = 'heihei'
}
a = undefined

if(true) {
    var a = 'heihei'
}
a = heihei

也就是说. { } 是木有作用域的.

里面声明的外面依然能够访问.

if(true) { let b = 'heihei_b' }
b = undefined

这样就有作用域了.

我想 w3c 如果不是为了兼容老代码。 可能直接强制用var 也遵循 代码块有作用域吧.

例子

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

这个是文章中的一个列子.

书中的解释是

上面代码中,变量i是let声明的,当前的i只在本轮循环有效,所以每一次循环的i其实都是一个新的变量,所以最后输出的是6。

也就是说。 每一次都是一个新的循环,

对于新的循环来说 i 就是新的局部变量.

不存在变量提升

首先得明白什么是变量提升.

var a = 'haha';
(function() {
  alert(a)
})();

会弹出 haha

var a = 'haha';
(function() {
  var a = 'haha inside';
  alert(a);
})()

这个就是 haha inside 因为你调用的是局部变量 a.

var a = 'haha';
(function() {
  alert(a);
  var a = 'haha inside';
})()

这个时候弹出来 undefined

其实这段代码相当于

var a = 'haha';
(function() {
  var a;
  alert(a);
  a = 'haha inside';
})()

这个就是变量提升.

书中的不会存在变量提升就是指.

我不会弹出 undefined 哟.

我会报错. xxxx is not defined

就是这个意思.

暂时性死区

let 或 const 声明的变量拥有暂时性死区(TDZ):当进入它的作用域,它不能被访问(获取或设置)直到执行到达声明。

首先暂时性死区 就是变量提升的另一种说法.

var a = 'haha';
(function() {
  alert(a);
  var a = 'haha inside';
})()

这个之所以会弹出. undefined 是因为 var a = 'haha inside';

相当于在自执行函数顶部声明了一个 var a; 然后后面来赋值.

使用 let or const 你在声明之前使用会报错

不管你是否去 typeof

避免了 变量提升 的危险.

这个区域 就有一个吊炸天的名字 暂时性死区

本质就是叫你 别提莫 声明之前去使用.

不允许重复声明

var a = 1;
var a = 2;

var 可以重复声明。 谁后面声明用谁.

但是 let or const 不行.

不管对方使用的 var or let or const

以下情况都会报错

var a;
let a;

var b;
const b = '2';

let c;
var c;

const d = '2';
var d;

以上仅针对于同一级别的作用域。

块级作用域

以前 javascript 并没有块级作用域. 也就是说.

var a = 'b';
if(true)
    var a = 'c' 

a 等于 c

也就是说. 你 if 中声明的任何变量.

都将是和if同一层级的变量.

谈不上坑爹. 可是毕竟很多时候是需要块级作用域

要不也不用每次都写匿名自执行的函数

var a = (function(){ var a = ''; })();

难免会有污染的情况

还有书中说的.

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

}

console.log(i); //10.

由于没有块级作用域. 所以泄露到了外部.

书中还提到了变量提升

var tmp = new Date();

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

f(); // undefined

其实。 有良好的书写习惯的话 这种问题很少遇到.

当你使用 let or const 的时候就没有这种烦恼.

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

}

console.log(i); // undefined

任意嵌套也没问题

for(let i=0;i<10;i++)
{
    if(true)
    {
        let i = 'wao';
    }

    console.log(i); // 1,2,3,4,5...
}

不同的 {} 就是一个作用域.

这引申出几个问题.

一. 是否是 {} 就是一个作用域。 switch case 呢?

function switchTest(o) {
    switch(o)
    {
      case '1':
        let a = '1';
        break;
      case '2':
        let a = '2';
        break;
    }
}

然后并不可以 直接报错.

Identifier 'a' has already been declared

继续来

function switchTest(o) {
    switch(o)
    {
      case '1':
        let a = '1';
        break;
      case '2':
        let b = '2';
        break;
    }

    console.log(a);
    console.log(b);
}

不管怎么都会报错.

因为变量死区.

就算你只输出一个 例如

console.log(a); //undefined

然而 真的有块级作用域

顺便提一句.

switch case 是一个很神奇的东西.

你在其中声明一样的变量,他会告诉你 变量已经声明过了. 一副我们里面是一起的样子

可是呢.

它和if有相同的功能.

如果没有 case 到. 那么里面代码也是不会执行.

如果你用var 该泄露还是泄露..

二. 书中提到的. function

首先书中提到了几个东西.

  1. es5 中不允许在 块级作用域 中声明函数
  2. es6 中. 允许声明,并且是类似 let 的行为,外部不能访问.

然而并没有声明卵用..

ES5. 浏览器没有遵守这个规定,还是支持在块级作用域之中声明函数。

而且 es5 & es6 混杂的情况下. 也很难按照规定来做.

以下是我测试. chrome 51.

目测只要执行过的 function 是不会遵循es6 let 声明.. 外部都能访问.

try {
  function f() {}
}
catch(e) { }

if (true) {
  function f() {}
}

都会影响外部.

如果不执行. 就没有这个问题.

如果在 function 中声明函数。 是不会影响外部的.

有点儿类似于 是声明的表达式.

可是有一个奇葩的

function f() { console.log('I am outside!'); }
(function () {
  if (false) {
    function f() { console.log('I am inside!'); }
  }

  f();
}());

按照我刚才的说法.

应该是执行 i am outside. 毕竟没有执行.

可是 ie9 是 I am inside! 如果在外部调用。 依然是 I am outside!'

chrome 是直接报错. 在外部 I am outside!'

然后茫然不知所措.

只能说各个浏览器,解析的方式各有不同.

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

三. 块级作用域

之前突发奇想. 如果在一个块里面,同事使用 let & var

是不是 外部能访问 b 不能访问 a

if(true) {
    var b = 'b';
    let a = 'a'
}

是可以的.

也就是说. 所谓的块级作用域其实和 {} 无关.

你必须使用 let 罢了

const

可以说他就是一个 固定的 let

const a;

你必须一开始就赋值. 不然会报错.

赋值以后,如果是值类型是不能更改的.

const a = 1;
a = 2

这样是会报错的.

可是引用类型就不一样了.

const 只能保证在 栈内存上的地址是不变的.

也就是说.

const a = {};
a['b'] = 'b';

这样是ok的.

内存地址不变,可是堆内存的实际的东西发生了变化.

如果你这样直接硬来是不行的。

const a = {};
a = {}

因为你这样是会改变地址的..

所以。

const 就用开放放字符串,数值吧.

全局对象的属性

如果你这样写.

var a = 'a'
console.log(window.a);

也就是说 var 在顶层声明会自动成为 window 属性.

但是 let 不会..

就是这样..

如果你用全部用 let

作用域就是 window -> 1层 -> 2层.

用var

就是 (window & 1层) > 2层..

以上.

thx

Let & Const的更多相关文章

  1. openssl 1.1.1 reference

    openssl 1.1.1 include/openssl aes.h: # define HEADER_AES_H aes.h: # define AES_ENCRYPT 1 aes.h: # de ...

  2. const,static,extern 简介

    const,static,extern 简介 一.const与宏的区别: const简介:之前常用的字符串常量,一般是抽成宏,但是苹果不推荐我们抽成宏,推荐我们使用const常量. 执行时刻:宏是预编 ...

  3. C++中的const

    一,C++中const的基本知识 1.C++中const的基本概念 1.const是定义常量的关键字,表示只读,不可以修改. 2.const在定义常量的时候必须要初始化,否则报错,因为常量无法修改,只 ...

  4. const extern static 终极指南

    const extern static 终极指南 不管是从事哪种语言的开发工作,const extern static 这三个关键字的用法和原理都是我们必须明白的.本文将对此做出非常详细的讲解. co ...

  5. const let,console.log('a',a)跟console.log('a'+a)的区别

    const 创建一个只读的常量 let块级作用域 const let重复赋值都会报错 console.log('a',a) a console.log('a'+a) a2 逗号的值会有空格:用加号的值 ...

  6. es6之let和const

    在javascript中,我们都知道使用var来声明变量.javascript是函数级作用域,函数内可以访问函数外的变量,函数外不能访问函数内的变量. 函数级作用域会导致一些问题就是某些代码块内的变量 ...

  7. construction const parameter问题 构造函数const引用参数问题

    工程在window下编译没有任何问题, 但是在linux(CentOS6)下编译就老是报错 C++ 编译器已升级到最新版 6.1.0 错误如下: In file included /bits/stl_ ...

  8. Error:const char* 类型的实参和LPCWSTR类型的形参不兼容的解决方法。

    在C++的Windows 应用程序中经常碰到这种情况. 解决方法: 加入如下转换函数: LPCWSTR stringToLPCWSTR(std::string orig) { size_t origs ...

  9. C#基础知识七之const和readonly关键字

    前言 不知道大家对const和readonly关键字两者的区别了解多少,如果你也不是很清楚的话,那就一起来探讨吧!探讨之前我们先来了解静态常量和动态常量. 静态常量 所谓静态常量就是在编译期间会对变量 ...

  10. const 与 readonly知多少

    原文地址: http://www.cnblogs.com/royenhome/archive/2010/05/22/1741592.html 尽管你写了很多年的C#的代码,但是可能当别人问到你cons ...

随机推荐

  1. mvc中服务器端、客户端属性验证

    在mvc中使用表单进行数据提交时,数据验证分为服务器端验证和客户端验证: 我们可以通过使用HtmlHelper中的方法及在页面中引用js库对Model的属性的数据注解(System.Component ...

  2. RMAN异机恢复遭遇ORA-01547、ORA-01152、ORA-01110错误案例

    测试环境:     操作系统  :  Red Hat Enterprise Linux ES release 4 (Nahant Update 4)   VMWARE     数据库     :  O ...

  3. ORA-04091: table xxxx is mutating, trigger/function may not see it

    今天同事让我看一个触发器为什么老是报错,当执行DML语句触发触发器后,会报ORA-04091错误:ORA-04091: table xxxx is mutating, trigger/function ...

  4. web.xml is missing and <failOnMissingWebXml> is set to true 错误解决办法

    对web项目的解决方案: 右击项目——>Java EE Tools——>Generate Deployment Descriptor Stub. 然后系统会在src/main/webapp ...

  5. STM32 KEIL不能输入仿真引脚端口error 65: access violation at 0x40021000 : no 'read' permission

    使用MDK自己创建一个STM32F103ZE核的项目 加入源码后编译,正常,在线仿真单步执行出现如下问题 error 65: access violation at 0x40021000 : no ' ...

  6. HTTP状态码302、303和307的故事

        今日读书,无法理解HTTP302.303.307状态码的来龙去脉,决定对其做深究并总结于本文.       <HTTP权威指南>第3章在讲解30X状态码时,完全没有讲清楚为什么要有 ...

  7. NopCommerce 增加 Customer Attributes

    预期: Customer 新增一个自定义属性 运行站点 1.Admin -> Settings -> Customer settings -> Customer form field ...

  8. POJ3281Dining[最大流]

    Dining Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 16352   Accepted: 7307 Descripti ...

  9. linux下更新python

    刚开始入门python,想直接入门python3,需要更新一下linux自带的python.自带的python是2.6,可以在终端root下键入python查看python版本. 1.从官网下载pyt ...

  10. [随记]Eval的连接方法

    在 .NET 3.5 及以下版本中,如下做法是错误的: <asp:Label ID="_column" runat="server" Text='栏目 I ...