一、作用域
作用域:變量生效(可以被訪問)的范圍,用來控制變量的可見性和生命周期。
全局作用域:不單獨(dú)屬于某一個函數(shù)的變量就是一個全局變量,在任何位置(普通函數(shù)、構(gòu)造函數(shù)、字面量對象中)都可以訪問到這個變量。
局部作用域:在函數(shù)中使用var定義的變量是局部變量。
注意:在js中塊級(也就是大括號)的概念并不像其他語言那樣完善(ECMA6中完善了),在其他語言中,一對大括號中的變量就是一個局部變量,但是在js中只有在一個函數(shù)中定義的變量才是一個局部變量。
作用域鏈:在多級作用域嵌套時,如果當(dāng)前作用域內(nèi)找不到所需要的變量,則向父級作用域?qū)ふ?,一直找到全局作用域,但不會向下尋找?/p>
變量提升:
var a = 12;
function fun1() {
alert("1"+a); // 未定義,內(nèi)部定義了a,變量提升,并未賦值,所以a是未定義
var a = 23;//由于這行代碼導(dǎo)致變量提升了
alert("2"+a);
a = 14;
}
fun1();
alert("3"+a);
面試題:
var a = 1;
for (var i = 0; i < 5; i++) {
var a = i;
}
// a = 4
function fn1() {
alert(a); // undefine
var a = 2;
alert(a); // 2
}
alert(fn1()); //undefine
alert(a); // 4
alert(abc(2)); // 報錯
二、匿名函數(shù)
匿名函數(shù):沒有函數(shù)名字,只有函數(shù)體的函數(shù)叫匿名函數(shù)。
區(qū)分:具名函數(shù),有函數(shù)名的函數(shù)。
var fn=function (){
alert('hello');
}
匿名函數(shù)使用場景:
1、通過DOM0級給標(biāo)簽添加事件函數(shù),這些函數(shù)全是匿名函數(shù)。
事件函數(shù):通過用戶事件觸發(fā)執(zhí)行的函數(shù),比如某個按鈕的click事件。
2、把匿名函數(shù)當(dāng)做另一個函數(shù)的參數(shù)傳遞,比如:定時器。
3、使用匿名函數(shù)模擬塊級作用域。
(function(){
for(var i=0;i<4;i++){
}
})();
4、匿名函數(shù)充當(dāng)閉包
三、閉包
閉包:在函數(shù)執(zhí)行完畢后,向外返回另一個函數(shù)。在返回的函數(shù)中,使用到一個局部變量,因?yàn)槌薪舆@個返回函數(shù)的變量是全局的,為了保證全局變量正常訪問,所以全局變量中所引用的局部變量生命周期也被無限的延長。
閉包能夠讀取其他函數(shù)內(nèi)部變量。
function fn1(){
var i=12;
function fn2(){
console.log(i);
return i+3
}
return fn2;
}
var result=fn1(); //得到fn2函數(shù)
console.log(result());//得到15
//fn1是fn2的?函數(shù),?fn2被賦給了?個全局變量,這導(dǎo)致fn2始終在內(nèi)存中,
//?fn2的存在依賴于fn1,因此fn1也始終在內(nèi)存中,不會在調(diào)?結(jié)束后,被垃
//圾回收機(jī)制(garbage collection)回收。
閉包的用途:
1、可以在全局作用域讀取函數(shù)內(nèi)部的變量。
2、讓這些局部變量的值始終保持在內(nèi)存中。
3、利用閉包解決使用循環(huán)添加事件的BUG。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<script type="text/javascript">
window.onload=function(){
var btnArr=document.querySelectorAll('.btn');
for(var i=0;i<btnArr.length;i++){
(function(num){
//num變量是函數(shù)的形參,函數(shù)在每次執(zhí)行時都會重新開辟內(nèi)存空間來存放這個形參
//所以給標(biāo)簽添加的點(diǎn)擊事件中使用到的num變量都是獨(dú)一無二的,num變量中的
//值是當(dāng)前遍歷標(biāo)簽時的下標(biāo)值
btnArr[num].onclick=function(){
//匿名函數(shù)在執(zhí)行時,給事件綁定了這個函數(shù),函數(shù)中操作了一個局部變量。該
//函數(shù)執(zhí)行時一定是在全局變量作用域中執(zhí)行的,所以為了保證在全局作用域中
//正常觸發(fā)該函數(shù),num變量也就變成了全局變量。
alert(num+1);
}
})(i);
}
}
</script>
</head>
<body>
<button class="btn">1</button>
<button class="btn">2</button>
<button class="btn">3</button>
<button class="btn">4</button>
</body>
</html>
4、閉包解決下拉選擇框的BUG
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
*{
margin: 0;
padding: 0;
}
ul{
width: 500px;
margin: auto;
margin-top: 20px;
}
li{
float: left;
list-style: none;
width: 100px;
height: 21px;
background: pink;
text-align: center;
cursor: pointer;
}
div{
display: none;
background: greenyellow;
}
.active{
background: indianred;
}
</style>
<script type="text/javascript">
window.onload=function(){
var lis=document.querySelectorAll('li');
var divs=document.querySelectorAll('div');
for(var i=0;i<lis.length;i++){
(function(indexs){
lis[indexs].onmouseover=function(){
lis[indexs].className='active';
divs[indexs].style.display='block';
}
})(i);
(function(indexs){
lis[indexs].onmouseout=function(){
divs[indexs].style.display='none';
lis[indexs].className='';
}
})(i);
}
}
</script>
</head>
<body>
<ul>
<li>
<span>
菜單一
</span>
<div>
<p>菜單一內(nèi)容</p>
<p>菜單一內(nèi)容</p>
<p>菜單一內(nèi)容</p>
<p>菜單一內(nèi)容</p>
</div>
</li>
<li>
<span>
菜單二
</span>
<div>
<p>菜單二內(nèi)容</p>
<p>菜單二內(nèi)容</p>
<p>菜單二內(nèi)容</p>
<p>菜單二內(nèi)容</p>
</div>
</li>
<li>
<span>
菜單三
</span>
<div>
<p>菜單三內(nèi)容</p>
<p>菜單三內(nèi)容</p>
<p>菜單三內(nèi)容</p>
<p>菜單三內(nèi)容</p>
</div>
</li>
<li>
<span>
菜單四
</span>
<div>
<p>菜單四內(nèi)容</p>
<p>菜單四內(nèi)容</p>
<p>菜單四內(nèi)容</p>
<p>菜單四內(nèi)容</p>
</div>
</li>
<li>
<span>
菜單五
</span>
<div>
<p>菜單五內(nèi)容</p>
<p>菜單五內(nèi)容</p>
<p>菜單五內(nèi)容</p>
<p>菜單五內(nèi)容</p>
</div>
</li>
</ul>
</body>
</html>