1. 程式人生 > >Js基礎知識6-JavaScript匿名函數和閉包

Js基礎知識6-JavaScript匿名函數和閉包

js基礎 訪問 fun null 個數 () nbsp 自我 每次

1,把匿名函數賦值給變量

var test = function() {
    return ‘guoyu‘;
};
alert(test);//test是個函數
alert(test());

2,把匿名函數自我執行的返回值賦值給變量

var test = (function() {
    return ‘GY‘;
})();
alert(test);//彈出  GY

3,自我執行,第一個圓括號放匿名函數,第二個括號執行並傳參

(function(a, b) {
    alert(a+b);
})(2,5);//直接彈出7

4,自我執匿名函數的傳參

alert((function() {
    return ‘guoyu‘;
})());

5,函數裏面放一個匿名函數

functiontest() {
    return function() {
        return ‘guoyu‘;
    };
}
alert(test());//執行test(),結果是一個函數體
alert(test()());//彈出guoyu

var t = test();
alert(t());//彈出guoyu

閉包

閉包是指有權訪問另一個函數作用域中的變量的函數,創建閉包的常見方式,就是在一個函數內創建另一個函數,通過另一個函數訪問這個函數的局部變量

1,通過閉包可以返回局部變量

functiontest() {
    var age = 28;
    return function() {
        return age;
    };
}
alert(test()());//直接彈出 28

2,使用閉包有個優點,同時也是缺點:局部變量駐留內存中,可以避免使用全局變量(全局變量汙染導致應用程序的不可預知性,每個模塊都可以調用必將引來災難,推薦使用私有的,封裝的局部變量)

使用全局變量進行累加
var age = 20;
functiontest() {
    age++;
    return
age; } alert(test());//21 alert(test());//22 如果你把var age = 20;放進test()函數內,那麽每次執行都會重新初始化為20,每次彈出的都是21,無論執行多少次!

3,使用匿名函數實現局部變量駐留內存中從而累加

functiontest() {
    var age = 20;
    return function() {
        age++;
        return age;
    }
}
var t = test();
alert(t());//21
alert(t());//22
alert(t());//23
alert(t());//24
/*如果每次都初始化age = 20;那麽每次返回都是21,不能實現累加,因此要避免初始化那一句,只要調用第一個return 語句即可,每次只調用t()即可*/
t = null;//解除引用,等待垃圾回收

循環裏的匿名函數的取值問題

function test() {
    var arr = [];
    for (var i = 0; i < 5; i++) {
        arr[i] = function() {
            return i;
        };
    }

    //循環執行完畢,i最終是4++,就是5
    return arr;
}

/*
    alert(test());
    打印出5個並列的“function() {return i;}”,
    因為arr數組的每個元素都是一個匿名函數,每個匿名函數都是返回"i",
    並不是返回123....,因為這個匿名函數是死的,沒有執行(自執行)
*/
alert(test()[0]);//彈出“function() {return i;}”

var t = test();

for (var i = 0; i < 5; i++) {
    //alert(t[i]);//數組裏面都是一個沒有自執行的匿名函數


    //現在讓數組裏的每個死函數執行起來,但是全都是彈出‘5’
    //因為執行test()裏的循環後,i已經為5了,但每個數組裏面都存的是個死函數,返回一個死i
    alert(t[i]());
}

如何解決上述的問題呢?

修改1

functiontest() {
    var arr = [];
    for (var i = 0; i < 5; i++) {
        arr[i] = i;//這裏不用匿名函數,直接給個i,
    }
    return arr;
}

var t = test();

for (var i = 0; i < 5; i++) {
    alert(t[i]);//依次彈出0,1,2,3,4
}

修改2,通過自我即時執行匿名函數:

//將匿名函數裏面的變量駐留到內存感覺像全局變量
functiontest() {
    var arr = [];
    for (var i = 0; i < 5; i++) {
        arr[i] = (function(num) {
            return num;
        })(i);
    }
    return arr;
}

