一個公司備案兩個網站seo內容優(yōu)化是什么
序言
學習JavaScript切勿好高騖遠。正所謂貪多嚼不爛,前端標準和工具這幾年的飛速發(fā)展,以及不時冒出的“新鮮玩意”讓眾多前端從業(yè)者驚呼:“學不動啦學不動啦!學習速度跟不上技術發(fā)展速度!我感到手忙腳亂、力不從心……"如果你有以上“癥狀”,請勿著急,這不過是你內心不安造成的。你為何追新?你又何苦追新?在根基不牢的情況下,就算蓋樓蓋到18層,再往上堆一塊磚,都可能導致大樓坍塌!這結果絕非你預期。所以,此時你應該沉下心來苦練基礎。而非死鉆牛角尖。硬要及時掌握那些業(yè)界最新冒出來的“玩意兒”對你無益處。
前言
我們知道,作用域鏈查找標識符的順序是從當前作用域開始一級一級往上查找。因此,通過作用域鏈,JavaScript函數內部可以讀取函數外部的變,但反過來,函數的外部通常則無法讀取函數內部的變量。在實際應用中,有時需要真正在函數外部訪問函數內部的局部變量,此時最常用的方法就是使用閉包。
那么什么是閉包?所謂閉包,就是 同時含有對函數對象以及作用域對象引用的對象。閉包主要是用來獲取作用域鏈或原型鏈上的變量或值。創(chuàng)建閉包最常見的方式是在一個函數中聲明內部函數(也稱嵌套函數),并返回內部函數。此時在函數外部就可以通過調用函數得到內部函數。雖然按照閉包的概念,所有訪問了外部變量的JavaScript函數都是閉包。但我們平常絕大部分時候所謂的閉包其實指的就是內部函數閉包。閉包可以將一些數據封裝私有屬性以確保這些變量的安全訪問,這個功能給應用帶來了極大的好處。需要注意的是,閉包如果使用不當,也會帶來一些意想不到的問題。下面就通過幾個示例來演示一下閉包的創(chuàng)建、使用和可能存在的問題及其解決方法。示例1: 創(chuàng)建閉包。
html>
<html>
<head>
?<title>閉包title>
head>
<body>
<script?type="text/javascript">function?outer(argument)?{var?b=0;return?function?inner?(){
???b++;console.log("內部的b:"+b);
??}
?}var?func?=??outer();//1?通過外部變量引用函數返回的內部函數console.log(func);//2?輸出內部函數定義代碼
?func();//3?通過閉包訪問局部變量b,此時b=1;console.log("外部函數中b:"+b);?//4 出錯,報引用錯誤。script>
body>
html>
上述代碼在外部函數 outer
中聲明內部函數 inner
,并返回內部函數,同時在 outer
函數外面,變量 func
引用了 outer
函數返回的內部函數,所以內部函數 inner
是一個閉包。該閉包訪問了外部函數的局部變量 b
。1處代碼通過調用外部函數返回內部函數并賦給外部變量 func
,使 func
變量引用內部函數,所以2處代碼將輸出 inner
函數的整個定義代碼。3處代碼通過對外部變量 func
添加一對小括號后調用內部函數 inner
,從而達到在函數外部訪問局部變量 b
的目的。執(zhí)行4處的代碼時將報 ReferenceError
錯誤,因為 b
是局部變量,不能在函數外部直接訪問局部變量。我們知道函數執(zhí)行完畢時,運行期上下文會被銷毀,與之關聯(lián)的活動對象也會隨之銷毀,因此離開函數后,屬于活動對象的局部變量將不能被訪問。但是為什么上述示例中的 outer
函數執(zhí)行完后,它的局部變量還能被內部函數訪問呢?這個問題我們可以用作用域鏈來解釋。當執(zhí)行1處代碼調用 outer
函數時,JavaScript引擎會創(chuàng)建 outer
函數執(zhí)行上下文的作用域鏈,這個作用域鏈包含了 outer
函數執(zhí)行時的活動對象,同時JavaScript引擎也會創(chuàng)建一個閉包,而閉包因為需要訪問 outer
函數的局部變量,因而其作用鏈也會引用 outer
的活動對象。這樣,當 outer
函數執(zhí)行完后,它的作用域對象因為有閉包的引用而依然存在,固而可以提供給閉包訪問。上述示例中的內部函數雖然有名稱,但在調用是并沒有用到這個名稱,所以內部函數的名稱可以缺省,即可以將內部函數修改為匿名函數,從而簡化代碼。 示例2: 經典閉包問題
html>
<html>
<head>
<title>經典閉包問題title>
<script?type="text/javascript">window.onload=function?()?{var?abtn?=?document.getElementsByTagName("button");for?(var?i?=?0;?i???abtn[i].onclick=function(){
????alert("按鈕"+(i+1));
???}
??}
?}script>
head>
<body>
<button>按鈕1button>
<button>按鈕2button>
<button>按鈕3button>
body>
html>
該示例期望實現的功能是,單擊每個按鈕時,在彈出的警告對話框中顯示相應的標簽內容,即單擊3個按鈕時將分別顯示“按鈕1”、“按鈕2”、“按鈕3”。上述示例頁面加載完后觸發(fā)窗口加載事件,從而執(zhí)行外層匿名函數,外層匿名函數執(zhí)行完循環(huán)語句后使活動對象中的局部變量i的值修改為 3
。外層匿名函數執(zhí)行完后撤銷,但由于其活動對象中的 abtn
和 i
變量被內層匿名函數引用,因而外層匿名函數的活動對象仍然存在堆中供內層匿名函數訪問。每執(zhí)行一次循環(huán)都將創(chuàng)建一個閉包,這些閉包都引用了外層匿名函數的活動對象,因而訪問變量i時都得到 3
,這樣最后的結果是單擊每個按鈕,在警告對話框中顯示的文字都是“按鈕4” (i+1=3+1)
,與期望的功能不一致。造成這個問題的原因是,每個閉包都引用一個變量,如果我們使不同的閉包引用不同的變量,就可以實現輸出的結果不一樣。這個需求可使用多種方法實現,在此介紹使用立即調用函數表達式( IIFE
)和ES6中的 let
創(chuàng)建塊即變量的方法。 IIFE
指的是:在定義函數的時候直接執(zhí)行,即此時函數定義變成了一個函數調用的語句。要讓一個函數定義語句變成函數調用語句,就需要將定義語句變?yōu)橐粋€函數表達式,然后在該表達式后面再加一對圓括號()即可。將函數定義語句變?yōu)橐粋€函數表達式的最常用方法就是將整個定義語句放在一對圓括號中。 1、IIFE中的函數為一個匿名函數
(function(name){
?console.log("hello,"+name);
})("maomin");
JS引擎執(zhí)行上述代碼時,會調用匿名,同時將后面圓括號中的參數 maomin
傳給 name
虛參,結果得到:"hello,maomin"。 2、IIFE中的函數為一個有名函數
(function?func?(name)?{
?console.log("I?am"+name);
})("maomin")
上述代碼跟匿名函數完全一樣。
示例3: 使用立即調用函數表達式解決經典閉包問題
html>
<html>
<head>
?<title>使用立即調用表達式解決經典閉包問題title>
?<script?type="text/javascript">window.onload=function?()?{var?abtn?=?document.getElementsByTagName("button");for?(var?i?=?0;?i???(function(num){
????abtn[num].onclick=function(){
????????alert("按鈕"+(num+1));
???????}
???})(i)
??}
?}script>
head>
<body>
<button>按鈕1button>
<button>按鈕2button>
<button>按鈕3button>
body>
html>
上述代碼中第二個匿名函數為 IIFE
,每次調用該匿名函數時將生成一個對應該函數的活動對象。該對象中包含可一個函數參數,值為當次循環(huán)的循環(huán)變量值。上述示例中,IIFE共執(zhí)行了 3
次,因而共生成了 3
個活動對象,活動對象中包含的參數值分別為 0
、 1
和 2
,依次對應 IIFE
的 3
次執(zhí)行。每次執(zhí)行 IIFE
時,將會產生一個閉包,該閉包會引用對應按鈕索引順序執(zhí)行 IIFE
的活動對象,而閉包引用的活動對象中的參數值剛好等于按鈕的索引值,因而單擊 3
個按鈕將在彈出的警告框中分別顯示"按鈕1"、“按鈕2”、“按鈕3”。 示例4:使用ES6中的let關鍵字創(chuàng)建塊級變量解決經典閉包問題
html>
<html>
<head>
?<title>使用ES6中的let關鍵字解決經典閉包問題title>
?<script?type="text/javascript">window.onload=function?()?{var?abtn?=?document.getElementsByTagName("button");for?(let?i?=?0;?i???abtn[i].onclick=function(){
????alert("按鈕"+(i+1));
???}
??}
?}script>
head>
<body>
<button>按鈕1button>
<button>按鈕2button>
<button>按鈕3button>
body>
html>
上述代碼中循環(huán)變量使用 let
聲明,因而每次循環(huán)時,都會產生一個新的塊級變量,所以在頁面加載完,執(zhí)行外層匿名函數時產生的活動對象中包含了 3
個對應循環(huán)變量的塊級變量,變量值分為 0
、 1
和 2
。每執(zhí)行一次循環(huán),將會產生一個閉包,該閉包中的變量 i
會引用外層匿名函數的活動對象對應按鈕索引的塊級變量,因而單擊 3
個按鈕時將在彈出的警告對話框中分別顯示“按鈕1”、“按鈕2”、“按鈕3”。 下一期更精彩
結語
歡迎關注我的公眾號,回復關鍵詞【電子書】,即可獲取近十幾本前端熱門電子書。更有精品文章等著你哦。你還可以加我微信,我拉攏了很多IT大佬,創(chuàng)建了一個技術交流、文章分享群,歡迎你的加入。
作者:Vam的金豆之路
主要領域:前端開發(fā)
我的微信:maomin9761
微信公眾號:前端歷劫之路
![]()