日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

Javascript的作用域,作用域链,闭包

發(fā)布時(shí)間:2025/7/14 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Javascript的作用域,作用域链,闭包 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

1,作用域和作用域鏈概念

? ? ? 作用域就是變量與函數(shù)的可訪問范圍,即作用域控制著變量與函數(shù)的可見性和生命周期。在JavaScript中,變量的作用域有全局作用域和局部作用域兩種。

? ? ? ?1.1 全局作用域,在代碼中任何一個(gè)地方都能訪問的對(duì)象擁有全局作用域,一般來說以下幾種情形擁有全局作用域:

? ? ? ? ? ? ? 最外層函數(shù)和在最外層函數(shù)外面定義的變量擁有全局作用域;

? ? ? ? ? ? ? 所有未定義直接賦值的變量自動(dòng)聲明為擁有的全局作用域;

? ? ? ? ? ? ? 瀏覽器環(huán)境中,所有windows對(duì)象的屬性擁有全局作用域;

? ? ? ?1.2 局部作用域,局部作用域一般只是固定的代碼片段內(nèi)可訪問到,在JS中一般是函數(shù)作用域;

? ? ? ?1.3 作用域鏈,當(dāng)代碼在一個(gè)環(huán)境中執(zhí)行是,會(huì)常見變量對(duì)象的一個(gè)作用域鏈,作用域鏈的作用是保證隊(duì)執(zhí)行環(huán)境有權(quán)訪問的所有變量和函數(shù)的有序訪問。全局執(zhí)行環(huán)境的變量對(duì)象始終都是作用域鏈中最后一個(gè)對(duì)象。

2,作用域規(guī)則

? ? ? 作用域有一套根據(jù)名稱查找變量的規(guī)則。

? ? ? ?實(shí)際情況中,通常需要同事顧及幾個(gè)作用域,當(dāng)一個(gè)塊或函數(shù)嵌套在另一塊或函數(shù)中時(shí),就發(fā)生了作用域的嵌套。因此,在當(dāng)前作用域中無法找到某個(gè)變量時(shí),引擎就會(huì)在外層嵌套的作用域中舉行查找,直到找到該變量,或抵達(dá)最外層的作用域(也就是全局作用域)為止,但不能通過向下搜索作用域鏈而進(jìn)入另一個(gè)執(zhí)行環(huán)境。

? ? ? ?var a = 1;

? ? ? ?function f() {

    var a =2;

? ? ? ? ? ? ? var b =3;

? ? ? ? ? ? ? console.log(a);? ? ? ?

  }? ? ? ? ? ??

  f();? //2

? ? ? ?a;? ?//1

? ? ? ?b;? // 報(bào)錯(cuò)

3,作用域工作模型

? ? ? JS作用域的工作模型是詞法作用域,詞法作用域就是定義在詞法階段的作用域。換句話說,詞法作用域是由你在寫代碼時(shí)將變量和塊作用域?qū)懺谀睦飦頉Q定的,因此當(dāng)詞法分析器處理代碼時(shí)會(huì)保持作用域不變(大部分情況下是這樣的)。

function f1() {
alert(a)
}
f1(); function f2() {
var a = 2;
f1();
}
var a =1;
f1(); //1
f2(); //1,因?yàn)閒1定義時(shí)的作用域的a為全局的a=1,說明函數(shù)不管在哪里調(diào)用都是基于它定義時(shí)的作用域;
上面代碼中,當(dāng)函數(shù)執(zhí)行時(shí),會(huì)先查找所需的變量,作用域查找會(huì)在找到第一個(gè)匹配的標(biāo)識(shí)符時(shí)停止,在多層的嵌套作用域中可以定義同名的標(biāo)識(shí)符,這叫做"遮蔽效應(yīng)"(內(nèi)部的標(biāo)識(shí)符"遮蔽"了外部的標(biāo)識(shí)符)。拋開遮蔽效應(yīng),作用域查找始終從運(yùn)行是所處的最內(nèi)部作用域開始,逐級(jí)向外或者說向上進(jìn)行,直到遇見第一個(gè)匹配的標(biāo)識(shí)符為止。詞法作用域規(guī)則會(huì)使函數(shù)在查找變量時(shí)從函數(shù)內(nèi)部到函數(shù)使用時(shí)的作用域。所以無論函數(shù)在哪里被調(diào)用,也無論它如何被調(diào)用,它的詞法作用域都只由函數(shù)被聲明時(shí)所處的位置決定。

4,函數(shù)作用域

? ? ?JS中沒有塊級(jí)作用域,而是基于函數(shù)的作用域。函數(shù)作用域的含義是指,屬于這個(gè)函數(shù)的全部變量都可以在整個(gè)函數(shù)的范圍內(nèi)使用及復(fù)用(事實(shí)上在嵌套的作用域中也可以使用)

