《你不知道的JavaScript(上)》笔记——作用域闭包
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了《你不知道的JavaScript(上)》笔记——作用域闭包,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含3598字,纯文字阅读大概需要6分钟。
内容图文
当函数可以记住并访问所在的词法作用域时, 就产生了闭包, 即使函数是在当前词法作用域之外执行。
function wait(message) {
setTimeout( function timer() {
console.log( message );
}, 1000 );
}
wait( "Hello, closure!" );
将一个内部函数( 名为 timer) 传递给 setTimeout(..)。 timer 具有涵盖 wait(..) 作用域的闭包, 因此还保有对变量 message 的引用。wait(..) 执行 1000 毫秒后, 它的内部作用域并不会消失, timer 函数依然保有 wait(..)作用域的闭包。
深入到引擎的内部原理中, 内置的工具函数 setTimeout(..) 持有对一个参数的引用, 这个参数也许叫作 fn 或者 func, 或者其他类似的名字。 引擎会调用这个函数, 在例子中就是内部的 timer 函数, 而词法作用域在这个过程中保持完整。这就是闭包。
在定时器、 事件监听器、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
首先, CoolModule() 只是一个函数, 必须要通过调用它来创建一个模块实例。 如果不执行外部函数, 内部作用域和闭包都无法被创建。
其次, CoolModule() 返回一个用对象字面量语法 { key: value, ... } 来表示的对象。 这个返回的对象中含有对内部函数而不是内部数据变量的引用。 我们保持内部数据变量是隐藏且私有的状态。 可以将这个对象类型的返回值看作本质上是模块的公共 API。
这个对象类型的返回值最终被赋值给外部的变量 foo, 然后就可以通过它来访问 API 中的属性方法, 比如 foo.doSomething()。
因此模块模式需要具备两个必要条件:
- 必须有外部的封闭函数, 该函数必须至少被调用一次(每次调用都会创建一个新的模块
实例)。 - 封闭函数必须返回至少一个内部函数, 这样内部函数才能在私有作用域中形成闭包, 并
且可以访问或者修改私有的状态。
模块模式另一个简单但强大的变化用法是, 命名将要作为公共 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 对象的内部引用, 可以从内部对模块实例进行修改, 包括添加或删除方法和属性, 以及修改它们的值。
现代的模块机制
大多数模块依赖加载器 / 管理器本质上都是将这种模块定义封装进一个友好的 API。
var MyModules = (function Manager() {
var modules = {};
function define(name, deps, impl) {
for (var i = 0; i < deps.length; i++) {
deps[i] = modules[deps[i]];
}
modules[name] = impl.apply(impl, deps);
}
function get(name) {
return modules[name];
}
return {define: define, get: get};
})();
这段代码的核心是 modules[name] = impl.apply(impl, deps)。 为了模块的定义引入了包装函数(可以传入任何依赖), 并且将返回值, 也就是模块的 API, 储存在一个根据名字来管理的模块列表中。
下面展示了如何用它来定义模块:
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("hippo")); // Let me introduce: hippo
foo.awesome(); // LET ME INTRODUCE: HIPPO
"foo" 和 "bar" 模块都是通过一个返回公共 API 的函数来定义的。 "foo" 甚至接受 "bar" 的示例作为依赖参数, 并能相应地使用它。
内容总结
以上是互联网集市为您收集整理的《你不知道的JavaScript(上)》笔记——作用域闭包全部内容,希望文章能够帮你解决《你不知道的JavaScript(上)》笔记——作用域闭包所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。