第六節(jié) 作用域變量提升和var等區(qū)別


一、作用域:

1.變量的作用域

作用域是變量的可作用范圍,變量只有在自己的作用域下才會生效。

函數(shù)會產(chǎn)生作用域,在函數(shù)內(nèi)定義的變量只能在函數(shù)內(nèi)使用。

1.2 作用域分類

局部作用域: 函數(shù)內(nèi)定義的變量和形參的作用域就是局部作用域;這樣的變量稱之為局部變量。

全局作用域: 在函數(shù)外面定義的變量的作用域是全局作用域;這樣的變量稱之為全局變量。

塊級作用域: 在代碼塊中定義的變量的作用域是塊級作用域;這樣的變量稱之為塊級變量。 ES6才支持

局部變量 只能在定義變量的函數(shù)內(nèi)使用; 全局變量 在任意地方都可以使用。

注意:

函數(shù)內(nèi)的形參也是局部變量,作用域范圍就是所在函數(shù)。

了解:

函數(shù)內(nèi)不使用關(guān)鍵字 var 聲明的變量會被當(dāng)做全局變量,但不建議這么做,在嚴(yán)格模式下,不使用關(guān)鍵字 var 就聲明變量,會報(bào)錯(cuò)!

a、b 都是在全局下定義的,所以他們的作用域就是全局,n是在fn中定義的,它的作用域就是fn;

var a=3;

var b=6;

function fn(){

? var n=3;

? console.log(n)

};

console.log(a,b);

在全局下定義的變量,在哪都可以訪問到,在私有作用域中定義的變量,在外面是訪問不到的

var a=3;

function fn(){

? var b=6;

? console.log(a);

}

fn();

console.log(b);

作用:隔離變量,不同作用域下同名變量不會有沖突

var a = 10,

? ? b = 20;

function fn(x) {

? ? var a = 100,

? ? ? ? c = 300;

? ? console.log('fn()', a, b, c, x)

? ? function bar(x) {

? ? ? ? var a = 1000,

? ? ? ? ? ? d = 400

? ? ? ? console.log('bar()', a, b, c, d, x)

? ? }

? ? bar(100)

? ? bar(200)

}

fn(10)

全局變量和私有變量

全局變量:在全局作用域中定義的變量就是全局變量

私有變量:

形參

在函數(shù)私有作用域中定義的變量

1.3 作用域鏈

① 什么是作用域鏈

1) 函數(shù)會限制變量的作用域范圍,而函數(shù)內(nèi)是可以再嵌套函數(shù)的,函數(shù)的層層嵌套,就形成了一個(gè)作用域鏈。2)作用域鏈描述的是程序在執(zhí)行過程當(dāng)中尋找變量的過程。

② 作用域鏈尋找變量的過程

當(dāng)函數(shù)內(nèi)使用某個(gè)變量的時(shí)候,會按照如下過程找到該變量:1) 先從自身所在作用域去查找,如果沒有再從上級作用域當(dāng)中去查找,直到找到全局作用域當(dāng)中。2)如果其中有找到,就不會再往上查找,直接使用。3)如果都沒有找到,那么就會報(bào)引用錯(cuò)誤提示變量沒有定義。

③ 注意:

一個(gè)變量的作用域只與函數(shù)聲明的位置有關(guān),與函數(shù)調(diào)用的位置無關(guān)!

functionfn(){

console.log(n);// 自己私有作用域沒有這個(gè)變量,向上級進(jìn)行查找,上級window 也沒有,就報(bào)錯(cuò)

}

fn();

===========

functionfn(){

n=3;// 自己私有作用域中沒有,向上級進(jìn)行查找,上級作用域也沒有,就相當(dāng)于給window.n=3;

}

fn();

console.log(n);

============

functionfn(){

n=3;// 自己私有作用域中沒有,向上級進(jìn)行查找,上級作用域中有,就是上級作用域的n的值重新改了3

}

varn=2;

fn();

console.log(n);

===============

functionfn(){

console.log(n);// 2

}

