理解js中的作用域

350 阅读2分钟

一、首先我们了解一下作用域的分类

  • 全局作用域:全局作用域是未定义在某个函数内的
  • 函数作用域:局部作用域是定义在某个函数内的

二、通过实例理解作用域中的声明

  • 例子一:代码中a、b、c和f1均为全局作用域中声明,我们可以将全局理解为一级作用域,全局作用域中声明的函数为二级作用域,函数中的函数称为三级作用域,以此类推,级数大的可以访问级数小的

  • 图示,函数f1可以访问全局作用域中的声明

  • 例子二:代码中a、b、c、f1、f2都是全局作用域中的声明,d、e、f11是函数作用域中的声明

  • 图示:f1和f2可以访问全局作用域中的声明,f11可以访问全局作用域和f1中的声明

三、理解let、const、var

  • js是顺序执行的,所以代码执行后对应的变量和声明是可以被访问的,那么如果在var let const声明的变量之前访问会如何呢

    console.log(a) // undefined console.log(b) // 报错 console.log(c) // 报错 var a = 1 let b = 2 const c = 3

  • var存在变量提升,但是let和const不会,所以提前访问var声明的变量会打印undefined,不会报错

  • 函数声明也会提升,那么变量提升和函数提升哪个优先呢?

    console.log(a) // [Function: a] var a = 1 function a() { let d = 4 function f11() { return d } return f11() }

  • 从上面的实例中我们可以看出,函数声明提升优先于变量提升

四、call、apply和bind

  • 全局作用域中的this:在全局作用域中this指向window,像例一中的a b c和f1都是可以通过window.a window.b window.f1访问到

  • 函数作用域中的this:当函数作为对象的方法被调用时,this指向当前的对象;函数本身也有this对象,像下面的栗子

    var a = function (){ this.d = 4 console.log(this.d) } a() // 4

  • call、apply和bind会改变当前作用域中this的指向

    let obj1 = { prop: 'obj1' } let obj2 = { prop: 'obj2' } function a() { console.log(this.prop) } a.call(obj1) // obj1 a.call(obj2) // obj2 a.apply(obj1) // obj1 a.apply(obj2) // obj2 a.bind(obj1)() // obj1 a.bind(obj2)() // obj2

  • 箭头函数的this指向调用它的对象,如果调用它的对象也是一个箭头函数,那么就向再上一级寻找
  • 箭头函数的this指向不可改变