函数作用域
函数作用域的含义是指,属于这个函数的全部变量都可以在整个函数范围内使用及复用(事实上在嵌套作用域中也可以使用)。
函数和函数表达式分辩
看function出现的位置,如果是声明的第一个词就是函数,否则为函数表达式
(function foo() {...}) 函数表达式,只能在{...}位置被访问,外部作用域则不行
function() {...} 函数声明
- var 隐式定义变量
function foo() { var a = b = 1 } foo() console.log(a) // undefined console.log(b) // 1
var a = b = 1 隐式创建了一个全局变量b,a的作用域在foo函数内,因此外部不能访问函数内部变量,可以访问全局变量。如果需要同时创建两个函数内变量,可以使用 var a = 1 , b = 1
块作用域
js中没有块级作用域,使用var声明的变量时写在哪里都是一样的,因为他们最终都会属于外部作用域
for(var i = 0; i < 10; i++) { console.log(i) } 等价于 var i = 0; for(; i < 10; i++) { console.log(i) }
附:经典面试题
for(var i=0; i<=5; i++) { setTimeout(function timer() { console.log(i) }, 1000) } // 输出为 6 6 6 6 6 6 // 闭包解决作用域问题,每次存储i的值 for(var i=0; i<=5; i++) { (function(j){ setTimeout(function timer() { console.log(j) }, j*1000) })(i) } // 输出为 1 2 3 4 5 6
// es6中添加了let用来劫持块作用域,简单的解决上面的问题
首先js是单线程,先执行同步操作,后执行异步操作,setTimeout为异步,所以先执行完for循环后执行定时器,但由于i为全局变量,for循环执行完后i被改变为6,此时有6个定时器被阻塞分别执行,即输出为6个6
使用闭包每次循环将i值存储起来,互不影响,即达到顺序输出的结果
变量提升
consoel.log(a) var a = 2 变量提升转换为 var a console.log(a) // undefined a = 2 // ------------------------------------ a = 2 var a console.log(a) 变量提升转换为 var a a = 2 console.log(a) // 2
函数提升
foo() function foo() { a = 2 console.log(a) // 2 var a // 提升变量到第一行 } // 提升函数声明到调用之前,因此不会报错 // ------------------------------------------------- foo() // TypeError 函数表达式不会被提升 var foo = function bar() {}
* 函数提升会优先于变量提升,变量与方法同名会被忽略,后面的方法会覆盖前面的方法
foo() function foo() { console.log(1) } // 被提升至调用之前 var foo // 提升至方法之后,方法提升优先于变量 function foo() { console.log(2) } // 紧跟上一个方法提升 等价于 function foo() { console.log(1) } function foo() { console.log(2) } var foo foo() // 输出2,第二个方法将第一个覆盖,变量未赋值,忽略
try...catch...finally语句
try执行代码块,catch捕获异常,finally不管是否抛出异常都必须执行的语句
语句的三种组合形式:
1. try{...} catch(e) {...}
2. try{...} finally{...}
3. try{...} catch(e) {...} finally{...}
执行顺序:如果内部抛出异常,外部捕获之前必须要先执行内部的finally
try { try { throw new Error('oops') } catch(e) { console.log('inner', e) throw(e) } finally { console.log('inner finally') } } catch(e) { console.log('outer', e) } // inner oops // inner finally // outer oops