域和闭包
文章目录

域和闭包

闭包

自运行函数

典型结构:

1
2
3
4
5
6
var a = 2;
(function foo() {
var a = 3;
console.log(a); // 3
})();
console.log(a); // 2

不过实际上也可以令其变成有名函数:

1
2
3
4
5
6
var a = 2;
(function IIFE() {
var a = 3;
console.log(a); // 3
})();
console.log(a); // 2

还可以传值进去并进行扩展:

1
2
3
4
5
6
7
8
var a = 2;
(function IIFE(global) {
var a = 3;
console.log(a); // 3
console.log(global.a); // 2
global.a = 10;
})(window);
console.log(a); // 10

这样就可以在里面读写传入的参数了, 注意我们是将 window 传入, 并且给了参数一个名字叫做 global , 然后对 global 进行一堆乱七八糟的读写

let

  • let和var的区别在于var的域需要整个函数域, let的域仅仅是任何大括号区块
1
2
3
4
5
6
7
8
function letTest() {
let x = 1;
if (true) {
let x = 2; // different variable
console.log(x); // 2
}
console.log(x); // 1
}
  • 另外一个重点, let无法创建全局变量
1
2
3
4
var x = 'global';
let y = 'global';
console.log(this.x); // "global"
console.log(this.y); // undefined
  • 同时不能在同一个区块多次使用let声明
1
2
3
4
if (x) {
let foo;
let foo; // SyntaxError thrown.
}
  • 另外对于let, 声明提前的功能也无效
1
2
3
4
function do_something() {
console.log(foo); // ReferenceError
let foo = 2;
}

声明提前 Hoisting

  • 函数声明会被提前
1
2
3
4
5
foo();
function foo() {
console.log( a ); // undefined
var a = 2;
}
以上存在两个声明: __foo的函数声明和a的变量声明__
上面代码等同于:
1
2
3
4
5
6
function foo() {
var a;
console.log(a); // undefined
a = 2;
}
foo();
下面的代码也很容易理解了:
1
2
3
4
5
foo(); // TypeError
bar(); // ReferenceError
var foo = function bar() {
// ...
};
等同于
1
2
3
4
5
6
7
var foo;
foo(); // TypeError
bar(); // ReferenceError
foo = function() {
var bar = ...self...
// ...
}
  • 函数会被提前到定义之前
1
2
3
4
5
6
7
8
9
10
foo(); // 1
var foo;

function foo() {
console.log(1);
}

foo = function() {
console.log(2);
};
这一段会被解释成:
1
2
3
4
5
6
7
8
9
10
11
function foo() {
console.log(1);
}

var foo; //duplicate (and thus ignored) declaration

foo(); // 1

foo = function() {
console.log(2);
};
但是注意如果多次声明那么就会复写之前的声明:
1
2
3
4
5
6
7
8
9
10
11
foo(); // 3
function foo() {
console.log(1);
}
var foo = function() {
console.log(2);
};

function foo() {
console.log(3);
}
  • 有一个对于Hoisting需要注意的地方

    因为声明会被提前, 那么条件之中的声明可能会出现理解偏差:

1
2
3
4
5
6
7
8
9
10
11
foo(); // "b"
var a = true;
if (a) {
function foo() {
console.log("a");
}
} else {
function foo() {
console.log("b");
}
}
当前版本的JS似乎没有相同问题了, 上述代码会报错, 不过依然需要避免Hoisting造成理解偏差.
  • 只有声明会被提前, 所有的赋值以及函数表达式的赋值都不会提前

参考文献