function d() {
if (true){
var a = 1;
}
console.log(a);
}
d(); //if不會(huì)生成新的作用域,所以a會(huì)泄露到當(dāng)前函數(shù)作用域
利用函數(shù)作用域的特點(diǎn),我們可以在任意代碼片段外部添加包裝函數(shù),可以將內(nèi)部的變量和函數(shù)定義"隱藏"起來,外部作用域無法訪問包裝函數(shù)內(nèi)部的任何內(nèi)容。 var a = 1;
(function f() {
var a = 2;
console.log(a); //2,利用函數(shù)作用域包裝代碼,使函數(shù)內(nèi)部變量不會(huì)被外部訪問
})();
console.log(a) var a =1;
function f() {
console.log(a); //underfined,不是1
var a = 2;
console.log(a); //2
}
f();
//上面代碼解析為
function f() {
var a;
console.log(a);
a = 2;
console.log(a);
}
var a;
a = 1;
f();
這個(gè)過程就是聲明提升。
聲明提升是因?yàn)镴S在執(zhí)行之前,會(huì)有一個(gè)預(yù)編譯過程,預(yù)編譯階段生成變量聲明和函數(shù)聲明,沒有初始化行為(賦值),匿名函數(shù)不參與預(yù)編譯只有在解釋執(zhí)行階段才會(huì)進(jìn)行變量初始化。
聲明提升原理
函數(shù)和變量的預(yù)解析特點(diǎn):
1.函數(shù)聲明會(huì)置頂
2.變量聲明也會(huì)置頂
3.函數(shù)聲明比變量聲明更置頂:(函數(shù)在變量上面)
4.變量和賦值語(yǔ)句一起書寫,在js引擎解析時(shí),會(huì)將其拆成聲明和賦值2部分,聲明置頂,賦值保留在原來位置
5.聲明過的變量不會(huì)重復(fù)聲明
  (function () {
a =1;
alert(window.a);
var a = 2;
alert(a);
})();
//上面代碼解析
(function () {
var a ; //a被提升到頂端后,a=1就不是隱式聲明全局變量了,而是給a賦值操作,所以window.a未聲明為undefined;
a =1;
alert(window.a); //undefined;
a = 2;
alert(a); //2
})();

5,欺騙函數(shù)作用域

? ? ?執(zhí)行環(huán)境類型中有兩種,全局和局部函數(shù),但可以用其他方法欺騙函數(shù)作用域。

? ? eval(),Javascript中的eval(...)函數(shù)可以接受一個(gè)字符串為參數(shù),并將其中的內(nèi)容視為好像在書寫是就存在于程序中這個(gè)位置的代碼并在運(yùn)行到此位置執(zhí)行參數(shù)代碼。因?yàn)閑val(...)可以在運(yùn)行期修改書寫期的詞法作用域,存在安全問題,不建議使用。

 

var a = 1;
function f() {
eval('var a =2;');//eval中的a遮蔽了全局中的a,讓作用域彈出的a改變了
console.log(a);
}
f();

? ?with,with語(yǔ)句接收一個(gè)對(duì)象參數(shù),表示with語(yǔ)句的對(duì)象作用域,with語(yǔ)句中的變量都會(huì)在這個(gè)指定的對(duì)象中查找。with會(huì)影響性能,不建議使用

 ?

window.onload = function () {
var a = 0;
var obj = {
a:1,
b:2
};
with(obj){
a = 2; //會(huì)在obj查找a屬性
}
console.log(obj.a); //2
console.log(a); //0
with(obj){
c = 3; //沒有在指定對(duì)象中找到c,非嚴(yán)格模式下,with會(huì)在全局隱式創(chuàng)建一個(gè)全局變量
}
console.log(obj.c); //undefined
console.log(c); //3
};

6,閉包

  閉包(closure)是Javascript語(yǔ)言的一個(gè)難點(diǎn),也是它的特色,很多高級(jí)應(yīng)用都要依靠閉包實(shí)現(xiàn)。

  ?閉包的特性:

? ? ? ? ? ? 1,函數(shù)嵌套函數(shù)

    2,函數(shù)內(nèi)部可以引用外部的參數(shù)和變量

 ? ? ? ? 3,參數(shù)和變量不會(huì)被垃圾回收機(jī)制回收

? ? ? ? 閉包的定義及其優(yōu)缺點(diǎn)

