JavaScript Day 6. let or const or var

let 与 var

  • var - 函式作用域
  • letconst- 区块作用域

JavaScript 宣告变数的方式有三种:var、let、const。let 是 ES6 出现後,被用来改善现有语法的宣告方式,在 ES6 未出现之前,网页不存在「区块域」的概念,因此大多数都使用 var 的方式宣告变数,不过这样有个问题,就是用 var 宣告变数会污染到全域变数,使用 let 可以只在部分区域运作。

var 与 let 宣告变数范例:

var a = '无敌哆啦A梦'; // 这里的 a 为全域变数
function doraemon () {
	let a = '无敌大雄'; // 这里的 a 为区域变数
	a = '变身哆啦美';
	console.log(a); // 变身哆啦美
}

doraemon(); 
console.log(a) // 无敌哆啦A梦

从范例来看,结果是「变身哆啦美」与「无敌哆啦A梦」,这里的观念在於只存在大括号里这件事。

第一个 console.log(a) 是「变身哆啦美」,原因是因为在里面我们重新给 a 赋予了一个「变身哆啦美」的值,而到了第二个 console.log(a) 的时候,答案却变成「无敌哆啦A梦」,这是因为function doraemon 里面的 a 只会存活在 {} 这个大括号里,因此里面我们替 a 赋予的值,没有更改到外面。

接着实际操作 letvar ,看看区块作用域与函式作用域的差别:

// var 宣告
// 宣告变数 a
var a = 10;
if(true){
  var b = 20;
}
 
// 输出: a = 10
console.log(a)
// 输出: b = 20
console.log(b)

// let 宣告
// 宣告变数 a
var a = 10;
 
if(true){
  let b = 20;
}
 
// 输出: a = 10
console.log(a)
// 因为变数 b 使用 let 宣告,离开 if 区域便无法被存取
console.log(b) //会显示没有定义

上面的例子可以看到 varlet 的差异在於区块的概念,letif 区域里面宣告的变数只留在 if 括号里,并且在同一个区块内,letconst 不能重复宣告变数,var 则可以重复宣告。

var 区域污染的现象在回圈尤其明显,这是一个 varfor 的例子:

<ul class="list">
	<li>1</li>
	<li>2</li>
	<li>3</li>
</ul> 
const list = document.querySelectorAll('.list li').length;
for(var i = 0; i < list; i++){
	document.querySelectorAll('.list li')[i].addEventListener('click', function(){
		alert(i+1);
	})
}

以上范例程序码运作方式为,透过点击了解我们点击到的是哪一个按钮,也就是当我们点击 <li>1</li> 的时候,我们预期他会显示 1,点击 <li>2</li> 的时候预期会显示 2 。

但在这个范例中会发现,不管我们点击哪一个,alert 都会显示 4,这是因为值被「全域变数」影响。for 回圈跑完以後,会直接显示全部跑完的结果,而不是个别处理。在这个过程中,var 已经直接将 i 宣告为「全域变数」,并不断透过 for 进行累加,因此全部跑完的结果是 4,但这不是我们预期的结果。

那要如何让以上程序范例码成为我们预期的呢?这时候使用 let 便可以达到个别处理的结果。

const list = document.querySelectorAll('.list li').length;
for(let i = 0; i < list; i++){
	document.querySelectorAll('.list li')[i].addEventListener('click', function(){
		alert(i+1);
	})
}

在这边我们把 var 改成 let,上面说到 let 有区域特性,它只会在大括号里运作,因此每一次的执行结果都会显示一次。

当我们点击 <li>1</li> 的时候,就会执行一次括号内的程序码,在 let i = 0 的作用域里面(括号内)执行 i++ ,因此 alert 此时会跳出 1,当我们点击 <li>2</li> 的时候,就会再执行一次括号内的程序码,在 let i = 1 的作用域里面执行 i++alert 於是跳出 2,然後结束。依此类推,最後即是我们所预期的呈现。

const

const 是宣告常数,常用在一些不能被变更的变数,譬如:url 网址。确定不再做更动的时候,可以使用 const 方法。

尝试执行以下程序码呈现的结果:

const me = '齐天大圣孙悟空';
let me = '猪八戒';
// Uncaught SyntaxError: Identifier 'me' has already been declared

在这边会显示上面这个 me,已经有被宣告变数,由上面的范例码可以知道,const 不能再被重新宣告变数覆盖。

另外,let 可以直接宣告变数,const 则是一定要有值。

let a;
// undefined

const b;
// Uncaught SyntaxError: Missing initializer in const declaration

let 直接宣告变数,只是显示没有东西,而直接宣告变数的 const,会显示缺少值。

虽然使用 const 宣告变数就无法更动,但如果使用 const 宣告物件,里面的属性仍然是可以更动的,因为物件有传参考的特性,因此依然可以修改。

const color = {
	light: 'white',
	dark: 'black'
};
color.midtones = 'grey';
// {light: "white", dark: "black", midtones: "grey"}

最後的结果,midtones: "grey" 是能够被加上去的。

有一点要注意,已经宣告的物件则无法再被重新宣告。

let newColor = {
	light: 'yellow',
	dark: 'crimson'
};
color = newColor // 错误

如果不希望 const 宣告的物件被修改,还有另一项法宝 freeze()freeze() 的功能是防止新增属性或是属性遭到修改,就像它英文的意思一样,「冻结」属性。

const color = {
	light: 'white',
	dark: 'black'
};
Object.freeze(color);
color.midtones = 'grey';
// {light: "white", dark: "black"}

同样的范例,可以看到与上面的结果不同,在物件下方添加 freeze(),属性 midtones 则无法被加入,於是可以防止物件被添加或修改。

参考资料:
ES6 开始的新生活 let, const


<<:  Day 3 Swift语法-基础篇(1/3)-基本运算符及字串

>>:  Day 15 - 使用 Helm 打包 Kubernetes 应用程序

爱用iPhone的UI/UX设计师最恐怖

(这个标题有点耸动跟钓鱼,但不知道为什麽我就是很想用它,在文章开头先讲明。) 即使已经证实了苹果在i...

Day24 生产环境需要注意的部分

在介绍过监控、yaml 控管、网路的端点暴露与附载平衡後,官方有给我们一些在,生产环境部署的建议。透...

EP23 - [TDD] OrderPayQuery 查询付款结果 (1/2)

Youtube 频道:https://www.youtube.com/c/kaochenlong ...

Flutter体验 Day 20-Provider

Provider Provider封装了 InheritedWidget 功能,提供更高效且易懂的使...

Ruby基本介绍(四)

基本上大叔宅男不是很想放男团K-pop, XD 本篇会提到的 定义方法 回圈(loop) 定义方法 ...