对于JavaScript中this指向的初步理解

94 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路

1、函数直接使用,this此时指向windows

  function get(content) {
    console.log(content);
  }
  
  get("你好"); // 你好
  // 上面的是下面的语法糖
  get.call(window, "你好"); // 你好

  var people = "outPeople";
  function hello() {
    let people = "innnerPeople";
    console.log("hello", this.people);
  }
  hello(); // hello outPeople
  // 上面的是下面的语法糖
  hello.call(window); // hello outPeople

2、函数作为对象的方法被调用,原则:谁调用我,this就指向谁

  var person = {
    name: "大明",
    run: function (time) {
      console.log(`${this.name}在跑步 最多${time}min就不行了`);
    },
  };
  var student = {
    name: "学生",
  };
  person.run(30); // 大明在跑步 最多30min就不行了
  // 上面的是下面的语法糖
  person.run.call(person, 30); // 大明在跑步 最多30min就不行了
  // 原则:谁调用我,我就指向谁,person调用run(),则this指向person
  // 改变调用函数的主体为student,student调用run(),则this指向student
  person.run.call(student, 20); // 学生在跑步 最多20min就不行了

了解了上面两个特性,尝试做两道题练练手吧!

题目一:控制台打印出什么?

  var name = 222;
  
  var a = {
    name: 111,
    say: function () {
      console.log(this.name); 
    },
  };

  var fun = a.say;
  fun();
  a.say();

题目一解析:

var fun = a.say = function () {
                      console.log(this.name); 
                  },
即
function fun () {
    console.log(this.name); 
}                  
fun()函数直接使用,即fun.call(window),所以打印结果为 window.name,即222
a.say() 这个即 a.say.call(a) 即 fun.call(a) ,a调用fun,所以this指向a,即a.name,即111

题目一答案:

  var name = 222;
  
  var a = {
    name: 111,
    say: function () {
      console.log(this.name); 
    },
  };

  var fun = a.say;
  fun(); // 222
  a.say(); // 111

题目二:在题目一的基础上,这次控制台打印出什么?

  var name = 222;
  
  var a = {
    name: 111,
    say: function () {
      console.log(this.name); 
    },
  };

  var fun = a.say;
  fun(); // 222
  a.say(); // 111
  // 主要看下半部分的控制台输出结果
  var b = {
    name: 333,
    say: function (fun) {
      fun();
    },
  };
  b.say(a.say);
  b.say = a.say;
  b.say();

题目二解析:

// 首先let fn1 =  a.say = function () {
                        console.log(this.name); 
                      },                      
b.say(a.say)即b.say(fn1)

令 let fn2 = b.say = function (fun) {
                        fun();
                      },                     
b.say(fn1)即fn2(fn1)

所以就是执行fn2(fn1),即fn1(),即直接调用fn1()函数,相当于fn1.call(window)
打印window.name,即222
                      
下面这种解释为什么错误?
a.say =  function () {
            console.log(this.name); 
         },
         
b.say =  function (fun) {
             fun();
         },
         
所以b.say(a.say) =  function (a.say) {
                         a.say()
                     },
                     
即b.say(a.say) 最后执行的是a.say(),即是a调用say()函数,即a.say.call(a),所以输出111
这里错误的原因在于:错把最后执行的a.say()当成a.say.call(a)的语法糖了,其实不然。
注意这里a.say()的上下文是
function (a.say) {
     a.say()
},
而不是全局作用域下的,是在函数作用域里面的,区分下面两个情况
情况一:
<script>
    a.say()
</script>

情况二:
<script>
    function (a.say) {
         a.say()
    },
</script>


// 其次
b.say =  a.say =  function () {
                    console.log(this.name); 
                  },
b.say(),这里就是b.say.call(b)的语法糖,所以输出b.name,即333                    

题目二答案:

  var name = 222;
  
  var a = {
    name: 111,
    say: function () {
      console.log(this.name); 
    },
  };

  var fun = a.say;
  fun(); // 222
  a.say(); // 111
  // 主要看下半部分的控制台输出结果
  var b = {
    name: 333,
    say: function (fun) {
      fun();
    },
  };
  b.say(a.say); // 222
  b.say = a.say;
  b.say(); // 333