关于 this 的问题,我们只需要记住一个原则,谁调用的我,我的 this 就指向谁(尖头函数和 new 的情况除外除外)

下面通过两个面试题来解释一下 this 的相关问题。

普通函数的 this

题目:请写出输出值,并解释为什么

  1. this.a = 20;
  2. function go() {
  3. console.log(this.a);
  4. this.a = 30;
  5. }
  6. go.prototype.a = 40;
  7. var test = {
  8. a: 50,
  9. init: function (fn) {
  10. fn();
  11. console.log(this.a);
  12. return fn;
  13. }
  14. };
  15. console.log((new go()).a);
  16. test.init(go);
  17. var p = test.init(go);
  18. p();
  1. 普通函数的 this 是谁调用它,this 就指向谁!
  1. var name = "window";
  2. var o = {
  3. name: "o",
  4. init: function() {
  5. console.log(this.name);
  6. }
  7. }
  8. o.init(); // o
  9. var init = o.init;
  10. init(); // window
  1. 调用实例化对象的属性时,是先从构造函数中查找,如果没有找到则在原型链上逐级寻找

所以输出如下

  • 40 // 因为在 console 时构造函数中还没有定义属性 a,所有会找到原型链上的 a
  • 30 // 此时构造函数上中已经定义了属性 a 了,所以输出 30
  • 20 // test.init 中的 fn 是直接调用,并没有依附任何对象,所以 fn 中的 this 指向 window,所以输出 20,注意这一步又把 windowa 赋值为 30 了
  • 50 // init 因为是从 test 调用的,所以 this 指向 test ,所以输出 50
  • 30 // fnthis 依然是 window ,因为上一步 window.a 被修改了,所以输出 30
  • 50 // init 因为是从 test 调用的,所以 this 指向 test ,所以输出 50
  • 30 // fnreturn 出来了,但是依然是直接调用的, this 还是指向 window ,所以输出还是 30

    箭头函数的 this

    题目:请写出输出值,并解释为什么 ```javascript this.a = 50;

var app = { start: function () { var test2 = { a: 30, demo: { a: 70, init: () => { console.log(this) console.log(this.a) } } } test2.demo.init(); var init = test2.demo.init; init() } }

app.start();

const start = app.start; start();

  1. 箭头函数的 `this` 永远和当前执行环境的 `this` 相同!
  2. ```javascript
  3. app.start();

当前环境的 this 指向 app ,所以 init 不管怎么调用, this 都指向 app

  1. const start = app.start;
  2. start();

当前环境的 this 指向 window ,所以 init 不管怎么调用, this 都指向 window

属性查找优先级

题目:请写出输出值,并解释为什么

  1. function C1(name) {
  2. if (name) this.name = name;
  3. }
  4. function C2(name) {
  5. this.name = name;
  6. }
  7. function C3(name) {
  8. this.name = name || 'fe';
  9. }
  10. C1.prototype.name = "yideng";
  11. C2.prototype.name = "lao";
  12. C3.prototype.name = "yuan";
  13. console.log((new C1().name) + (new C2().name) + (new C3().name));

所有的构造函数都没有传参

  • C1 因为判断了 name 是否有效,不会在构造函数中创建属性 a ,所以会在原型链中寻在,输出为 "yideng"
  • C2 name 没有传所以值为 undefined ,输出为 undefined
  • C3 因为有 || ,所以 name 被赋值为 "fe",输出为 “fe”

所以最终输出为 "yidengundefinedfe"

🚀 推荐阅读