两个公式,帮你彻底解决js变量访问问题

93 阅读3分钟
  • 公式一:没有this => 只跟函数作用域定义位置有关(无论在哪调用)
  • 公式二:有this => 只跟函数调用对象有关(无论在哪定义)

1. 公式一

题1. fn1 函数作用域内 定义函数fn2,打印结果为20

var age = 10
​
function fn1() {
  var age = 20
  function fn2() {
    console.log(age); // 20
  }
  fn2()
}
​
fn1() 
// 变量age在fn2自身作用域找不到,向上一级去找
// 因为fn2在fn1作用域内定义的,所以fn2的上一级作用域是fn1的作用域
// 打印的age是fn1作用域内声明的变量

题2. fn1 函数作用域外 定义函数fn2,fn2在fn1内调用,打印结果为10

var age = 10
​
function fn2() {
  console.log(age); // 10
}
​
function fn1() {
  var age = 20
  fn2()
}
​
fn1()
// 变量age在fn2自身作用域找不到,向上一级去找
// 因为fn2在全局作用域内定义的,所以fn2的上一级作用域是全局作用域
// 打印的age是全局作用域内声明的变量

题3. fn1 函数作用域外 定义函数fn2,fn2作为fn1的参数,在fn1内调用,打印结果为10

var age = 10
​
function fn2() {
  console.log(age); //10
}
​
function fn1(fn) {
  var age = 20
  fn()
}
​
fn1(fn2)
// 变量age在fn2自身作用域找不到,向上一级去找
// 因为fn2在全局作用域内定义的,所以fn2的上一级作用域是全局作用域
// 打印的age是全局作用域内声明的变量

题4. obj对象方法fn1内 定义函数fn2, 在fn1内调用,打印结果为10

var age = 10var obj = {
  age: 20,
  fn1() {
    function fn2() {
      console.log(age); // 10
    }
    fn2()
  }
}
​
obj.fn1()
// 变量age在fn2自身作用域找不到,向上一级去找
// 因为fn2在fn1作用域内定义的,所以fn2的上一级作用域是fn1作用域
// fn1作用域内并没有声明的age变量,继续向上一级查找
// 虽然fn1是对象obj的方法,但是对象obj并不能称之为fn1的上一级作用域,fn1的上一级作用域是全局作用域
// 打印的age是全局作用域内声明的变量

2. 公式二

题5. fn1 函数作用域内 定义函数fn2,打印结果为10 (只在第1题的基础上加个this)

var age = 10
​
function fn1() {
  var age = 20
  function fn2() {
    console.log(this.age); // 10
  }
  fn2()
}
​
fn1() 
// 函数在没有指定对象调用时,this指向window(node环境指向global)
// fn2()执行时,没有指定对象调用,所以this.age中的this指向window
// 在全局用var定义的变量都是window的属性(let,const定义的不是),所以this.age === window.age
// 打印的this.age是window.age

题6. obj对象方法fn1内 定义函数fn2, 在fn1内调用,打印结果为10 (只在第4题的基础上加个this)

var age = 10var obj = {
  age: 20,
  fn1() {
    function fn2() {
      console.log(this.age); // 10
    }
    fn2()
  }
}
​
obj.fn1()
// 这题很容易被迷惑,不要以为在一个对象里面看到this,这个this就一定指向该对象
// 记住公式二,fn2()执行时,并没有指定对象调用,所以this.age中的this指向window
// 打印的this.age是window.age

题7. fn1 函数作用域内 定义函数fn2, 在fn1内指定obj对象调用,打印结果为10

var obj = {
  age: 10
}
var age = 30
function fn1() {
  var age = 20;
  function fn2() {
    console.log(this.age);
  }
  fn2.call(obj)
}
fn1()
// 根据公式二,fn2()执行时,指定obj对象调用,所以this.age中的this指向obj
// 打印的this.age是obj.age