? ? ? ? ? ? ?閉包?是指有權(quán)訪問另一個(gè)函數(shù)作用域中的變量的函數(shù),創(chuàng)建閉包的最常見的方式就是在一個(gè)函數(shù)內(nèi)創(chuàng)建另一個(gè)函數(shù),通過另一個(gè)函數(shù)訪問這個(gè)函數(shù)的局部變量,閉包的缺點(diǎn)就是常駐內(nèi)存,會(huì)增大內(nèi)存使用量,使用不當(dāng)很容易造成內(nèi)存泄露。閉包是javascript語(yǔ)言的一大特點(diǎn),主要應(yīng)用閉包場(chǎng)合主要是為了:設(shè)計(jì)私有的方法和變量。一般函數(shù)執(zhí)行完畢后,局部活動(dòng)對(duì)象就被銷毀,內(nèi)存中僅僅保存全局作用域。但閉包的情況不同!

   嵌套函數(shù)的閉包? ?

  window.onload = function () {
function aaa() {
var a = 1;
return function(){
alert(a++)
};
}
var fun = aaa();
fun();// 1 執(zhí)行后 a++,,然后a還在~
fun();// 2
fun = null;//a被回收!!
  };
  //閉包會(huì)使變量始終保存在內(nèi)存中,如果不當(dāng)使用會(huì)增大內(nèi)存消耗。
  javascript的垃圾回收原理
(1)在JavaScript中,如果一個(gè)對(duì)象不再引用,那么這個(gè)對(duì)象就會(huì)被GC回收;
(2)如果兩個(gè)對(duì)象互相引用,而不再被第3者所引用,那么這兩個(gè)互相引用的對(duì)象也會(huì)被回收;
  使用閉包的好處:
1,希望一個(gè)變量長(zhǎng)期駐扎在內(nèi)存中
2,避免全局變量的污染
3,私有成員的存在
  一,全局變量的累加
  
  window.onload = function () {
  
    var a = 1;   function f() {
   a++;
   alert(a);
   }
   f(); //2
   f(); //3
}
二,局部變量
   window.onload = function () {
   function f() {
   var a = 1;
   a++;
   alert(a);
   }
   f();
   f();
//那么怎么才能做到變量a既是局部變量又可以累加呢? ?三,局部變量的累加
  window.onload = function () {
  function outer(){
  var x=10;
  return function(){ //函數(shù)嵌套函數(shù)
  x++;
  alert(x);
  }
    }
    var y = outer(); //外部函數(shù)賦給變量y;
    y(); //y函數(shù)調(diào)用一次,結(jié)果為11,相當(dāng)于outer()();
    y();
  }

   函數(shù)聲明于函數(shù)表達(dá)式

? ? ? ? ? ?在js中我們可以通過關(guān)鍵字function來聲明一個(gè)表達(dá)式:

? ? ? ? ? ?

  <script>
window.onload = function () {
  function abc(){
   alert(123);
  }
  abc();
  }
</script>
//我們也可以通過一個(gè)"()"來將這個(gè)聲明變成一個(gè)表達(dá)式:   window.onload = function () {
  (function abc(){
alert(123);
    })()
  }

? ? 四,模塊化代碼,減少全局變量的污染

? ??

  window.onload = function () {
   var abc = (function () { //abc為外部匿名函數(shù)的返回值
   var a = 1;
   return function () {
   a++;
   alert(a);
   }
   })();
   abc(); //2 ;調(diào)用一次abc函數(shù),其實(shí)是調(diào)用里面內(nèi)部函數(shù)的返回值
   abc(); //3
  }

? ? ?5,私有成員的存在

? ? ? ??

  window.onload = function () {
  var aaa = (function(){
   var a = 1;
   function bbb(){
   a++;
   alert(a);
   }
   function ccc(){
   a++;
   alert(a);
   }
   return {
   b:bbb, //json結(jié)構(gòu)
   c:ccc
   }
  })();
  aaa.b(); //2
  aaa.c() //3
  }

? ? 六,使用匿名函數(shù)實(shí)現(xiàn)累加

? ? ?

window.onload = function () {
function box(){
var age = 100;
return function(){ //匿名函數(shù)
age++;
return age;
};

}
var b = box();
alert(b());
alert(b()); //即alert(box()());
alert(b());
alert(b); // function () {
// age++;
// return age;
// }

b = null; //解除引用,等待垃圾回收
}

? ?七,在循環(huán)中直接找到對(duì)應(yīng)元素的索引

? ??

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
<title></title>
<script>
window.onload = function(){
var aLi = document.getElementsByTagName('li');
for (var i=0;i<aLi.length;i++){
aLi[i].onclick = function(){ //當(dāng)點(diǎn)擊時(shí)for循環(huán)已經(jīng)結(jié)束
alert(i);
};
}
}
</script>

</head>
<body>
<ul>
<li>123</li>
<li>456</li>
<li>789</li>
<li>010</li>
</ul>
</body>
</html>

? ? ?八,使用閉包改寫上面的代碼

? ??

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
<title></title>
<script>
window.onload = function(){
var aLi = document.getElementsByTagName('li');
for (var i=0;i<aLi.length;i++){
(function(i){
aLi[i].onclick = function(){
alert(i);
};
})(i);
}
};
</script>
</head>
<body>
<ul>
<li>123</li>
<li>456</li>
<li>789</li>
</ul>
</body>
</html>

轉(zhuǎn)載于:https://www.cnblogs.com/sjie0224/articles/8195570.html

總結(jié)

以上是生活随笔為你收集整理的Javascript的作用域,作用域链,闭包的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。