varn=2;

fn();

console.log(n);

二、瀏覽器底層運(yùn)行機(jī)制

var x=12;

let y=13;

z=14;

console.log(window.x);

console.log(window.y);

console.log(window.z);

console.log(x);

console.log(y);

console.log(z);

ECStack(Execution context Stack) 執(zhí)行環(huán)境棧(棧內(nèi)存,從內(nèi)存中分配出來的一塊內(nèi)存)

EC(Execution Context)執(zhí)行上下文(在編程語言中,代碼執(zhí)行,為了區(qū)分全局作用域和函數(shù)執(zhí)行所處不同的作用域,目的是為了區(qū)分每個(gè)詞法作用域下代碼的獨(dú)立性)EC 就是代碼執(zhí)行所處的范圍

EC(g):全局執(zhí)行上下文

EC(function):函數(shù)執(zhí)行的上下文

VO 和AO:在每一個(gè)執(zhí)行上下文中,代碼執(zhí)行的時(shí)候,都會存貯一些變量:

全局上下文中的變量存儲在VO

私有上下文中的變量存儲在AO

GO:瀏覽器把一些內(nèi)置的屬性和方法放到了GO中,并且在全局執(zhí)行上下文(EC(g))中創(chuàng)建了一個(gè)window變量對象,并且讓其指向GO


三、變量提升

1、什么是變量提升?

當(dāng)瀏覽器開辟出供js執(zhí)行的棧內(nèi)存之后,代碼并不是立即自上而下執(zhí)行,而是需要先做一些事情:把當(dāng)前作用域中帶var 和function 的關(guān)鍵字進(jìn)行提前的聲明和定義,這叫做變量提升機(jī)制。

var 和function 在變量提升階段區(qū)別:

var 在變量提升階段,是只聲明,未定義(不賦值)

function 在此階段是聲明和定義都完成。

var a=2;

var b=a;

b=3;

console.log(b)

雖然函數(shù)還沒有聲明定義,但是調(diào)用也不受影響

2、變量提升(條件判斷)

①不論判斷條件是否成立,都會進(jìn)行變量提升

在當(dāng)前作用域下,不管判斷條件是否成功,都會進(jìn)行變量提升:

var :還是只聲明

function:

新版本瀏覽器中的function 只是聲明,不定義

在老版本中還是聲明和定義(僅限判斷語句)

console.log(a);

if(1=="1"){

? console.log(a);

? var a=2;

? console.log(a);

}

console.log(a);

undefined undefined 2 2

console.log(a);

if(1=="2"){

? console.log(a);

? var a=2;

? console.log(a);

}

console.log(a);

undefined undefined

console.log(fn);

if(1=="2"){

? console.log(fn);

? function fn(){};

? console.log(fn);

}

console.log(fn);

undefined undefined

console.log(fn);

if(1=="1"){

? console.log(fn);

? function fn(){};

? fn=3;

? console.log(fn);

}

console.log(fn);

undefined 函數(shù) 3 函數(shù)

函數(shù)是個(gè)渣男,以函數(shù)為分界線,函數(shù)以上的內(nèi)容會給全局一份

console.log(a);

if("a" in window){

? ? var a=100;

}

console.log(a);

undefined 100

f=function(){

? ? return true;

};

g=function(){

? ? return false;

};

~function(){

if(g()&&[]==![]){

? ? f=function(){return false;};

? ? function g(){

? ? ? ? return true;

? ? }

}

}();

console.log(f());

console.log(g());

報(bào)錯(cuò)

console.log(fn);

if(1==1){

? console.log(fn);

? function fn(){

? ? ? console.log("ok");

? }

}

console.log(fn)

undefined 函數(shù) 函數(shù)

var a=0;

if(true){

? a=1;

? function a(){}

? a=21;

? console.log(a);

}

console.log(a);

21 1

console.log(num);

console.log(fn);

