[ES6]Day01—ES6简介、Let、Const关键字、块级作用域

ECMAScript 6 入门 (Day01)

ECMAScript 6.0(以下简称 ES6)是 JavaScript 语言的下一代标准,已经在 2015 年 6
月正式发布了。它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。

在这里插入图片描述

1.1 ECMAScript 和 JavaScript 的关系

ECMAScript 和 JavaScript 的关系是,前者是后者的规格,后者是前者的一种实现(另外的 ECMAScript 方言还有
JScript 和 ActionScript)。日常场合,这两个词是可以互换的。

1.2 ES6 与 ECMAScript 2015 的关系

ES6 既是一个历史名词,也是一个泛指,含义是 5.1 版以后的 JavaScript 的下一代标准,涵盖了 ES2015、ES2016、ES2017 等等,而 ES2015 则是正式名称,特指该年发布的正式版本的语言标准。

在这里插入图片描述

-----------------------------------------------------------分隔线-------------------------------------------------

1.3 let 命令

ES6 新增了let命令,用来声明变量。 其用法类似于var,但是 使用let关键字声明的变量,只在所在的代码块内有效;使用let关键字声明的变量才具有块级作用域 。

1)使用let关键字声明的变量,只在所在的代码块内有效。

 	if(true){
 		let a = 10;
 		console.log(a) //10
 	}
 	console.log(a) // a is not defined

2)使用let关键字声明的变量才具有块级作用域

if(true){
 		let a = 10;
 		var b = 200;
 	}
 	console.log(a) // a is not defined
 	console.log(b) // 200

3)不允许重复声明同一个变量

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

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

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

因此,不能在函数内部重新声明参数。

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

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

4)防止循环变量 变成 全局变量

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

}
console.log(i) //i is notdefined

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

}
console.log(i) //2

5)不存在变量提升,需要先定义再使用

变量提升 即 变量可以在声明之前使用,值为undefined

// var 的情况
console.log(foo); // 输出undefined
var foo = 2;


// let 的情况
console.log(bar); // 报错ReferenceError
let bar = 2; 

6)使用let关键字声明的变量具有暂时性死区

ES6 明确规定,如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。 凡是在声明之前就使用这些变量,就会报错。

总之,在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。

if (true) {
	// 暂时性死区开始  
	tmp = 'abc'; // ReferenceError  
	console.log(tmp); // ReferenceError
	let tmp; // 直到定义,暂时性死区才结束 
	 
	console.log(tmp); // undefined
	tmp = 123;
	console.log(tmp); // 123
}

拓展:面试题

原题:循环用var 关键字

var arr=[];
for(var i=0;i<2;i++){
	arr[i]=function(){
		console.log(i)
	}
}
arr[0]();//2
arr[1]();//2

在这里插入图片描述

题目分析:

定义一个数组,循环体是给数组内的元素赋值,这里给每个元素赋的值是方法,方法中打印i,当i=2时跳出循环,arr0; 表示取出数组下标为0的元素,这个元素为一个方法,直接arr[0]()调用方法

题目详解:

console.log(i) 根据作用域链查找原则,要向上一级作用域查找,在这里上一级作用域是循环创建的全局作用域下的全局变量 i ,当arr[i](); 函数执行时,此时循环已经停止,i=2,由于数组中的元素函数输出的都是全局变量i,所以结果都是 2

变题:循环用let关键字

var arr=[];
for(let i=0;i< 2;i++){
	arr[i]=function(){
		console.log(i)
	}
}
arr[0]();//0
arr[1]();//1

题目详解:

由于使用的是let关键字,具有块级作用域,在循环结束后,生成了两个块级作用域,产生的两个块级作用域都有各自的变量i,两个变量互不影响,console.log(i) 根据作用域链查找原则,要向上一级作用域查找,在这里上一级作用域是循环创建的两个块级作用域都有各自的变量i,当arr[i](); 函数执行时,由于数组中的元素函数输出的都是块级作用域 变量i,所以结果分别是0 ,1

1.4 const 命令

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

