let和const命令笔记(ES6标准入门)

2、let和const命令

2.1 let命令

基本用法

作用范围:代码块内。

使用场景:for循环(待补充)

在for循环中,每个let生命的变量都是独立的。而var声明的变量指向同一个。特别的是,for循环中循环变量是一个父作用域,而循环体内是一个作用域。

for(let i = 0; i < 10; i++) {
	let i = 'abc';
	console.log(i)
}
// abc
不存在变量提升

变量提升,变量可以在生命之前使用,只不过值为undefined

console.log(foo); // undefined
var foo = 2;

console.log(bar); // ReferenceError
let bar = 'abc';
暂时性死区

暂时性死区:let 声明的变量,在未声明之前不能使用,同时该块区域封锁,外面的变量也进不来。

var tmp = 123;
if(true) {
	tmp = 'abc'; // ReferenceError
	let tmp;
}
// 可以看到tmp在这个块级区域内被封锁了,即使有外部tmp,它也不会使用

在死区内使用typeof 是不安全的(ReferenceError)。需要注意的是,typeof一个没有声明的变量确实允许的,死区和暂未声明是有区别的。

var tmp = 123;
if(true) {
	console.log(typeof tmp); // ReferenceError
    console.log(typeof undeclared_variable); // undefined
	let tmp;
}

隐蔽的死区

function bar (x = y, y = 2) {
	return [x, y];
}
// 由y决定x,但是y属于死区

死区的本质:只要进入当前作用域(let const),所要使用的变量就已经存在,但是不可获取,只有等到声明变量那行代码出现,才可以使用使用该变量。

不允许重复声明

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

function () {
	var a;
	let a; // 报错
}

function(a) {
    let a; // 报错
}
function(a) {
    {
        let a; // 不会报错
    }
}

2.2 块级作用域

为什么需要块级作用域

ES5只有全局作用域和函数作用域,没有块级作用域。问题:1. 变量提升带来的麻烦。 2. 泄露为全局变量

  1. 变量提升

    var tmp = 1;
    function f() {
    	console.log(tmp);
    	if(false) {
    		var tmp = 'hello world'
    	}
    }
    // 想要打印外部变量,但是却是undefined
    
  2. 泄露

    for(var i = 0; i < 5; i++) {
    }
    console.log(i); // 5
    // 内存没有给销毁,而是成为全局变量。
    
ES6的块级作用域

let 为JS带来块级作用域

块级作用域的出现可以让立即执行匿名函数退出舞台。

// IIFE写法
(function() {
	var tmp = ''
} ())
// 块级作用域写法
{
	let tmp = ''
}
块级作用域和函数声明

ES5规定,函数只能在顶层作用域和函数作用域之中使用。不能在块级范围内使用。但是浏览器没有遵循这项规则。

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

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

ES5相当于以下代码。由于ES5只有函数作用域和全局作用域,而且变量会被提前。所以里面的f函数实际上被提前了(IIFE函数顶部)。

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

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

ES6由于存在块级作用域,所以里面的f实际上并不会污染外面,所以调用的是外面的f函数,输出I am outside


但是但是!!!实际在ES6浏览器会报错,这是因为具体实现与规定有出入。具体实现如下

  1. 允许块级作用域内声明函数。有花括号存在才行。

    if(false) function a() {} // 不允许

  2. 函数声明类似于var,也就是会提升到全局作用域和函数作用的头部。

  3. 函数声明还会提升到块级作用域的头部。

以上是浏览器的实现,在node等其他环境依然当作let的行为就ok


回来看之前的例子,其在ES6的具体实现为:

function f() {console.log('I am outside')}

(function () {
	var f = undefined;
	if(false) {
		function f() {console.log('I am inside')}
	}
	f()
}())
// f is not a function

应避免在块级作用域内声明函数,确实需要,写成函数表达式的方式。

do表达式

块级作用域内封闭,外部不能访问。

提案:利用do关键字使得块级作用域转变为表达式,得到返回值。是一个提案而已

let x = do {
	
}

2.3 const命令

基本用法
  1. 和let行为类似。(暂时性死区,不提升,不可重复声明)
  2. 声明的同时必须赋值。
本质

保存变量的地址不变。对于简单类型(数值,字符串,布尔值),其值就保存在变量指向的内存地址中;对于复合类型(对象,数组),

变量指向的内存地址保存只是一个指针,const保证该指针是固定的,至于复合类型内部怎么变,不是const能决定的。

const foo = {};
foo.a = 'b'; // 可行

const bar = [];
bar.length = 0; // 可行
bar.push('Hello'); // 可行
bar = ['aa']; // 报错

如果想将一个对象冻结,应该使用Object.freeze()方法

const foo = Object.freeze({});
foo.prop = 123; // 不起作用,在严格模式下报错

彻底冻结该对象

var constantize = (obj) => {
	Object.freeze(obj);
	Object.keys(obj).forEach((key, i) => {
		if(typeof obj[key] === 'object') {
			constantize(obj[key]);
		}
	})
}
ES6声明变量的6中方式
  • var
  • let
  • const
  • function
  • import
  • class

2.4 顶层对象属性

浏览器中的顶层对象:window;Node中的顶层对象:global

顶层对象的属性和全局变量相关是JS设计的败笔。

  1. 无法再编译时提示变量未声明的错误,只有运行时才能发现,(对象的属性是动态的,无法在编译时就预测到)
  2. 程序员容易创建全局变量而自己不知情
  3. 顶层对象的属性到处可以读写,不利于模块化编程
  4. window指窗口对象,有具体实际意义

ES6逐渐将全局变量和顶层对象隔离。

  1. var function 任然属于定策对象的属性
  2. let const class的全局变量不属于顶层对象的属性。
let a = 1;
console.log(window.a); // undefined

var b = 3;
console.log(window.b); // 3
// 在node中写成global.a或者统一用this.a

2.5 global对象

  • 在浏览器中,顶层对象是window,但是Node和Web Worked没有window
  • 在浏览器和Web Worker中,self指向顶层对象,但是Node没有self
  • 在Node中,global是顶层对象,但是其他环境没有。

用this可以取到顶层对象,但是任然有局限

  • 全局环境下,可以获得顶层对象,但是在模块中指的是当前模块
  • 在函数中,this指向不尽相同
  • 不管严格模式还是普通模式,new Function(‘return this’) ()返回全局对象,但是如果浏览器用了CSP(内容安全策略),那么eval和new Function将不能使用。

可以通过,对self window global依次判断存在(==undefined)与否,获得全局对象。还可以通过插件方式。

提案:在语言层面直接引入global对象。直接了断。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值