闭包总结(2018.03.19)
什么是閉包?
簡單講,閉包就是指有權訪問另一個函數作用域中的變量的函數。
不好理解?看下面一個簡單的例子:
function func() {var a = 1, b = 2;function closure() {return a + b}return closure } 復制代碼上述代碼中的closure就是一個閉包,是不是有點感覺了?
接下來再看下下面這句話:
通常,函數的作用域及其所有變量都會在函數執行結束后被銷毀。但是,在創建了一個閉包以后,這個函數的作用域就會一直保存到閉包不存在為止。
有點暈?我們一點點來看:
function addNum() {var a = 1, b = 2;console.log("addNum->a", a);console.log("addNum->b", b);return (a + b); }addNum(); console.log("handle->a", a); console.log("handle->b", b); 復制代碼執行結果如上圖,在函數執行結束后,作用域和變量立即被銷毀。
如果有閉包存在:
function addNum(x) {return function(y) {return x + y;} }var handleAddNum = addNum(5); console.log(handleAddNum(2)); // 7 console.log(handleAddNum(3)); // 8 復制代碼結果和上個例子是不是有所不同,按理說,addNum被執行結束后,x就應該別銷毀,但是因為有閉包的存在,x的作用域被繼續保留了,想要銷毀x,就要銷毀閉包。
handleAddNum = null; 復制代碼下面在看下一個比較經典的閉包問題:
function test(){var arr = [];for(var i = 0;i < 10;i++){arr[i] = function(){return i;};}for(var a = 0;a < 10;a++){console.log(arr[a]());} } test(); //結果連打十個10 復制代碼分析下執行過程:
首先,在這個作用域內,都是至上而下執行的,var i定義了一個整個作用域上的變量,第一個for語句執行結束后,i為10, 然后是第二個for語句,執行arr[i] = function(){ return i};,因為在函數中沒有找到i,會往上一層作用域去找,而上一層的i已經為10,所以會連續輸出十個十。
把var改動成let后,看下執行結果:
function test(){var arr = [];for(let i = 0;i < 10;i++){arr[i] = function(){return i;};}for(var a = 0;a < 10;a++){console.log(arr[a]());} } test(); //輸出0,1,2,3,4,5,6,7,8,9 復制代碼分析下執行過程:
let 在定義變量時會開辟新的塊級作用域,即每次for循環都會開辟出一塊的新的作用域,所以當執行arr[i] = function(){ return i};時,沒有找到i時,向上找,在let開辟的新的塊級作用域中找到了i,即對應的0,1,2,3,4,5,6,7,8,9
閉包中的this對象:
有如下代碼:
var obj = {name: 'yy',getThis: function() {console.log('this', this);} }obj.getThis(); 復制代碼執行結果:this Object {name: "yy"}...就是我們普遍認為的函數在哪里定義就在哪里執行。
那再看下面這個例子:
var obj = {name: 'yy',getThis: function() {//匿名函數return function() {console.log('this', this);}} } obj.getThis()(); 復制代碼執行結果:
this Window {speechSynthesis: SpeechSynthesis, caches: CacheStorage, localStorage: Storage, sessionStorage: Storage, webkitStorageInfo: DeprecatedStorageInfo…}
全局作用域中調用了匿名函數,所以this指向了window。
不要認為函數在哪里,其內部的this就指向哪里。匿名函數的執行環境具有全局性,因此其 this 對象通常指向 window。
鞏固下,想想下面的結果是啥:
var name = "The Window";var obj = {name: "My Object",getName: function(){var that = this;console.log('getName:', this);return function(){return that.name;};} };console.log(obj.getName()()); 復制代碼閉包的應用:設計私有的方法和變量
- 任何在函數中定義的變量,都可以認為是私有變量,因為不能在函數外部訪問這些變量。私有變量包括函數的參數、局部變量和函數內定義的其他函數。
- 把有權訪問私有變量的公有方法稱為特權方法(privileged method)。
單例(singleton):指的是只有一個實例的對象。JavaScript 一般以對象字面量的方式來創建一個單例對象。
var singleton = {name: "percy",speak:function(){console.log("speaking!!!");},getName: function(){return this.name;} }; 復制代碼模塊模式(The Module Pattern):為單例創建私有變量和方法。
var singleton = (function(){// 私有變量var age = 22;var speak = function(){console.log("speaking!!!");};// 特權(或公有)屬性和方法return {name: "percy",getAge: function(){return age;}}; })(); 復制代碼閉包的缺陷:
總結
以上是生活随笔為你收集整理的闭包总结(2018.03.19)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 淘宝app如何删除评价(淘宝海外全球站首
- 下一篇: Cocos Creator导出场景和预制