文章内容全部来自《你不知道的JavaScript - 上》,记录学习呀呀呀!!!
函数作用域
函数作用域是指,属于这个函数的全部变量都可以在整个函数的范围内使用及复用(事实上在嵌套的作用域中也可以使用)。
var a = 2; //属于全局
function foo() {
var a = 3; //属于foo这个函数
console.log(a); // 3
}
foo();
console.log(a); // 2
匿名、具名、立即执行
匿名与具名
setTimeout(function() {
console.log("I waited 1 second! ");
}, 1000 );
这叫作匿名函数表达式,因为function()..没有名称标识符。函数表达式可以是匿名的,而函数声明则不可以省略函数名——在JavaScript的语法中这是非法的。
匿名函数的缺点:
- 匿名函数在栈追踪中不会显示出有意义的函数名,使得调试很困难。
- 如果没有函数名,当函数需要引用自身时只能使用已经过期的arguments.callee引用,比如在递归中。
- 匿名函数省略了对于代码可读性/可理解性很重要的函数名。一个描述性的名称可以让代码不言自明。
立即执行函数
var a = 2;
(function foo() {
var a = 3;
console.log(a); // 3
})();
console.log(a); // 2
上述模式(function foo())(),专业术语:IIFF,代表立即执行函数表达式(Immediately Invoked Function Expression)
两种书写形式:
- 函数表达式被包含在()中,然后在后面用另一个()括号来调用,(function foo(){ .. })()
- 函数表达式被包含在()中,然后在后面用另一个()括号来调用,(function(){ .. }())
应用场景
- 当作函数调用并传递参数进去
var a = 2;
(function IIFE(global) {
var a = 3;
console.log(a); // 3
console.log(global.a); // 2
})(window);
console.log(a); // 2
- 解决undefined标识符的默认值被覆盖导致的异常;将一个参数命名为undefined,但是在对应的位置不传入任何值,这样就可以保证在代码块中undefined标识符的值真的是undefined
(function IIFE(undefined) {
var a;
if (a === undefined) {
console.log("Undefined is safe here! ");
}
})();
区分函数声明和表达式最简单的方法是看function关键字出现在声明中的位置(不仅仅是一行代码,而是整个声明中的位置)。如果function是声明中的第一个词,那么就是一个函数声明,否则就是一个函数表达式
块作用域
举个例子🌰
for (var i=0; i<10; i++) {
console.log(i);
}
====等于如下代码====
var a;
for (i=0; i<10; i++) {
console.log(i);
}
实际上,代码中只需要让i出现在for循环内部,但是变量i污染到了整个作用域,这样的话就很容易引起变量的冲入或者其他意想不到的错误。
let
ES6为改变现状,引入了新的关键字let。let关键字可以将变量绑定到所在的任意作用域中(通常是{ .. }内部)。换句话说,let为其声明的变量隐式地劫持了所在的块作用域。
var foo = 1;
if (foo) {
let bar = foo * 2;
}
console.log(bar); // ReferenceError
let将bar隐士的绑定在了{}块级作用域中
const
除了let以外,ES6还引入了const,同样可以用来创建块作用域变量,但其值是固定的(常量)。之后任何试图修改值的操作都会引起错误。
var foo = true;
if (foo) {
var a = 2;
const b = 3; // 包含在if中的块作用域常量
a = 3; // 正常!
b = 4; // 错误!
}
console.log(a); // 3
console.log(b); // ReferenceError!
特殊
try/catch
JavaScript的ES3规范中规定try/catch的catch分句会创建一个块作用域,其中声明的变量仅在catch内部有效
try {
undefined(); // 执行一个非法操作来强制制造一个异常
} catch (err) {
console.log(err); // 能够正常执行!
}
console.log(err); // ReferenceError: err not found
with
with从对象中创建出的作用域仅在with声明中而非外部作用域中有效。