深入挖掘js之作用域闭包
前提:JavaScript中闭包无处不在,你只需要能够识别并拥有它。闭包是基于词法作用域书写代码时自然产生的结果。 一、实质问题
词法作用域简单的来说词法作用域就是定义在词法阶段的作用域,换就话说,词法作用域是由你在写代码时将变量和块作用域写在哪里来决定的 function foo(a){ var b = a*2; function bar(c){ console.log(a,b,c); } bar (b*3); } foo(2); 在这个例子中包含了三个逐级嵌套的作用域
关于词法作用域我们就现讲这么多,接下来还是回到我们的正文,作用域闭包 function foo(){ var a=2; function bar(){//bar()的词法作用域能够访问foo()的内部作用域 console.log(a); } return bar;//将bar()函数当做一个值类型进行传递 } var baz =foo(); baz(2); foo()内部作用域依然存在,没有被回收。bar()依然持有该作用域的引用。这个引用就叫闭包 function foo(){ var a=2; function baz(){ console.log(a); } bar(baz); } function bar(fn){ fn(); } foo(); //把内部函数baz传递给bar, // 当调用这个内部函数, // 他涵盖的foo()内部作用域的闭包就可以观察到了,因为它能够访问a var fn; function foo(){ var a =2; function baz(){ console.log(a); }; fn = baz; } function bar(){ fn(); } foo(); bar();
二、提升function wait(message){ setTimeout(function timer(){ console.log(message) },1000); }; wait("hello world"); 在引擎内部,内置的工具函数setTimeout()持有对一个参数的引用,引擎会调用这个函数,在这个例子中就是内部的timer函数,而词法作用域就在这个过程中保持完整。这就是闭包。 三、循环和闭包for(var i=0;i<=5;i++){ setTimeout(function timer() { console.log(i); },i*1000); } //大家猜猜结果会是啥? 正常情况下会分别输出数字1~5,但实际会输出五次6。
代码中有什么缺陷导致它的行为通语义所暗示的不一致呢? for( var i=0;i<=5;i++){ (function(){ setTimeout(function timer() { console.log(i); },i*1000); })(); } 这样子为什么还不行呢?我们显然拥有了更过的词法作用域。
for( var i=1;i<=5;i++){ (function(){ var j =i; setTimeout(function timer() { console.log(j); },j*1000); })(); } 重返块作用域for(let i =1;i<=5;i++){ setTimeout(function timer() { console.log(i); },i*1000); } let欺骗此法作用域,每次在迭代都去创建一个新的作用域,然后执行完后被销毁,这样每个迭代都有自己的作用域就可以达到我们的预期效果,输出1~5。 四、模块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.doAnother(); foo.doSomething(); 这个模式JavaScript中被称为模块,保护私有属性,只提供公共方法。
现代的模块机制大多数模块依赖加载器/管理器本质上都是将这种模块定义封装进一个友好的API。 var MyModules = (function Manager(){ var modules = {}; function define(name,deps,impl){ for(var i=0;i<deps.length;i++){ deps[i] = module[deps[i]]; } modules[name] = impl.apply(impl,deps); } 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("hippo")); foo.awesome(); (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |