你不知道的javascript上
一个简单的闭包
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| function foo(){ var a = 2; function bar(){ console.log(a); } return bar; } var baz = foo(); baz();
function foo(){ var a = 2; fuction baz(){ console.log(a); } bar(baz); } function bar(fn){ fn(); }
var fn; function foo(){ var a = 2; function baz(){ console.log(a); } fn = baz; } function bar(){ fn(); } foo(); bar();
|
无论通过什么手段将内部函数传递到所在作用域外,它都会持有对原始定义作用域的引用,无论在何处执行这个函数都会使用闭包。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| for(var i = 0;i < 5;i++){ (function(j){ setTimeout(function(){ console.log(j); },1000*j) })(i) }
for(let i = 0;i < 5;i++){ setTimeout(function(){ console.log(i); },1000*i) }
|
模块
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| function CoolModule(){ var something = "cool"; var another = [1,2,3]; function doSomething(){ console.log(something); } function doAnother(){ console.log(another.join(",")); } return { doSomething, doAnother } } var a = new CoolModule(); a.doSomething(); a.doAnother();
|
两个必要条件
- 必须有外部的封闭函数,该函数必须至少被调用一次(每次调用都会创建一个新的模块
实例)。
- 封闭函数必须返回至少一个内部函数,这样内部函数才能在私有作用域中形成闭包,并
且可以访问或者修改私有的状态。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
| var foo = (function CoolModule(){ var something = "cool"; var another = [1,2,3]; function doSomething(){ console.log(something); } function doAnother(){ console.log(another.join(",")); } return { doSomething, doAnother } })(); foo.doSomething(); foo.doAnother();
function CoolModule(id) { function identify() { console.log( id ); } return { identify: identify } } var foo1 = CoolModule( "foo 1" ); var foo2 = CoolModule( "foo 2" );
var foo = (function CoolModule(id){ function change(){ publicAPI.identify = identify2; } function identify1(){ console.log(id); } function identify2(){ console.log(id.toUpperCase()); } var publicAPI = { change, identify:identify1 } return publicAPI; })("foo module") foo.identify(); foo.change(); foo.identify();
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, 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();
|
call和apply
原文
- 相同点:都是在特定的作用域中调用函数,等于设置函数体内this对象的值,以扩充函数赖以运行的作用域。
- 一般来说,this总是指向调用某个方法的对象,但是使用call()和apply()方法时,就会改变this的指向。
- 不同点:
- 描述:apply()方法接收两个参数,一个函数运行的作用域(this),另一个是参数数组。
- 语法:apply([thisObj [,argArray] ]),调用一个对象的一个方法,另一个对象替换当前对象。
- 说明:如果argArray不是一个有效数组或不是arguments对象,那么将导致一个TypeError,如果没有提供argArray和thisObj任何一个参数,那么Global对象将用作thisObj。
- 描述:call()方法,第一个参数和apply()方法的一样,但是传递给函数的参数必须列举出来。
- 语法:call([thisObject[,arg1[,arg2[,…,argn]]]]),应用某一对象的一个方法,用另一个对象替换当前对象。
- 说明:call方法可以用来替代另一个对象调用一个方法,call方法可以将一个函数的对象上下文从初始的上下文改变为thisObj指定的新对象,如果没有提供thisObj参数,那么Global对象被用于thisObj。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| window.color = "red"; document.color = "yellow"; var s1 = { color:"blue" } function changeColor(){ console.log(this.color); } changeColor(); changeColor.call(); changeColor.call(window); changeColor.call(document); changeColor.call(this); changeColor.call(s1);
|
//