if([]){

? // 只要進(jìn)到當(dāng)前if條件中,會立即對fn進(jìn)行賦值;

? fn()

? var num=100;

? function fn(){console.log("a")}

}

console.log(fn);

undefined undefined a 函數(shù)

②只對等號左邊的做變量提升

console.log(fn);

console.log(fn(1,2));

varfn=function(n,m){

returnn+m;

}

console.log(fn(3,4));

=====================

sum();

fn();

varfn=function(){

console.log(1);

};

functionsum(){

console.log(2);

}

fn();

sum();

=====================

console.log(obj.f1);

varobj={

f1:function(){

console.log(1)

}

}

③return 下面的代碼進(jìn)行變量提升,return 后面的代碼不進(jìn)行變量提升

functionfn(){

console.log(a);

returnfunctionf1(){

}

vara=3;

}

fn();

=============================

functionfn(){

console.log(f2);

returnfunctionf1(){

}

functionf2(){

console.log("f2")

}

}

fn();

④如果變量名字重復(fù)

對于var的不會進(jìn)行重復(fù)聲明,但是會重新賦值在變量提升階段,看到第一行var num ,會聲明一個(gè)變量num,此時(shí)看到第二行還有一個(gè)就不用再聲明了對于function的在變量提升階段是聲明和定義一起完成的,如果遇到重復(fù)聲明定義的,會進(jìn)行重新賦值

console.log(fn)

functionfn(){

console.log(1);

}

functionfn(){

console.log(2);

}

functionfn(){

console.log(3);

}

======================

console.log(fn)

functionfn(){

console.log(1)

}

varfn=2;

console.log(fn)

===============================

console.log(num);

varnum=1;

console.log(num);

varnum=2;

console.log(num);

fn();// 4

functionfn(){

console.log(1);

}

functionfn(){

console.log(2);

}

fn();// 4

functionfn(){

console.log(3);

}

fn=100;

functionfn(){

console.log(4);

}

fn();

⑤自執(zhí)行函數(shù)在當(dāng)前所在的作用域中不進(jìn)行變量提升

自執(zhí)行函數(shù)自己所形成的私有作用域照常進(jìn)行

functionf2(){

console.log("f2");

}

// 自執(zhí)行函數(shù)在此處不進(jìn)行變量提升

(function(){

console.log(a);// undefined, 照常進(jìn)行變量提升

vara=3;

})();



一、帶var 和不帶var的區(qū)別

●帶var 的時(shí)候就是聲明變量,不帶var的時(shí)候,沒有變量提升,在全局作用域下,帶var 還是不帶var 都是給GO添加了一個(gè)屬性(也相當(dāng)于給window),屬性名就是此變量,屬性值就是變量值

console.log(a); //undefined

var a=3;

b=6;

console.log(window.a);

console.log("a" in window);

delete window.a;

delete window.b;

【思考】:下面的答案是什么?

console.log(a); //undefined

var a=3;

console.log(window.a);

console.log("a" in window);

【 判斷一個(gè)對象到底有沒有一個(gè)屬性】:用 “屬性名” in 對象,如果返回值是false 說明就是不存在,如果是true說明就是存在。

obj={"name":"lili"};

console.log(“name” in obj )// true? 說明name就是obj的屬性

console.log("age" in obj)//false? ? 說明age 不是obj的屬性

二、let const && var 的區(qū)別

/**

* let const && var 的區(qū)別

*/

varnum=12;

//let vs const

/*

? let 和 const聲明的都是變量,只不過const聲明的變量,

? 不允許重新指向其他的值(和值關(guān)聯(lián)的指針是不能改變的)

? const 不能直接寫const m,必須給一個(gè)初始值,不然會報(bào)錯(cuò)

*/

constm={

name:"cxh"

}

m.name="zcf"

console.log(m)

//let vs var

