JavaScript this 指向 - 练习题

32 阅读3分钟

为了助记:

以下是 20 道考察 this指向的题目,涵盖各种场景。自己先思考答案,再看解析:

基础题(1-10)

1. 全局调用

var a = 1;
function test() {
  console.log(this.a);
}
test();

2. 对象方法调用

var obj = {
  a: 2,
  test: function() {
    console.log(this.a);
  }
};
obj.test();

3. 方法赋值后调用

var a = 1;
var obj = {
  a: 2,
  test: function() {
    console.log(this.a);
  }
};
var foo = obj.test;
foo();

4. 多层对象

var a = 1;
var obj1 = {
  a: 2,
  obj2: {
    a: 3,
    test: function() {
      console.log(this.a);
    }
  }
};
obj1.obj2.test();

5. 回调函数

var a = 1;
var obj = {
  a: 2,
  test: function() {
    console.log(this.a);
  }
};
setTimeout(obj.test, 100);

6. 构造函数

function Person(name) {
  this.name = name;
  console.log(this);
}
var p = new Person('Alice');

7. 箭头函数

var a = 1;
var obj = {
  a: 2,
  test: () => {
    console.log(this.a);
  }
};
obj.test();

8. 嵌套箭头函数

var a = 1;
var obj = {
  a: 2,
  test: function() {
    return () => {
      console.log(this.a);
    };
  }
};
obj.test()();

9. 方法中的函数

var a = 1;
var obj = {
  a: 2,
  test: function() {
    function inner() {
      console.log(this.a);
    }
    inner();
  }
};
obj.test();

10. 立即执行函数

var a = 1;
var obj = {
  a: 2,
  test: (function() {
    console.log(this.a);
  })()
};

进阶题(11-20)

11. call/apply

var a = 1;
var obj1 = { a: 2 };
var obj2 = { a: 3 };

function test() {
  console.log(this.a);
}

test.call(obj1);
test.apply(obj2);

12. bind

var a = 1;
var obj = { a: 2 };

function test() {
  console.log(this.a);
}

var boundTest = test.bind(obj);
boundTest();

var obj2 = { a: 3, test: boundTest };
obj2.test();

13. bind + new

function Person(name) {
  this.name = name;
}
Person.prototype.sayName = function() {
  console.log(this.name);
};

var obj = {};
var BoundPerson = Person.bind(obj);
var p = new BoundPerson('Alice');
p.sayName();
console.log(obj.name);

14. 严格模式

'use strict';
var a = 1;
function test() {
  console.log(this);
}
test();

15. 箭头函数 + call

var a = 1;
var obj = { a: 2 };
var test = () => {
  console.log(this.a);
};
test.call(obj);

16. 事件处理器

// 假设在浏览器中
var button = document.createElement('button');
button.textContent = 'Click me';

var obj = {
  a: 1,
  handleClick: function() {
    console.log(this.a);
  }
};

button.addEventListener('click', obj.handleClick);
button.click();  // 模拟点击

17. 类中的 this

class Person {
  constructor(name) {
    this.name = name;
  }
  
  sayName() {
    console.log(this.name);
  }
  
  sayNameArrow = () => {
    console.log(this.name);
  }
}

const p = new Person('Bob');
const { sayName, sayNameArrow } = p;
sayName();
sayNameArrow();

18. 原型链上的 this

function Person(name) {
  this.name = name;
}

Person.prototype.sayName = function() {
  console.log(this.name);
};

var p1 = new Person('Alice');
var p2 = new Person('Bob');

p1.sayName();
p2.sayName();

19. 多层 bind

var obj1 = { a: 1 };
var obj2 = { a: 2 };
var obj3 = { a: 3 };

function test() {
  console.log(this.a);
}

var test1 = test.bind(obj1);
var test2 = test1.bind(obj2);
var test3 = test2.bind(obj3);

test3();

20. 综合题

var length = 10;
function fn() {
  console.log(this.length);
}

var obj = {
  length: 5,
  method: function(fn) {
    fn();
    arguments[0]();
  }
};

obj.method(fn, 1, 2, 3);

挑战题(额外)

21. 链式调用

var obj = {
  value: 1,
  increment: function() {
    this.value++;
    return this;
  },
  getValue: function() {
    return this.value;
  }
};

console.log(obj.increment().increment().getValue());

22. 模块模式

var calculator = (function() {
  var value = 0;
  
  return {
    add: function(x) {
      value += x;
      return this;
    },
    getValue: function() {
      return value;
    },
    reset: function() {
      value = 0;
    }
  };
})();

calculator.add(5).add(3);
console.log(calculator.getValue());

23. 数组方法中的 this

var obj = {
  data: [1, 2, 3, 4, 5],
  multiplier: 2,
  multiply: function() {
    return this.data.map(function(item) {
      return item * this.multiplier;
    });
  }
};

console.log(obj.multiply());

24. 修复数组方法中的 this

var obj = {
  data: [1, 2, 3, 4, 5],
  multiplier: 2,
  multiply: function() {
    return this.data.map(function(item) {
      return item * this.multiplier;
    }, this);
  }
};

console.log(obj.multiply());

25. Proxy 中的 this

var target = {
  value: 1,
  getValue: function() {
    return this.value;
  }
};

var handler = {
  get: function(obj, prop) {
    if (prop === 'value') {
      return 100;
    }
    return obj[prop];
  }
};

var proxy = new Proxy(target, handler);
console.log(proxy.getValue());

答案解析指南

回答时,考虑以下因素:

  1. 调用方式(普通函数、方法、构造函数、call/apply/bind)
  2. 是否严格模式
  3. 箭头函数 vs 普通函数
  4. 事件处理器
  5. 回调函数
  6. 嵌套函数
  7. 类方法
  8. 原型方法
  9. 立即执行函数
  10. 链式调用

学习建议

  1. 先自己写出每道题的答案
  2. 在浏览器控制台或 Node.js 中运行验证
  3. 对于错误的题目,仔细分析原因
  4. 总结 this的绑定规则
  5. 尝试修改代码,看输出如何变化

具体解析,请移步: JavaScript this 指向 - 练习题 - 详细解析