提供一種間接的方式可以訪問到函數內部的數據(變量)javascript
在函數內部建立函數(內部函數),在這個內部函數中,能夠操做外部函數中的變量
01 在函數(外部)中建立函數(內部函數),在該函數(內部函數)中操做外部函數中的變量
02 在外部函數中,把內部函數做爲返回值返回
03 調用外部函數,並接收其返回值(是一個函數)
04 調用接收到的返回值(內部函數),來間接的操做外部函數中的變量segmentfault
function inner(){ var num = 10; return num; }; var fn1 = inner(); var fn2 = inner(); console.log(fn1); //10 console.log(fn2); //10
其實每個函數體就是一個閉包,但該博文所指的閉包並無這麼簡單。這裏的inner儘管也能從外部讀取inner函數的局部變量,但fn1,fn2是經過各開闢一個內存空間去存儲num的值,就至關於fn1=new Number(10),fn2 = new Number(10),這樣不能修改inner裏面的變量值,並不能達到獲取內部變量和修改內部變量,其次咱們想要獲得的是將inner內部的變量暴露出外部使用,這明顯fn1,fn2各玩各的。數組
需求:想要在函外面(另一個函數中)訪問某一個函數內部的局部變量
閉包:在函數內部使用函數
閉包鏈式做用域:一個子對象能夠沿着他的父對象訪問父對象的全部變量,反之,則不行多線程
function sum() { var a = 10; function showMessage() { //根據鏈式做用域在這個函數內部能夠訪問變量a alert(a); } return showMessage; } //調用sum var showMes = sum();//調用完成後,正常狀況局部變量應該被銷燬,但最終沒有 showMes();
//經過上面的使用,局部變量a沒有銷燬
//閉包的做用:1.延長局部變量的生命週期
//若是有不少局部變量,那麼延長他們的生命週期,會大量佔用內存,慎重使用閉包
1、獲取單個數據(考慮賦值)併發
function func() { var num = 123; return function (a) { if (a !== undefined) //容錯操做 { num = a; } return num; } } var f1 = func(); var x = f1(456); //經過參數修改內部變量 var y = f1(); console.log(x); //456 console.log(y); //123
function func() { var name = "張學友"; var age = 40; return [ function getName() { return name; }, function getAge() { return age; } ] } var foo = func(); console.log(foo[0]()); //張學友 console.log(foo[1]()); //40
說明:上面的代碼可以知足返回多個變量值的需求,可是要數組操做的方式並不常見,且和使用習慣不符合。函數
利用對象返回並設置對個變量值spa
function foo() { var name = "張學友"; var age = 45; return { getName:function () { return name; }, getAge:function () { return age; }, setName:function (nameValue) { name = nameValue; }, setAge:function (ageValue) { age = ageValue; } } } var func = foo(); console.log(func.getName()); //張學友 console.log(func.getAge()); //45 func.setName("張三"); func.setAge(30); console.log(func.getName()); //張三 console.log(func.getAge()); //30
1、在函數中使用var
操做符定義一個變量,那麼當這個函數執行完畢以後,這個變量也會被銷燬(也有的狀況下不會,好比閉包,後面會說明),而全局變量會一直存在。因此在咱們寫代碼時,儘可能少的使用全局變量,濫用全局變量,簡直就是一個會使人噁心的習慣,由於它會帶來不少沒必要要的麻煩。線程
有兩個網址都是第一個解釋做用域和閉包,第二個解釋閉包,做用域鏈,和垃圾回收機制
***************************************************************************
進程指的是系統中正在運行的一個應用程序。
線程:一個進程中能夠有一個或多個線程,線程是CPU調度的最小單位,是真正執行任務的。
多線程:一箇中可能有多條線程,多條線程之間併發的執行多個不一樣的任務。
單線程:一個進程中只有一條線程,即同一時間只能執行一個操做,只能幹一件事情。
javascript是單線程的:
js中的線程主要處理三塊任務:(由上到下優先級處理)
01 渲染任務
02 js的代碼執行任務
03 js中的事件處理任務(如setTimeOut方法)
一、DOM操做
//函數定義和調用一塊兒使用, //形式:(function sum(){})(),簡化成(函數的定義)(函數的調用); var btns = document.getElementsByTagName('button'); //遍歷按鈕 for(var i= 0;i < btns.length;i++){ // btns[i].onclick = (function (a) { // alert(a); // })(i) (function (a) { btns[a].onclick = function () { alert(a); } })(i) ; }
當點擊按鈕的時候,須要輸出i值,那麼這個函數首先回會去尋找本身函數內部有沒有對應的i值,若是有就直接訪問這個i值,若是沒有就要沿着閉包鏈式做用域去他的父對象中尋找對應變量i, 因此會去for循環中尋找i值,可是注意函數執行實在按鈕點擊的時候才觸發,按鈕點擊是一個延遲操做,當按鈕點擊的時候for中的i值執行已經完畢,並且值是循環長度,因此咱們獲取的值5;(註釋部分)
經過閉包每一次循環都會保存i值,在彈出i值所在的函數中放置一個變量,那麼就能夠實現輸出0-4;
*************************************************************************************************
二、定時器中閉包的使用
for(var i = 0; i < 4; ++i){ // (function(a){ // setInterval(function(){ // console.log(a); // },0) // })(i) setInterval((function (a) { console.log(a) })(i),0); }
註釋部分是出現無序的數字,而且定時器沒有中止,反之第二種寫法能夠得到想要效果
其餘:函數名函數只能函數體內調用:
var a = function b(){ console.log(1); }; a(); //1 b(); //not defined (只能在局部使用,相似閉包)
var a = function b(){ console.log(1); console.log(b); }(); // 1 function b(){...}