/*

1、在全局上下文中,基于var聲明的變量是直接放在GO(window)中,

而基于let聲明的變量是放在VO(G)中 的,和GO沒關(guān)系

2、var存在的變量提升,let不存在變量提升

3、var 允許重復(fù)聲明,而let是不允許的[而且在詞法分析階段就過不去]

4、let會產(chǎn)生塊級上下文,var不會

5、關(guān)于暫時(shí)性死區(qū)問題:typeof 檢測一個(gè)未聲明的變量,

不會報(bào)錯(cuò),結(jié)果是undefined 在let聲明前使用就會報(bào)錯(cuò)

*/

console.log(m);//m is not defined

console.log(typeofm)//"undefined"

console.log(typeofa)//報(bào)錯(cuò) 未聲明前不能使用

leta=10

暫時(shí)性死區(qū):

ES6明確規(guī)定,如果區(qū)塊中存在let和const命令,這個(gè)區(qū)塊對這些命令聲明的變量,從一開始就形成了封閉作用域。凡是在聲明之前就使用這些變量,就會報(bào)錯(cuò)。在代碼塊內(nèi),使用let命令聲明變量之前,該變量都是不可用的。這在語法上,稱為“暫時(shí)性死區(qū)”(temporal dead zone,簡稱 TDZ)。

console.log(a);// ReferenceError: a is not defined

leta=2;

三、作用域鏈擴(kuò)展練習(xí)題

在私有作用域中,如果沒有定義這個(gè)私有變量,就會向上一級作用域進(jìn)行查找,如果都沒有,繼續(xù)進(jìn)行查找,直到查找到window為止,如果此變量聲明的時(shí)候用了 let、const,就相當(dāng)于給VO添加一個(gè)這樣的變量,如果聲明的時(shí)候用了var、function 或者壓根沒聲明就相當(dāng)于給GO添加了一個(gè)屬性(也相當(dāng)于給window添加了一個(gè)屬性)【思考題】

console.log(b);

function fn(){

? ? b=13;

? ? console.log(b);? ?

}

fn();

console.log(b);

【答案】

console.log(b);//b is not defined

function fn(){

? ? b=13; // 不是私有變量,向上查找,直到window都沒有,給window添加一個(gè)屬性 window.b=13;

? ? console.log(b);//13

}

fn();

console.log(b);// 13?

【思考題】

console.log(a,b);

var a=12,

b=12;

function fn(){

? ? console.log(a,b);

? ? var a=b=13;

? ? console.log(a,b);

}

fn();

console.log(a,b);


函數(shù)底層運(yùn)行機(jī)制

1、私有上下文

函數(shù)執(zhí)行,就會形成一個(gè)全新的私有上下文,然后進(jìn)棧執(zhí)行私有上下文,首先會有一個(gè)AO(私有變量對象-->形參變量和函數(shù)體內(nèi)聲明過的變量),來存儲私有變量

代碼執(zhí)行之前會做哪些事?

●初始作用域鏈:<自己的上下文(執(zhí)行產(chǎn)生的),函數(shù)的作用域(創(chuàng)建時(shí)候聲明的)>●初始this●初始arguments●形參賦值●變量提升●代碼執(zhí)行

2、代碼演示:

var x=[12,23];

function fn(x){

x[0]=100;

x=[100];

x[1]=200;

console.log(x);

}

fn(x);

console.log(x);

四、練習(xí)題(私有變量和全局變量)

var a=b=13和var a=13,b=13的區(qū)別

vara=b=13

vara=13;

b=13;

vara=13,b=13;

vara=13;

varb=13;

1)

var a=12,b=13,c=14;

function fn(a){

? console.log(a,b,c);

? var b=c=a=20;

? console.log(a,b,c);

}

fn(a);

console.log(a,b,c);

2)

/*

傳進(jìn)來的參數(shù)如果是引用數(shù)據(jù)類型,在函數(shù)里面雖然是私有變量,

但是更改的還是那個(gè)引用地址,所以全局下的變量也會發(fā)生變化

*/

var ary=[12,13];

function fn(ary){

? console.log(ary);

? ary[0]=100;

? ary=[100];

? ary[0]=0;

? console.log(ary);

}

fn(ary);

console.log(ary);