1)声明常量时必须赋初始值

const PI //Missing initializer in const declaration 丢失初始值

2)使用const关键字声明的变量才具有块级作用域

 	if(true){
 		const a = 10;
 			if(true){
		 		const a = 20; 
		 		console.log(a) //20
		 	}
 		console.log(a) //10
 	}
 	console.log(a) // a is not defined

3)用于声明常量,常量的值(内存地址)就不能改变

ECMAScript中有5中简单数据类型(也称为基本数据类型): Undefined、Null、Boolean、Number和String,复杂的数据类型:Object

对于基本类型,值不可更改,例如:String 、Number、 Boolean类型等

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

上面代码表明改变常量的值会报错。

const ary=[100,200];
ary[0]='a'; //  ary 修改元素,可以成功
ary[1]='b';
console.log(ary);//['a','b']

//  ary 直接赋值,就会报错
ary=['a','b'] ;// TypeError: Assignment to constant variable.

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

//  foo 指向另一个对象,就会报错
foo = {}; // TypeError: "foo" is read-only

上面代码表明改变常量值对应的内存地址会报错。 常量foo储存的是一个地址,这个地址指向一个对象。不可变的只是这个地址,即不能把foo指向另一个地址,但对象本身是可变的,所以依然可以为其添加新属性。

1.const声明的变量不得改变值,这意味着,const一旦声明变量,就必须立即初始化,不能留到以后赋值
2.const的作用域与let命令相同:只在声明所在的块级作用域内有效。
3.const声明的常量,也与let一样不可重复声明
4.const 实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。

在这里插入图片描述

1.5 块级作用域

1)ES5 只有全局作用域和函数作用域,没有块级作用域,这带来很多不合理的场景。

块级作用域,其实就相当于一对大括号内的区域,比如if(){ }function(){ }for(){ } 等等

  • 第一种场景,内层变量可能会覆盖外层变量。
var tmp = new Date();

function f() {

  console.log(tmp); 
  
  if (false) {
  
    var tmp = 'hello world';// 内层的tmp变量覆盖了外层的tmp变量
    
  }
}
  
f(); // undefined

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

  • 第二种场景,用来计数的循环变量泄露为全局变量。
var s = 'hello';
for (var i = 0; i < s.length; i++) {
  console.log(s[i]);
}
console.log(i); // 5

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

2)块级作用域与函数声明

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

  • ES6 引入了块级作用域,明确允许在块级作用域之中声明函数。
  • ES6 规定,块级作用域之中,函数声明语句的行为类似于let,在块级作用域之外不可引用。
  1. 允许在块级作用域内声明函数。
  2. 函数声明类似于var,即会提升到全局作用域或函数作用域的头部。
  3. 同时,函数声明还会提升到所在的块级作用域的头部

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

// 第一种写法,报错
if (true) let x = 1;

// 第二种写法,不报错
if (true) {
  let x = 1;
}

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

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

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

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

ES6 声明变量的六种方法

var , function , let , const , import , class

ES5 只有两种声明变量的方法:var命令 和 function命令。
ES6 除了添加 let 和 const 命令,后面章节还会提到,另外两种声明变量的方法:
import命令和class命令。
所以,ES6 一共有 6 种声明变量的方法。

1.6 顶层对象的属性

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

  • 在ES6 中 var 命令和 function 命令声明的全局变量,依旧是顶层对象的属性;
  • 另一方面规定,let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性。
  • 也就是说,从 ES6 开始,全局变量将逐步与顶层对象的属性脱钩。
// 如果在 Node  REPL 环境,可以写成 global.a
// 或者采用通用方法,写成 this.a

var a = 1; 
window.a // 1

let b = 1;
window.b // undefined

上面代码中,全局变量 a 由 var 命令声明,所以它是顶层对象的属性;
全局变量 b 由 let 命令声明,所以它不是顶层对象的属性,返回undefined。

下一篇 : [ES6]Day02—变量的解构赋值、箭头函数

参考链接:

阮一峰:ECMAScript 6 入门

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值