ECMAScript 6 学习笔记:变量定义方法

栏目: JavaScript · 发布时间: 5年前

内容简介:let 声明的变量只在 let 命令所在的代码块内有效。如果在 let 命令所在代码块外调用,则会报错。let 命令的特性导致它非常适合用于 for 循环,每次循环的 i 都是不同的变量,但是每一轮循环都会记住上一轮循环的值,而 var 声明的全局变量,每次循环都是同一个变量:使用传统的 var 定义变量的方式,声明的变量会发生变量提升现象,即定义的变量在编译时被提到了代码的头部,具体表现为变量可以在声明之前使用,值为 undefined。而 let 纠正了这种行为,使用 let 声明的变量一定要在声明后使

ES6 声明变量的六种方法

  • var 和 function
  • let 和 const
  • import 和 class

let 命令

基本用法

let 声明的变量只在 let 命令所在的代码块内有效。如果在 let 命令所在代码块外调用,则会报错。

{
  let foo = 1;
  var bar = 2;
  console.log(foo); // 1
  console.log(bar); // 2
}
console.log(foo); // ReferenceError: foo is not defined
console.log(bar); // 2

let 命令的特性导致它非常适合用于 for 循环,每次循环的 i 都是不同的变量,但是每一轮循环都会记住上一轮循环的值,而 var 声明的全局变量,每次循环都是同一个变量:

// 使用 var 定义变量
var a = [];
for (var i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i);
  };
}
a[1](); // 无论如何都是 10,因为这里的 i 是全局变量

// 使用 let 定义变量
var a = [];
for (let i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i);
  };
}
a[1](); // 输出 1,尽管每次循环的 i 都是重新定义的,但是 for 会记住上一次 i 的值

变量提升

使用传统的 var 定义变量的方式,声明的变量会发生变量提升现象,即定义的变量在编译时被提到了代码的头部,具体表现为变量可以在声明之前使用,值为 undefined。而 let 纠正了这种行为,使用 let 声明的变量一定要在声明后使用,否则会报错。

// 存在变量提升
console.log(foo); // 输出 undefined
var foo = 1;

// 不存在变量提升
console.log(bar); // 报错 ReferenceError
let bar = 1;

暂时性死区

只要块级作用域内存在 let 命令,它所声明的变量就“绑定”这个区域,不再受到外部的影响。ES6 明确规定,如果区块中存在 let 和 const 命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。这种行为在语法上称为“暂时性死区”。

var foo = 1;

{
  foo = 2; // 报错 ReferenceError
  let foo; // 由于 let 的存在,区块被绑定,变量无法提升,因此上面会报错
}

重复声明

let 不允许在相同作用域内,重复声明同一个变量

{
  let a = 1;
  let a = 2; // 报错
}

{
  let a = 1;
  {
    let a = 2; // 不报错
  }
}

块级作用域

ES5 只有全局作用域和函数作用域,没有块级作用域,这样可能导致多种问题:

  • 内层变量覆盖外层变量
var tmp = 1;

function f() {
  console.log(tmp);
  if (false) {
    var tmp = 2;
  }
}

f(); // undefined,因为 if 代码块中的变量发生了变量提升,导致 console.log 无法读取外部变量
  • 计数循环变量泄露为全局变量,如上文介绍 for 循环时所提到的那样。

ES6 允许块级作用域的任意嵌套,外层作用域无法读取内层作用域的变量,内层作用域可以定义外层作用域的同名变量。

{
  {let insane = 'Hello World'}
  console.log(insane); // 报错,外层作用域无法读取内层作用域的变量
};

函数声明

ES5 规定,函数只能在顶层作用域和函数作用域之中声明,不能在块级作用域声明。ES6 引入了块级作用域,明确允许在块级作用域之中声明函数。ES6 规定,块级作用域之中,函数声明语句的行为类似于 let,在块级作用域之外不可引用。但是在浏览器的 ES6 环境中,块级作用域内声明的函数,行为类似于 var 声明的变量。考虑到环境导致的行为差异太大,应该避免在块级作用域内声明函数。如果确实需要,也应该写成函数表达式,而不是函数声明语句。另外,还有一个需要注意的地方。ES6 的块级作用域允许声明函数的规则,只在使用大括号的情况下成立,如果没有使用大括号,就会报错。

// 不报错
'use strict';
if (true) {
  function f() {}
}

// 没有大括号,报错
'use strict';
if (true) 
  function f() {}

const 命令

const 声明一个只读的常量,一旦声明,常量的值就不能改变,这意味着,const 一旦声明变量,就必须立即初始化,不能留到以后赋值。const 命令的语法特性与 let 命令相同,比如作用域、变量提升规则等。

const PI = 3.1415;
PI = 3; // TypeError: Assignment to constant variable.

const 命令保证的是变量指向的内存地址保存的数据不能改动,而对于对象和数组,const 只能保证指向对象和数组的指针不变,因此对于 const 声明的对象和数组是可以使用其内部方法添加数值的,但是无法指向另一个对象或者数组。

const foo = {};

// 为 foo 添加一个属性,可以成功
foo.prop = 123;
foo.prop // 123

foo = {123}; // TypeError: "foo" is read-only

如果需要声明一个完全无法改动的对象,应该使用 Object.freeze 方法,将对象和对象的属性全部冻结:

// 使用递归函数将对象和对象的属性全部冻结
var constantize = (obj) => {
  Object.freeze(obj);
  Object.keys(obj).forEach((key, i) => {
    if (typeof obj[key] === 'object') {
      constantize(obj[key]);
    }
  });
};

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Web Services原理与研发实践

Web Services原理与研发实践

顾宁刘家茂柴晓路 / 机械工业出版社 / 2006-1 / 33.00元

本书以web services技术原理为主线,详细解释、分析包括XML、XML Schema、SOAP、WSDL、UDDI等在内在的web Services核心技术。在分析、阐述技术原理的同时,结合作者在Web Services领域的最新研究成果,使用大量的实例帮助读者深刻理解技术的设计思路与原则。全书共有9章,第1章主要介绍web Services的背景知识;第2-7章着重讲解webServic......一起来看看 《Web Services原理与研发实践》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具