var t = test();

for (var i = 0; i < 5; i++) {
    alert(t[i]);//依次彈出0,1,2,3,4
}

修改3:

functiontest() {
    var arr = [];
    for (var i = 0; i < 5; i++) {
        arr[i] = (function(num) {
            //return num;
            return function() {//這麽寫就是閉包了,閉包將變量駐留在內存,和前例中累加一個道理
                return num;
            };
        })(i);
    }
    return arr;
}

var t = test();

for (var i = 0; i < 5; i++) {
    //alert(t[i]);這裏返回的是5個依次“function() {return num;}”
    alert(t[i]());//依次打印出0,1,2,3,4
}

閉包中的this

var test = {
    getThis: function() {
        return this;
    }
};

alert(test.getThis());//[object Object]

再看看閉包中:

var test = {
    getThis: function() {
        return function() {//這麽寫就是閉包了
            return this;
        };
    }
};

alert(test.getThis()());//[object Window]

結論:this 對象在運行時基於函數的執行環境綁定的,如果this在全局範圍就是widow,如果在對象內部就指向這個對象。而閉包在運行時指向window的,因為閉包不屬於這個對象的屬性或方法,再看下面

var user = ‘The Window‘;
var box = {
    user:‘The Box‘,
    getUser: function() {
        //return this.user;
        return function() {//這麽寫就是閉包了
            return this.user;
        };
    }
};

alert(box.getUser()());//The Window

那麽有的同學想問了,怎麽才能讓它彈出 The box呢?
方法有兩個:對象冒充,變量保存_this

var user = ‘The Window‘;
var box = {
    user:‘The Box‘,
    getUser: function() {//這個地方要冒充一下
        return function() {
            return this.user;
        };
    }
};

alert(box.getUser().call(box));//The Box
var user = ‘The Window‘;
var box = {
    user:‘The Box‘,
    getUser: function() {
        var _this = this;//保存到臨時變量
        return function() {
            return _this.user;
        };
    }
};

alert(box.getUser()());//The Box


模仿塊級作用域,for ,if 等塊級裏的東西封裝起來,變量私有化,可以保護數據,防止泄露,js沒有私有作用域這個概念

functiontest() {
    for(var i = 0; i < 5; i++) {//塊級作用域,可惜JS沒這個東西

    }
    var i;//重新聲明也不影響
    alert(i);//即使超出for塊級,依舊打印出5,說明js沒有塊級作用域這個概念
}
test();

開始使用塊級作用域,也就是出了if , for等塊,裏面的i就不再起效,方法就是包含自我執行的匿名函數,就可以實現私有作用域

functiontest() {
    (function() {
        for (var i = 0; i < 5; i++) {//包含自我執行的匿名函數,就可以實現私有作用域
            alert(i);
        }
    })();

    alert(i);
    //這裏i就不認識了,相當於沒定義i,i被銷毀了,後面繼續定義i和上面的i沒任何關系,防止汙染
}
test();
(function() {
    var age = 20;
    alert(age);
})();
alert(age);//報錯,undefined
//這樣可以全局變量私有化,防止汙染

私有變量(外部不可訪問)

functiontest() {
    var age = 20; //私有變量
}


functionTest() {
    this.age = 20;//屬性:公有的,外部可訪問
    this.run = function() {//方法:公有的
        return ‘is running...‘;
    };
}


var t = new Test();
alert(t.age);
alert(t.run());

functionTest() {
    var age = 20;  //私有變量
    functionrun() {//私有函數
        return ‘ is running...‘;
    }

    this.publicGo = function() { //對外可見的公共接口,特權方法
        return age + run();
    };
}

var t = new Test();
alert(t.publicGo());
//20 is running...私有變量,私有函數,通過公共接口被訪問
//把一些細節封裝起來,通過一些接口去訪問
    

Js基礎知識6-JavaScript匿名函數和閉包