前面一片文章讲到过一点函数,了解到每声明一个函数就会产生一个作用域。而外面的作用域访问不了里面的作用域(把里面的变量和函数隐藏起来),而里面的可以访问到外面的。对于隐藏变量和函数是一个非常有用的技术。
基于作用域隐藏的方法叫做最小授权或最小暴露原则。
这个原则是指在软件设计中,应该最小限度的暴露必要内容,而将其内容都隐藏起来,比如某个模块或对象得API设计。隐藏变量和函数可以解决同名标识符的之间的冲突,冲突会导致变量的意外覆盖。
例如:
1 2 3 4 5 6 7 |
var a = 2; function foo(){ var a = 3; console.log(a); } foo(); console.log(a); |
虽然这种技术可以解决一些问题,但是他并不理想,会导致一些额外的问题,首先必须声明一个具名函数foo(),意味着foo这个名称本身“污染”了所在的作用域,其次必须显式的通过函数名foo()调用这个函数才能运行其中的代码。
如果函数不需要函数名,并且能够自动运行,这会更加理想。幸好js提供了同时解决这两个问题的方案 — (IIFE) Immediately Invoked Function Expression — 立即执行函数
1 2 3 4 5 6 |
var a = 2; (function foo(){ var a = 3; console.log(a); })() console.log(a); |
首先立即执行函数不会当做函数声明处理而是当做函数表达式处理。
区分函数声明还是函数表达式:看function在声明中是不是第一个词,如果是第一个词就是函数声明否则就是函数表达式。而立即执行函数” (function “,不是” function “,所以是函数表达式。
函数声明和函数表达式之间最重要的区别是他们的名称标识符将会绑定在何处
函数声明的函名称数会绑定在当前作用域内。假如在全局作用域创建一个函数声明,就可以在全局作用域访问这个函数名称并执行。而函数表达式的函数名称会绑定在自身的函数中,而不是当前说在作用域中。例如你全局创建一个函数表达式,如果你直接执行这个你创建的函数表达式的函数名就会报错,因为当前作用域下没有这个标识符,而你在函数表达式里面的作用域里访问这个函数名就会返回这个函数的引用。
作用域闭包,嗯,闭包这儿两个字就有点让人难以理解,(可以想象成一个包是关上的,里面隐藏了一些神秘的东西)而对于闭包的定义是这样说的:当函数可以记住并访问所在的作用域时,就产生了闭包,即使函数是在当前作用域之外执行。
for instance(拽个英文,哈哈)。
1 2 3 4 5 6 7 8 |
function foo() { var a = 2; function bar() { console.log(a); } bar(); } foo(); |
上面的 代码bar()可以访问外部作用域中的变量。根据上面的定义这是闭包吗?从技术来讲也许是,但我们理解的是作用域在当前作用域查找变量如果没找到会继续向上面查找,找到返回,找不到继续找,直到全局作用域。– 而这些正是闭包的一部分。函数bar()具有一个涵盖foo()作用域的闭包。