var
聲明一個(gè)變量,可選將其初始化為一個(gè)值。
function fn(){
var a = 1
console.log(a)
}
fn() //輸出 1 。正常的
看看以下代碼
注意:console.log(2)沒(méi)有被執(zhí)行
function fn(){
if(true){
console.log(1)
}else{
//這不會(huì)執(zhí)行
console.log(2)
}
}
fn() // 1
再來(lái)看看以下代碼
console.log(a)報(bào)錯(cuò)了
function fn(){
if(true){
console.log(a)
}else{
//這不會(huì)執(zhí)行
console.log(2)
}
}
fn() //報(bào)錯(cuò)了 a is not defined
還得看看以下代碼
function fn(){
if(true){
console.log(a) //undefined
}else{
//這不會(huì)執(zhí)行
var a
console.log(2)
}
}
fn()
以上代碼竟然沒(méi)有報(bào)錯(cuò)?這....
else{}的大括號(hào)不會(huì)執(zhí)行的
我在else{}的大括號(hào)中聲明了a,a竟然被執(zhí)行了。
趕緊查MDN,原來(lái)是變量提升了。
注意:變量提升將影響變量聲明,而不會(huì)影響其值的初始化。
function fn(){
console.log(a) //undefined
var a = 10
console.log(a) // 10
}
fn()
目的:只暴露frank一個(gè)全局變量
{
var a = 1
window.frank = function (){
console.log(a)
}
}
以上代碼不符合我的目的。
var a = 1,就會(huì)不小心暴露window.a全局變量
---------分割線---------
改善:用函數(shù)包裹起來(lái)
function fn(){
var a = 1
window.frank = function (){
console.log(a)
}
}
fn()
以上代碼不符合我的目的。
這個(gè)函數(shù)有個(gè)名字fn,也是一個(gè)全局變量
---------分割線---------
改善:立即執(zhí)行函數(shù)。
(function (){
var a = 1
window.frank = function (){
console.log(a)
}
}())
目的達(dá)到了。
---------分割線---------
再改善: let
{
let a = 1
window.frank = function (){
console.log(a)
}
}
console.log(a) //a is not defined
console.log(window.frank) //f () {}。正常執(zhí)行
目的達(dá)到了。
let
let語(yǔ)句聲明一個(gè)塊級(jí)作用域的本地變量,并且可選的將其初始化為一個(gè)值。
let聲明的變量只在它所在的代碼塊有效。
{
let a = 10
var b = 20
}
console.log(a) //a is not defined
console.log(b) //20
if(true){
let b = 1;
console.log(1) //1
}else{
console.log(2) //2
}
console.log(b) // 報(bào)錯(cuò) b is not defined
說(shuō)明:
let 的作用域在最近的 {} 之間
不存在變量提升。
{
let a = 1
var b = 1
{
console.log(a) //報(bào)錯(cuò)。a is not defined
console.log(b) // undefined
let a = 2
var b = 2
}
}
-------------分割線---------------
//var 的情況
console.log(x) // undefined
var x = 2;
//let的情況
console.log(y) // 報(bào)錯(cuò)。 y is not defined
let y = 3
如果在let a之前使用a,那么會(huì)報(bào)錯(cuò)。
不允許重復(fù)聲明
//報(bào)錯(cuò)
function fn(){
var a = 1
let a = 2
}
//報(bào)錯(cuò)
function f(){
let b = 1
let b = 2
}
const
const聲明一個(gè)只讀的常量。一旦聲明,常量的值就不能改變。
不允許再次賦值,只有一次賦值機(jī)會(huì)
// let
{
let a = 1
console.log(a) //1
a = 2
console.log(a) // 2
}
// const
{
const a = 1
console.log(a) //1
a = 2
console.log(a) // 報(bào)錯(cuò)
}
不能只聲明,不賦值。
const b; // 報(bào)錯(cuò)
console.log(b)
總結(jié):
1、var 會(huì)變量提升,可以重復(fù)賦值。
2、var 變量提升將影響變量聲明,而不會(huì)影響其值的初始化。
3、const與let的作用域是相同的:只在聲明所在的塊級(jí)作用域內(nèi)有效。
4、const與let都是不可重復(fù)聲明。
5、const與let都是不存在變量提升。
6、const只有一次賦值機(jī)會(huì),而且必須在聲明的時(shí)候立馬賦值。
補(bǔ)充面試題:
題1:
---------
var a = 11
function fn(){
console.log(a) //輸出?
}
a = 22
fn()
-----------------------------------------
題2:
---------
var a = 11
function fn(){
console.log(a) //輸出?
}
fn()
a = 22
-----------------------------------------
答案:
題1 :輸出22
題2 :輸出11
-----------------------------------------
題3:
---------
for(var i = 0; i < 6; i++){
}
console.log(i) // 輸出?
-----------------------------------------
解:
var i
for( i = 0; i < 6; i++){
//0,1,2,3,4,5
}
console.log(i) // 輸出 6
// var 變量提升。for循環(huán)到 i = 6 的時(shí)候,
// 不滿足 i < 6 的條件,就跳到console.log(i),
// 所以最后輸出 6
題4:
---------
for(var i = 0; i < 6; i++){
function fn(){
console.log(i) // 輸出?
}
fn()
}
題5:
---------
<button id = "x">點(diǎn)擊</button>
for(var i = 0; i < 6; i++){
function fn(){
console.log(i) // 輸出?
}
x.onclick = fn
}
答案:
題3 :輸出 6
題4 :輸出 0,1,2,3,4,5
題5 :輸出 6 (時(shí)機(jī)問(wèn)題,刻舟求劍)
-----------------------------------------
題6:
---------
<ul>
<li>導(dǎo)航1</li>
<li>導(dǎo)航2</li>
<li>導(dǎo)航3</li>
<li>導(dǎo)航4</li>
<li>導(dǎo)航5</li>
<li>導(dǎo)航6</li>
</ul>
var liTags = document.querySelectorAll('li')
for(var i = 0; i < liTags.length; i++){
liTags[i].onclick = function(){
console.log(i) // 當(dāng)我點(diǎn)擊【導(dǎo)航3】輸出?
}
}
答案:
題6 :輸出 6 (變量提升)
-----------------------------------------
針對(duì)題6進(jìn)行修改,實(shí)現(xiàn)點(diǎn)擊第n個(gè)【導(dǎo)航】就輸出 n ;
如點(diǎn)擊【導(dǎo)航1】 輸出 0
解法1:
//用let就好了
var liTags = document.querySelectorAll('li')
for(var i = 0; i < liTags.length; i++){
let j = i;
liTags[i].onclick = function(){
console.log(i) // 當(dāng)我點(diǎn)擊【導(dǎo)航3】輸出 2
}
}
-----------------------------------------
解法2:使用立即執(zhí)行函數(shù)
var liTags = document.querySelectorAll('li')
for(var i = 0; i < liTags.length; i++){
(function(j){ //j等于第一個(gè)參數(shù)
//var j = arguments[0] //j等于第一個(gè)參數(shù)
liTags[j].onclick = function(){
console.log(j) // 當(dāng)我點(diǎn)擊【導(dǎo)航3】輸出 2
}
})(i)
}
簡(jiǎn)化:
-----------------------------------------
var liTags = document.querySelectorAll('li')
//i的作用域是 () 括號(hào)里面。
// 0,1,2,3,4,5 退出循環(huán) 6
for(let i = 0; i < liTags.length; i++){
//塊里面的i = 圓括號(hào)里面 i 的值
// i0,i1,i2,i3,i4,i5
liTags[i].onclick = function(){
console.log(i) // 當(dāng)我點(diǎn)擊【導(dǎo)航3】輸出 2
}
// 圓括號(hào)里面 i 的值 = 塊里面的i
}