當前位置:首頁 » 文件傳輸 » 閉包外部不能訪問內部函數
擴展閱讀
webinf下怎麼引入js 2023-08-31 21:54:13
堡壘機怎麼打開web 2023-08-31 21:54:11

閉包外部不能訪問內部函數

發布時間: 2023-08-10 22:52:31

㈠ 初學js,一個很簡單的問題,為什麼函數外訪問不到函數內的全局變數

原因如下:

1、函數裡面的變數不是全局變數,函數內部聲明的變數一定是局部變數,所以想要外部訪問是無法直接訪問到的,請規范全局變數和局部變數的定義。

2、外部想要訪問函數內的變數可以採用閉包來實現,代碼實例如下:

functiontest(){
varx=10;
returnfunction(){
returnx;
}
}
//調用局部變數x,報錯未定義
alert(x);
//調用
vara=test();
alert(a());

這樣可以實現外部訪問內部變數。

㈡ js中作用域,閉包問題

這篇文章主要介紹了JavaScript中的作用域和閉包問題,是JS入門學習中的基礎知識,需要的朋友可以參考下
JavaScript的作用域以函數為界,不同的函數擁有相對獨立的作用域。函數內部可以聲明和訪問全局變數,也可以聲明局部變數(使用var關鍵字,函數的參數也是局部變數),但函數外部無法訪問內部的局部變數:
function test() {
var a = 0; // 局部變數
b = 1; // 全局變數
}
a = ?, b = ? // a為undefined,b為1
同名的局部變數會覆蓋全局變數,但本質上它們是兩個獨立的變數,一方發生變化不會影響另一方:
a = 5; // 函數外a的值為5
function test() {
var a = 4; // 函數內a的值為4
}();
a = ? // 函數外a的值仍為5,不受函數影響
一般而言,函數結束後,對函數內部變數的引用全部結束,函數內的局部變數將被回收,函數的執行環境將被清空,但是,如果以內部函數作為函數的返回結果,情況就會發生變化:
function test(i) {
var b = i * i;
return function() {
return b--;
};
}
var a = test(8);
a(); // 返回值為64, 內部變數b為63
a(); // 返回值為63, 內部變數b為62
當以內部函數作為返回值時,因為函數結束後內部變數的引用並未結束,所以函數的局部變數無法回收,函數的執行環境被保留下來,因而形成了閉包效果,可以通過該引用訪問本該被回收的內部變數。
閉包還使得函數的局部變數成為「私有」變數,只能通過返回的內部函數訪問,而無法通過其他任何手段去改變。
因此,閉包可用於維持局部變數和保護變數。
不使用閉包的情況:
var a = []; // 假設a中包含5個元素
for (var i = 0, m = a.length; i < m; i++) {
a[i].onclick = function(e) {
return 'No. ' + i;
};
}
// 點擊任何一個元素,返回值都是「No. 5」,因為i最後的值

㈢ 簡單的閉包問題

概念

閉包,在《javascripts高級程序設計》裡面是這樣介紹的:閉包是指有權訪問另一個作用域中的變數的函數。額。。這句話我以前看過很多遍,但依然不是很懂,只知道它是跟作用域有關。現在我知道了,如果這句話換成:但凡是內部的函數被保存到了外部,必定生成閉包。這樣就容易理解多了不是。
我們以下面的這個代碼塊為例:

例子解釋

function a() {const num = 100;function b () {num++;console.log(num);}return b;}const demo = a();demo();demo();

我們先執行上述代碼,看看結果是什麼:

a執行完,返回了b,此時的b只是聲明,但還沒調用,所以沒有形成自己的AO,但作用域鏈和 a doing 時是一樣的,所以雖然 a() 的作用域被銷毀了,但是相同的一份卻被b保存到了外面。這也就是內部函數被保存到了外面形成閉包的本質。這樣也不難理解為什麼上述代碼列印出來的值是那樣的了:

  • 執行第一個demo()時,也即是執行 b(),由於b保存了a的作用域鏈,所以也可以訪問到 num ,執行 b() 後,加一;

  • 那為什麼第二次執行 demo(),列印出的值還是有自增了呢?這是因為操作的都是保存在 b 里的 num ,雖然每次調用 demo() 都會形成新的作用域鏈,但是num,卻是每次從上一次的作用域鏈直接 到當前作用域鏈中的。

  • 這樣形成的閉包雖然可以使外部可以訪問到內部的函數,但是導致了原有的作用域鏈不釋放,會造成內存泄漏。(內存泄漏的意思就是佔用內存,可用內存資源變少了)。所以如果不是特殊需要,應盡量防止這種情況發生。

    並且,作用域鏈的配置機制引出了一個值得注意的副作用:即閉包只取得包含函數中任何變數最後一個值,比如下面這個例子:

  • function createFunctions() {var result = [];for(let i = 0; i< 10; i++) {result[i] = function() {console.log(i);}}return result;}var myArr = createFunctions();for(var j = 0; j < 10; j++) {myArr[j]();}

  • 這個函數會返回一個函數數組,表面上看,似乎每個函數都應該有自己的索引值,即會返回:0,1,2...9;但實際上,每個函數都會返回10;這是因為在createFunctions()執行時,for循環跳出的條件是i=10;所以函數返回後,i的值是10 ;而每個result的作用域鏈中都保存這createFunctions()的AO,所以他們引用的都是createFunctions()的i值,所以每個函數內部i的值都是10;
    這樣,我們可以創建一個立即執行函數強制讓閉包的行為符合預期:

  • function createFunctions() {var result = [];for(var i = 0; i < 10; i++) {(function(j) {result[i] = function() {document.write(j + " ");}}(i));}return result;}var myArr = createFunctions();for(var j = 0; j < 10; j++) {myArr[j]();}

  • 典型應用

    下面看看幾個用到閉包的典型例子:

  • 實現共有變數

    如累加器:調用多少次,累加多少次,用閉包更加模塊化

  • function add() {var count = 0;function demo() {count++;console.log(count);}return demo;}var counter = add();counter();//1counter();//2counter();//3

  • 實現緩存

  • 如eater: eat和push保存的都是eater的AO;,所以eat中food改變後。實際上是eater變了,所以也會影響push;

  • function eater() {var food = '';var obj = {eat: function() {console.log('eating' + food);food = '';},push: function(myFood) {food = myFood;}}return obj;// 相當於返回裡面的eat和push操作food;}var eater1 = eater();eater1.push('banana');eater1.eat();