JS

函数作用域

 函数作用域的含义是指,属于这个函数的全部变量都可以在整个函数范围内使用及复用(事实上在嵌套作用域中也可以使用)。

  函数和函数表达式分辩

  看function出现的位置,如果是声明的第一个词就是函数,否则为函数表达式

  (function foo() {...})  函数表达式,只能在{...}位置被访问,外部作用域则不行

  function() {...}  函数声明

  1. 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
原文地址:https://www.cnblogs.com/zhoujin-Jojo/p/13714669.html