根据 Mozilla 开发者网络(MDN),“闭包是将一个函数和对其周围的状态(词法环境)的引用捆绑在一起(封闭)的组合。”简而言之,这意味着在一个函数内部的函数可以访问其外部(父)函数的变量。
为了更好地理解闭包,可以看看作用域及其执行上下文。
下面是一个简单的代码片段:
1 2 3 4 5 6 7 8 9 10 11 12
var hello = "Hello";
function sayHelloWorld() { var world = "World"; function wish() { var year = "2021"; console.log(hello + " " + world + " "+ year); } wish(); } sayHelloWorld();
下面是这段代码的执行上下文:
每次创建函数时(在函数创建阶段)都会创建闭包。每个闭包有三个作用域。
本地作用域(自己的作用域)
外部函数范围
全局范围
我稍微修改一下上面的代码来演示一下闭包:
1 2 3 4 5 6 7 8 9 10 11 12 13
var hello = "Hello";
var sayHelloWorld = function() { var world = "World"; function wish() { var year = "2021"; console.log(hello + " " + world + " "+ year); } return wish; } var callFunc = sayHelloWorld(); callFunc();
var resourceRecord = function(myName, myAddress) { var resourceName = myName; var resourceAddress = myAddress; var accessRight = "HR"; return { changeName: function(updateName, privilege) { // only HR can change the name if (privilege === accessRight ) { resourceName = updateName; return true; } else { return false; } }, changeAddress: function(newAddress) { // any associate can change the address resourceAddress = newAddress; }, showResourceDetail: function() { console.log ("Name:" + resourceName + " ; Address:" + resourceAddress); } } } // Create first record var resourceRecord1 = resourceRecord("Perry","Office"); // Create second record var resourceRecord2 = resourceRecord("Emma","Office"); // Change the address on the first record resourceRecord1.changeAddress("Home"); resourceRecord1.changeName("Perry Berry", "Associate"); // Output is false as only an HR can change the name resourceRecord2.changeName("Emma Freeman", "HR"); // Output is true as HR changes the name resourceRecord1.showResourceDetail(); // Output - Name:Perry ; Address:Home resourceRecord2.showResourceDetail(); // Output - Name:Emma Freeman ; Address:Office