【答案】:

[12,13]

[0]

[100,13]

五、上級作用域:

上級作用域:當(dāng)前函數(shù)執(zhí)行,形成一個(gè)私有作用域A,這個(gè)A的上級作用域是誰,跟它在哪執(zhí)行無關(guān),跟它在哪定義(創(chuàng)建)有關(guān)系,在哪創(chuàng)建,它的上級作用域就是誰

簡而言之:上級作用域和函數(shù)在哪執(zhí)行無關(guān),和函數(shù)在哪定義有關(guān)

var a=2;

function fn(){

? console.log(a);

}

fn();

function sum(){

? var a=3;

? fn();

}

sum();

?1、作用域練習(xí)題

var n=10;

function fn(){

? ? var n=20;

? ? function f(){

? ? ? ? n++;

? ? ? ? console.log(n);

? ? }

? ? f();

? ? return f;

}

var x=fn();

x();

x();

console.log(n);

答案】:打?。?1、22、23、10

2、堆棧內(nèi)存小科普

GC 即 Garbage Collection 垃圾回收

1)js中的內(nèi)存分為:堆內(nèi)存和棧內(nèi)存

??【堆內(nèi)存】:只要用來存儲引用數(shù)據(jù)類型的值(對象存的是鍵值對,函數(shù)存的是字符串)

??【棧內(nèi)存】:供js運(yùn)行的環(huán)境(函數(shù)執(zhí)行)

2) 堆棧內(nèi)存的釋放問題

我們每次給變量存值或者執(zhí)行函數(shù)的時(shí)候都會占用內(nèi)存空間,如果一直這樣下去,日積月累,電腦總會裝不下 的,所以內(nèi)存是需要釋放的。

①堆內(nèi)存的釋放:

常見的瀏覽器釋放方式主要有以下兩種:

谷歌瀏覽器是標(biāo)記清除(Mark-Sweep),此算法分為 標(biāo)記 和 清除 兩個(gè)階段,標(biāo)記階段即為所有活動(dòng)對象做上標(biāo)記,清除階段則把沒有標(biāo)記(也就是非活動(dòng)對象)銷毀

ie和火狐等瀏覽器是采用計(jì)數(shù)方法,當(dāng)前作用域中如果一個(gè)空間地址被占用一次,就會累加一,如果減少一次占用就會減1,直到0的時(shí)候,說明已經(jīng)沒有被占用了,就釋放了。

當(dāng)聲明了一個(gè)變量并且將一個(gè)引用類型賦值給該變量的時(shí)候這個(gè)值的引用次數(shù)就為 1

如果同一個(gè)值又被賦給另一個(gè)變量,那么引用數(shù)加 1

如果該變量的值被其他的值覆蓋了,則引用次數(shù)減 1

當(dāng)這個(gè)值的引用次數(shù)變?yōu)?0 的時(shí)候,說明沒有變量在使用,這個(gè)值沒法被訪問了,回收空間,垃圾回收器會在運(yùn)行的時(shí)候清理掉引用次數(shù)為 0 的值占用的內(nèi)存

?堆內(nèi)存釋放:讓所有引用這個(gè)堆內(nèi)存的變量賦值為null,堆內(nèi)存地址不在被占用,瀏覽器在空閑的時(shí)候就會把堆內(nèi)存 釋放

let x = 5;

let fn = function (x) {

? return function (y) {

? ? console.log(y + (++x));

? }

}

let f = fn(6);

f(7);

fn(8)(9);

f(10);

console.log(x);

================

let a = 0, b = 0;

let A = function (a) {

? A = function (b) {

? ? alert(a + b++)

? }

? alert(a++)

}

A(1);

A(2);

六、閉包

function fn(i){

? ? return function (n){

? ? ? console.log(n+(++i));

? ? }

}

var f=fn(2);

f(3);

fn(5)(6);

fn(7)(8);

f(4)

1、閉包的作用:●【保護(hù)】:保護(hù)里面的私有變量不受外界的干擾.?●【保存】:形成不銷毀的作用域,可以把里面的變量保存下來,

