ES6学习笔记1:let和const命令

目录

let 命令

基本用法

let 命令是用来声明变量,和 var 用法类似,但是let 所声明的变量作用域只在所在的代码块内有效。

在for循环中,很适合使用let命令,可以有效的避免闭包的问题。

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

在这里的ivar声明的,在全局范围内有效,每一次循环,变量i都会发生改变,并且循环内a的函数内部console.log(i);也会根据全局变量发生改变而改变,导致运行输出的是最后一次循环的i的值。

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

在这里的ilet声明的,当前的i只对当前的循环有效,所以每一次的循环的i都是一个新的变量。JavaScript 引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的基础上进行计算。

变量提升

通过 var声明的变量会发生一些“变量提升”的现象,即变量可以在声明之前使用,值为undefined,按照正常的逻辑,变量应该在声明语句之后才可以使用。而let则修复了这个问题,let声明的变量,一定要在声明后才可以使用,否则会报错。

暂时性死区

只要块级作用域有let命令,它所声明的变量就绑定了这个区域,不在受外部的影响。ES6 明确规定,如果区块中存在letconst命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。在这段代码块中,使用let命令声明变量之前,这个变量都是不可用的,这不可用的区间就是“暂时性死区”。

在“暂时性死区”中,typeof运行时也会抛出异常。

不允许重复声明

  • let不允许在相同的作用域内,重复声明同一个变量。
function fun(){
  let a = 10;
  let a = 1;
}

上面的代码在同一个作用域内声明了两个相同的a;所以会报错。

但是下面代码不会报错:

function fun(){
  let a = 10;
  var a = 1;
}

还有let声明的变量与当前函数的参数不能一样

function fun(param){
  let param;
}
fun();

此时的函数fun()就会因为函数参数名称和let声明的变量名称一致,导致报错。

为什么需要块级作用域?

  • 内层变量可能会覆盖外层变量
var tmp = new Date();
function fun(){
  console.log(tmp);
  if(false){
    var tmp = 'hello world';
  }
}
fun();

此时在fun()函数执行以后,内层的tmp变量提升,覆盖了外层的tmp变量,所以此时为undefined.

  • 用来计数的循环变量泄露为全局变量
var str = 'hello';

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

console.log(i) // 5

这里的i只是用来控制循环的,但是循环结束以后,并没有消失,进而成为了全局变量。

块级作用域与函数声明

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

在ES6中,允许在块级作用域中声明函数。但是在块级作用域中声明的函数在作用域之外不可调用。

块级作用域怎么来?

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

// 不是块级作用域
if(true) let x = 1; // 报错

// 块级作用域
if(true){
  let x = 1;
}

const命令

基本用法

  • const声明的变量是一个只读的常量,只要声明了,常量的值就不能改变了,并且在声明变量的同时初始化,不能在声明以后再进行赋值操作。
const demo; // 非法的
  • constlet的作用域是一样的,只在声明的块级作用域内有效。
  • const也存在暂时性死区,只能在声明变量的位置之后使用。

本质

  • const实际上保证的并不是变量的值,而是变量指向的内存地址所保存的数据不能改动。对于简单的数据类型(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但是对于复合型的数据(只要是对象和数组),变量指向的内存地址保存的是一个指向实际数据的指针,此时的const只能保证这个指针是固定的,至于指针指向的数据是不是可变的就不能控制了。
// 对于对象来说
const foo = {};

// 给 foo 添加一个属性,是可以的
foo.prop = 123;

// 将 foo 指向另一个对象就会报错
foo = {}; 

// 对于数组来说
const arr = [];

// 给数组中push元素是没有问题的
arr.push(1);

// 但是将 arr 赋值到另一个数组就会报错

arr = ['demo'];

冻结对象

如果想要冻结一个对象,可以使用Object.freeze()方法

const foo = Object.freeze({});
foo.prop = 123;

此时在常规模式下,fooprop属性完全没作用,在严格模式中,这种写法会报错。

除了将对象本身冻结,对象的属性也应该冻结:

var constantize = (obj) =>{
  Object.freeze(obj);
  Object.keys(obj).forEach((key,i) => {
    if(typeof obj[key] === 'object'){
      constantize(obj[key]);
    }
  })
}

ES6 声明变量的六种方法

  • var命令
  • function命令
  • let命令
  • const命令
  • import命令
  • class命令

顶层对象的属性

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

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

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

在这里,顶层对象的属性赋值与全局变量的赋值是同一件事。

在ES6中, varfunction命令声明的变量是全局变量,依旧是顶层对象的属性;letconstclass声明的变量是不属于顶层对象的属性。

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

let b = 1;
console.log(window.b) // undefined

globalThis对象

JavaScript 语言存在一个顶层对象,它提供全局环境(全局作用域),所有代码都在这个环境中运行。

  • 在浏览器中:顶层对象是window,但是在Node和Web Worker没有window.
  • 在浏览器和Web Worker 里面,self也指向顶层对象,但是Node中没有self.
  • Node 里面,顶层对象是global,但是在其他环境都不支持

this关键字

  • 全局环境中,this会返回顶层对象,但是在Node模块和ES6模块中,this返回的是当前模块.
  • 函数中的this,如果函数不是作为对象的方法运行,而是单纯作为函数运行,this会指向顶层对象。但是在严格模式下,这时的this会返回undefined.
  • 不论是什么模式,new Function('return this')(),总是会返回全局对象,但是,如果浏览器用了CSP(Content Security Policy,内容安全策略),那么evalnew Function这些方法就不能使用了。

获取顶层对象的两种方法

  • 第一种方法
(typeof window !== 'undefined' ? window
: (typeof process === 'object' && typeof require === 'function' && typeof global === 'object')? global : this
)
  • 第二种方法
var getGlobal = function () {
  if(typeof self !== 'undefined') {return self}
  if(typeof window !== 'undefined') {return window}
  if(typeof global !== 'undefined') {return global}
  throw new Error('unable to locate global object');
}

备注:本文是自己学习阮一峰老师的《ECMAScript 6 入门》所做的笔记,大部分例子来源于此书。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值