let 和 const

let

{
  let a = 1; // <-- 只在 let 所在的代码块中有效
  var b = 2;
}
console.log(a); // Uncaught ReferenceError: a is not defined
console.log(b); // 2

for 循环

// var
var fnList = [];
for (var i = 0; i < 10; i++){
  fnList[i] = () => {
    console.log(i);
  }
}
fnList.forEach(fn => fn()); // 打印出 10 个 10
// let
var fnList2 = [];
for (let j = 0; j < 10; j++) {
  fnList2[j] = () => {
    console.log(j);
  }
}
fnList2.forEach(fn => fn()); // 0 1 2 3 4 5 6 7 8 9

不存在变量提升

console.log(a); // undefined
var a = 1;

console.log(b); // Uncaught ReferenceError: b is not defined
let b = 2;

暂时性死区

let a = 1;
if (true) {
  a = 2; // Uncaught ReferenceError: e is not defined
  let a;
}
typeof x; // Uncaught ReferenceError: x is not defined <-- typeof 不再是百分百安全的操作符
let x;

隐蔽死区

function bar(x = y, y = 2) { // Uncaught ReferenceError: y is not defined <-- x = y 此时 y 还没声明,会有暂时性死区
  return [x, y];
}
bar();

不允许重复声明

function func() {
  let a = 1;
  var a = 2;
}
// Uncaught SyntaxError: Identifier 'a' has already been declared

function func2() {
  let a = 1;
  let a = 2;
}
// Uncaught SyntaxError: Identifier 'a' has already been declared

不能在函数内部重新声明参数

function func(arg) {
  let arg;
}
// Uncaught SyntaxError: Identifier 'arg' has already been declared

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

块级作用域

ES5 只有全局作用域和函数作用域。

1、内层变量会覆盖外层变量

var a = new Date();
function f() {
  console.log(a);
  if (false) {
    var a = 'Hello a.';
  }
}
f(); // undefined

2、用来计数的循环变量泄露为全局变量

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

ES6 的块级作用域

function fn() {
  let a = 1;
  if (true) {
    let a = 2;
  }
  console.log(a);
}
fn(); // 1

块级作用域和函数声明

ES5 规定函数只能在顶层作用域和函数作用域中声明。

// ES5 环境中
function f() {
  console.log('I am outside.');
}

(function() {
  if (false) {
    function f() {
      console.log('I am inside.');
    }
  }
  f(); // I am inside.
})();
// ES6 环境中 会报错
function f() {
  console.log('I am outside.');
}

(function() {
  if (false) {
    function f() {
      console.log('I am inside.');
    }
  }
  f(); // Uncaught TypeError: f is not a function
})();

应避免在块级作用域中声明函数,如果需要,可写成函数表达式。

{
  let a = 'a';
  function f() {
    console.log(a);
  }
}
f(); // a

{
  let a = 'a';
  const f2 = function() {
    console.log(a);
  }
}
f2(); // Uncaught ReferenceError: f2 is not defined

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

if (true) let a = 1; // Uncaught SyntaxError: Lexical declaration cannot appear in a single-statement context
// 不报错
if (true) {
  let a = 1;
}

const

const 声明一个只读的常量,声明后值不能改变。

const 声明的常量,只是指向的地址不能改变,但是对于符合类型的数据,是可以改变里面的属性的。

const a = {};
a.name = 'a';
a.age = 20;
console.log(a); // {name: "a", age: 20}
a = {}; // Uncaught TypeError: Assignment to constant variable

要冻结对象,可以用 Object.freeze

正常模式下,修改对象属性不会生效。

const a = {};
Object.freeze(a);
a.name = 'a';
console.log(a); // {}

严格模式下,修改对象属性会报错。

'use strict';
const a = {};
Object.freeze(a);
a.name = 'a'; // Uncaught TypeError: Cannot add property name, object is not extensible

顶层对象的属性

顶层对象,在浏览器中指的 window 对象,在 Node 中指的是 global 对象。在 ES5 中,顶层对象的属性和全局变量是等价的。

window.a = 1;
console.log(a); // 1

a = 2;
console.log(window.a); // 2
Last Updated: 5/6/2019, 3:35:12 PM