①閉包在實(shí)戰(zhàn)中的應(yīng)用【1】閉包之私有變量的保護(hù)應(yīng)用【jquery】?通過window添加屬性暴漏到全局

(function(){

? ? function jquery(){

? ? }

? ? //把jquer 這個(gè)方法通過window添加屬性暴漏到全局

? ? window.jquery=window.$=jquery;

})()

在使用的時(shí)候: jquery() 或者$()

【2】私有變量之保存機(jī)制-選項(xiàng)卡案例再憶【選項(xiàng)卡案例原版】

<!DOCTYPE html>

? ? ? ? ul>li {

? ? ? ? ? ? width: 100px;

? ? ? ? ? ? height: 40px;

? ? ? ? ? ? line-height: 40px;

? ? ? ? ? ? text-align: center;

? ? ? ? ? ? border: 1px solid #333;

? ? ? ? ? ? margin-right: 10px;

? ? ? ? ? ? display: inline-block;

? ? ? ? ? ? position: relative;

? ? ? ? ? ? top: 1px;

? ? ? ? }

? ? ? ? .main>div {

? ? ? ? ? ? height: 300px;

? ? ? ? ? ? line-height: 300px;

? ? ? ? ? ? border: 1px solid #333;

? ? ? ? ? ? text-align: center;

? ? ? ? ? ? display: none;

? ? ? ? }

? ? ? ? .main li.current {

? ? ? ? ? ? background: darkcyan;

? ? ? ? ? ? border-bottom-color: darkcyan;

? ? ? ? }

? ? ? ? .main div.current {

? ? ? ? ? ? background: darkcyan;

? ? ? ? ? ? display: block;

? ? ? ? }

? ? </style>

</head>

<body>

? ? <div class="main" id="main">

? ? ? ? <ul>

? ? ? ? ? ? <li class="current">音樂</li>

? ? ? ? ? ? <li>電視</li>

? ? ? ? ? ? <li>綜藝</li>

? ? ? ? </ul>

? ? ? ? <div class="current">音樂內(nèi)容</div>

? ? ? ? <div>電視內(nèi)容</div>

? ? ? ? <div>綜藝內(nèi)容</div>

? ? </div>

</body>

</html>

<script>

? ? var main = document.getElementById("main");

? ? var lis = main.getElementsByTagName("li");

? ? var divs = main.getElementsByTagName("div");

? ? for (var i = 0; i < lis.length; i++) {

? ? ? ? lis[i].index = i;

? ? ? ? lis[i].onclick = function () {

? ? ? ? ? ? var index = this.index;

? ? ? ? ? ? change(index);

? ? ? ? }

? ? }

? ? function change(index) {

? ? ? ? for (var i = 0; i < lis.length; i++) {

? ? ? ? ? ? lis[i].className = "";

? ? ? ? ? ? divs[i].className = "";

? ? ? ? }

? ? ? ? lis[index].className = "current";

? ? ? ? divs[index].className = "current";

? ? }

</script>

②、回憶當(dāng)初里面的i 為啥是3

1、【作用域方式去思考】當(dāng)我們觸發(fā)點(diǎn)擊事件的時(shí)候,這個(gè)函數(shù)執(zhí)行,形成私有作用域, 在這個(gè)私有作用域里面,并沒有私有變量i,所以就會向上級作用域進(jìn)行查找,此時(shí)上級作用域就是全局作域里面的i,當(dāng)我們發(fā)生點(diǎn)擊時(shí)間的時(shí)候,此時(shí)for 循環(huán)早已完成,i早就是3

作用域:●window 全局作用域●函數(shù)執(zhí)行形成私有作用域

