Javascript 是一个很特别的程式语言,与传统的 C 语言有很大的落差,这篇文章会介绍两个 Javascript 独有的特性 Hoisting 与 Closure , Closure 也有人翻译成闭包。
Closure
Closure 很特别,目前在各种程式语言中,很少会支援这个特性的,一般来说变数的生命周期,只会生存在该 function ,一旦离开了 function ,变数便会被回收,不能够再被使用,而且每个在 function 中的变数,一定要事先宣告,在 function 中的变数,我们称之为 Local Variable,function 只能使用自身的 Local Variable ,不能使用 function 外的变数,但是在 Javascript 中却没有这么简单,来看一个 function 使用外部变数的范例。
- var a = 1;
- function closure1() {
- console.log(a)
- }
- closure1();
上一段程式会印出 「1 」,然而在 function closure1 中没有宣告 a 这个变数,但是 closure 的 parent 中宣告了 a 这个变数,所以 Javascript 会自动去取得 a =1 。
再来看一个使用昵名 function 的范例。
- function closure2() {
- var a = 2;
- var s = function () {
- console.log(a);
- }
- s();
- }
- closure2();
这段程式会印出 「2」,原理跟第一个范例相同, closure2 中执行了 s() ,所以 s() 的 parent 是 closure2 ,根据 closure 的特性 s() 可以使用 closure2 的变数。
再来看一个奇怪的范例,你应该知道输出的结果是什么了吧。
- var a = 1;
- function closure3() {
- var s = function () {
- console.log(a);
- }
- s();
- }
- closure3();
使用 Closure 时要特别小心,不好的 Closure 很容易造成 memory leak ,其实笔者我平常是不使用 Closure 这种写法的。
Hoisting
Hoisting 跟变数的宣告有关系,一个 JS function 可以重覆定义相同的变数名称,如果在 C 语言你重覆定义相同的变数的话,你连 Compile 都会过不了,但是这在 Javascript 中是完全合法的。
- var a = 1;
- function hoisting1() {
- if (!a) {
- var a = 2;
- }
- console.log(a);
- }
- hoisting1();
上一段程式,会印出 「2 」这个值,疑! 刚刚才说过 closure 的观念, a 不是应该就自动去取得他的 parent 的值吗 (a=1)。
Javascript 有另一个特性 Hoisting ,程式会将 function 中全部需要宣告的 Local Variable ,提升到 function 的第一行来执行。
来看看 Javascript 真正的执行过程:
- var a = 1;
- function hoisting1() {
- var a;
- if (!a) {
- a = 2;
- }
- console.log(a);
- }
- hoisting1();
看完真正 JS Engine 的执行码,就可以很清楚的知道原因, Local Variable a 在 function 的第一行就已经被宣告了,这时 a 会等於「undefined」,所以才造成程式进入 if (!a) 的区块。
回應 (Leave a comment)