一、作用域:
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);