闭包
闭包是什么?
当函数能够记着并接见地点的词法作用域时,就发生了闭包,纵然函数是在当前词法作用域以外实行,简朴上讲,就是在一个函数中内部的函数。
function foo() {
var a = 2;
function bar() {
console.log( a );
}
return bar;
}
var baz = foo();
baz(); // 2 —— 朋侪,这就是闭包的结果。
那末bar函数就是一个闭包,它能够在作用域外被接见。
种种闭包实例:
function foo() {
var a = 2;
function baz() {
console.log( a ); // 2
}
bar( baz );
}
function bar(fn) {
fn(); // 妈妈快看呀,这就是闭包!
}
function setupBot(name, selector) {
$( selector ).click( function activator() {
console.log( "Activating: " + name );
} );
}
setupBot( "Closure Bot 1", "#bot_1" );
setupBot( "Closure Bot 2", "#bot_2" );
function wait(message) {
setTimeout( function timer() {
console.log( message );
}, 1000 );
}
wait( "Hello, closure!" );
本质上不管何时何地,假如将函数看成第一级的值范例并随处通报,就会由闭包,在定时器、事宜监听器、Ajax要求、跨窗口通讯、Web Workers或许其他的异步(或许同步)使命中,只需使用了回调函数,实际上就是闭包
模块
模块实例:
function CoolModule() {
var something = "cool";
var another = [1, 2, 3];
function doSomething() {
console.log( something );
}
function doAnother() {
console.log( another.join( " ! " ) );
}
return {
doSomething: doSomething,
doAnother: doAnother
};
}
var foo = CoolModule();
foo.doSomething(); // cool
foo.doAnother(); // 1 ! 2 ! 3
这类形式在JavaScript中就是模块。
最常见的完成模块形式的要领一般被称为模块暴露。
模块形式所具有的两个必要特性:
必需有外部的关闭函数,该函数最少被挪用一次(每次挪用都邑发生新的模块实例)。 关闭函数必需返回最少一个内部函数,如许内部函数才能在私有作用域中构成闭包,而且能够接见或许修正私有的状况。
模块形式的另一个简朴但壮大的用法是定名将要作为大众API返回的对象。
var foo = (function CoolModule(id) {
function change() {
// 修正大众 API
publicAPI.identify = identify2;
}
function identify1() {
console.log( id );
}
function identify2() {
console.log( id.toUpperCase() );
}
var publicAPI = {
change: change,
identify: identify1
};
return publicAPI;
})( "foo module" );
foo.identify(); // foo module
foo.change();
foo.identify(); // FOO MODULE
经由过程在模块实例的内部保存对大众API对象的内部援用,能够从内部对模块实例举行修正,包含增加或删除要领和属性,以及修正他们的值。
当代的简朴模块机制:
var MyModules = (function Manager() {
var modules = {}
function define(name, argus, func) {
for (var i = 0; i < argus.length; i++) {
argus[i] = modules[argus[i]]
}
modules[name] = func.apply(func,argus)
}
function get(name) {
return modules[name]
}
return {
define: define,
get: get
}
})()
MyModules.define("bar", [], function () {
function hello(who) {
return "Let me introduce: " + who;
}
return {
hello: hello
};
});
MyModules.define("foo", ["bar"], function (bar) {
var hungry = "hippo";
function awesome() {
console.log(bar.hello(hungry).toUpperCase());
}
return {
awesome: awesome
};
});
var bar = MyModules.get("bar");
var foo = MyModules.get("foo");
console.log(
bar.hello.call(undefined, "hippo")
); // Let me introduce: hippo
foo.awesome.call(undefined); // LET ME INTRODUCE: HIPPO
“foo”和”bar”模块都是经由过程一个返回大众API的函数来定义的,“foo”以至接收“bar”的实例作为依靠参数,并能响应的使用它。
它们相符前面列出的模块形式的两个特性:挪用包装了函数定义的包装函数,而且将返回值作为该模块的API。
ES6的模块机制
ES6中为模块增加了一级语法支撑。在经由过程模块体系举行加载时,ES6会将文件看成自力的模块来处置惩罚。每一个模块都能够导入其他模块或特定的API成员,同时也能够导出本身的API成员。
重构之前的模块得三个文件
- bar.js
function hello(who) {
return "Let me introduce: " + who
}
export hello
- foo.js
import hello from "bar"
var hungry = "hippo"
function awesome() {
console.log(hello(hungry).toUpperCase())
}
export awesome
- baz.js
module foo from "foo"
module bar from "bar"
console.log(bar.hello("hippo"))
foo.awesome
import要领:将一个模块中的一个或多个API导入到当前作用域中,并绑定在一个变量上。
module要领:将全部模块的API导入并绑定到一个变量上
export要领:将当前模块的一个标识符导出为大众API
模块文件中的内容会被看成包含在作用域闭包中一样来处置惩罚。