在es5中,没有块级作用域的概念,只有 函数作用域
的概念。
webpack进行模块化打包的时候,也需要把不同的函数隔离开,使得各个模块的代码互不影响,它的实现原理也是 IIFE
使用 IIFE
可以很方便的创建一个块级作用域,在这个块级作用域之外的地方访问其中的变量都会报错。做到了 let
声明中隔离作用域和防止变量声明提升的概念。
try {
console.log('变量声明提升a', a);
}catch(error){
console.error('变量未被定义');
}
(function () {
var a = 1;
console.log('内部可以正常使用a', a)
})()
try {
console.log('外部a', a);
}catch(error){
console.error('变量未被定义');
}
const相比较let要复杂一些,除了制造块级作用域,const 需要额外处理它值不可变的特性。
基于数据类型区分,const声明对于基本类型的数据,不变的就是它的值。而对于引用类型数据,不变的是它的引用的地址,内存地址中的数据是可变的。看一个简单的例子:
const a = {id:1};
a.age = 23;
console.log(a); // {id:1, age:23}
/**但是直接进行修改会抛异常*/
a = {} // Assignment to constant variable.
// 数组同理
这个例子也就验证了,修改的是内存地址上的数据,而不是引用的“地址”(类似C语言中的指针)
了解这个概念后,我们也很容易读懂下面这段示例
const obj1 = {id: 123};
const obj2 = {id: 123};
// 指向不同的内存空间
obj1 === obj2 // false
const obj3 = {id: 123};
const obj4 = obj3;
// 指向相同的内存空间
obj3 === obj4 // true
obj3.age = 23;
console.log(obj4) // {id:123, age: 23}
接下来我们利用这个概念看一下具体实现:
try {
console.log('变量声明提升a', a);
}catch(error){
console.error('变量未被定义');
}
(function () {
var a = {id:123, age:23};
const type = Object.prototype.toString.call(a);
// 引用类型数据
if(type === [Object, Object] || type === [Object, Array]) {
var b = a;
a.sex = 1;
if(a !==b) {
console.error('Assignment to constant variable.');
a = b;
}
} else {
// 基本类型
var pre = a;
if(a !== pre) {
console.error('Assignment to constant variable.');
a = pre;
}
}
console.log('这是作用域中的a', a)
})()
try {
console.log('外部a', a);
}catch(error){
console.error('变量未被定义');
}
(小黄书上 p63)补充: 试用 try..catch的组合更加通用。IIFE作为函数,可能会影响this、return、break、continue。