for (var i = 0; i < lis.length; i++) {

? ? ? ? lis[i].onclick = function () {

? ? ? ? ? // 這里的i為啥會變成3?當(dāng)我們觸發(fā)點(diǎn)擊事件的時(shí)候,這個(gè)函數(shù)執(zhí)行,形成私有作用域,

? ? ? ? ? // 在這個(gè)私有作用域里面,并沒有私有變量i,所以就會向上級作用域進(jìn)行查找,此時(shí)上級作用域就是

? ? ? ? ? // 全局作用域里面的i,當(dāng)我們發(fā)生點(diǎn)擊時(shí)間的時(shí)候,此時(shí)for 循環(huán)早已完成,i早就是3

? ? ? ? ? ? change(i);

? ? ? ? }

? ? }

2、【同步異步事件去思考】【同步事件】:當(dāng)一件事件做完之后,再繼續(xù)下一件事情【異步事件】:當(dāng)一件事件還沒有做完,不再等待,直接去做下一個(gè)事件。所有的事件都是異步編程?!九e列子】:比如你想吃著泡面去刷劇。你先打開開關(guān)去燒水,這個(gè)時(shí)候我就站在那等,直到水燒好了,把面泡好了,我再去看電視。這個(gè)是同步事件?。 我把燒水的開關(guān)打開,我就去刷劇了,一邊刷劇,一邊等著燒水,水燒好了,我再去關(guān)掉.... 這個(gè)就是異步事件?

for (var i = 0; i < lis.length; i++) {

? ? ? ? lis[i].onclick = function () {

? ? ? ? ? ? change(i);

? ? ? ? }

? ? }


for循環(huán)是同步事件,執(zhí)行完i=3;點(diǎn)擊事件是異步事件,當(dāng)我們點(diǎn)擊頁面上的按鈕的時(shí)候,這個(gè)for循環(huán)早已經(jīng)執(zhí)行完了。

lis[0].onclick = function () {

? ? ? ? ? ? change(i);

}

lis[1].onclick = function () {

? ? ? ? ? ? change(i);

}

lis[2].onclick = function () {

? ? ? ? ? ? change(i);

}

3、解決方法:

1)自定義屬性

2)閉包

for (var i = 0; i < lis.length; i++) {

? ? // 之前i找到的上級作用域是window,現(xiàn)在我們手動(dòng)增加一層作用域,用一個(gè)閉包的形式,里面把點(diǎn)擊事件賦值

? ? //給了外面的元素,被占用,形成不銷毀的作用域.n是私有變量,當(dāng)點(diǎn)擊頁面上的元素的時(shí)候,就會找閉包作用域

? ? //中的私有變量n


? ? (function(n){

? ? ? lis[n].onclick = function () {

? ? ? ? ? ? change(n);

? ? ? ? }

? ? })(i)


? ? }

=======================================

for (var i = 0; i < lis.length; i++) {

//每次for循環(huán),就給li綁定一個(gè)點(diǎn)擊事件,并且點(diǎn)擊的事件的值是return里面的小函數(shù),形成了不銷毀的作用域

當(dāng)我們點(diǎn)擊li的時(shí)候,里面的小函數(shù)就會執(zhí)行,變量i就是自執(zhí)行函數(shù)里面的私有變量

? ? ? ? ? ? lis[i].onclick=(function(i){

? ? ? ? ? ? ? ? return function(){

? ? ? ? ? ? ? ? ? ? change(i);

? ? ? ? ? ? ? ? }

? ? ? ? ? ? })(i)? ? ?

? ? }

3)let

? for (let i = 0; i < lis.length; i++) {

? ? ? ? lis[i].onclick=function(){

? ? ? ? ? ? change(i);

? ? ? ? }

? ? }?

塊級作用域:在es6語法中,用{} 括起來的,里面有const 或者let 都是塊級作用域:●在塊級作用域外面訪問不到里面的變量●塊級作用域也有作用域鏈(塊級作用域也可以進(jìn)行嵌套)

{

? ? console.log(a);

? ? let a=8;

? ? console.log(a);

}

console.log(a);

========================================

{

? ? let a=2;

? ? {

? ? ? ? let b=3;

? ? ? ? console.log(a);

? ? }

}

console.log(a);

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容