你不知道的JS(三)-函数作用域和块作用域

393 阅读2分钟

函数是JS常见的作用域单元。本质上,声明在一个函数内部的变量或者函数所在的处的作用域中“隐藏”起来,这是有意为之的良好软件的设计原则。

块作用域指的是变量和函数不仅可以属于所处的作用域,也可以属于某个代码块(通常指 {...} 内部)。

函数作用域

(function foo(a) {
	function doSomething(a) {
    	return a - 1;
    }
    var b;
    b = a + doSomething(a * 2);
    console.log(b * 3); // 15
    
})(2);

函数表达式形式函数 foo 是立即执行函数(IIFE)也是一个具名函数,将 doSomething 放在函数内部是规避冲突,实现“私有”内容。

以 function 关键字是声明中的第一个词,那么就是函数声明。否则就是函数表达式。

匿名函数的缺点

  1. 在栈中不会显示出有意义的函数名,使得调试很困难。
  2. 如果没有函数名,当函数调用自身时只能使用已经过期的 arguments.callee 引用。
  3. 代码可读性/可理解性差

块作用域

for (var i = 0; i< 3; i++) {
	console.log(i);
}

形式上带有块作用域风格,但是 i 还是全局作用域,可以使用 ES6 中的 let 形成真正的块作用域。

此外还有 if , try...catch(err){}, with 对象

var foo = true;
if (foo) {
	let bar = foo * 2;
    bar = something(bar);
    console.log(bar);
}
console.log(bar); // ReferenceError

const 类似;

try {
	undefined();
}
catch (err) {
	console.log(err); // 正常执行
}
console.log(err) // ReferenceError: err not found

catch 也会形成一个块作用域

垃圾收集

function process(data) {...}
var some = {...}
process(some);
var btn = document.getElmentById("myButton");
btn.addEventLister("click", function click(evt){
	console.log("btn click");
}, false);

click 函数并没有用到 some 变量,理论上 process 执行后,可以被垃圾回收,但是由于 click 函数形成一个覆盖整个作用域的闭包,JS引擎kennel依然保存这个结构,但是修改成:

{
	let some = {...};
    process(some);
}

就可以在完事之后被销毁!