JavaScript中this关键字指向规则详解与测试

作者:半夏时间:2026-10-22 07:01:06浏览:291

本文通过四道测试题深入解析JavaScript中this关键字的指向规则。详细讲解了四种核心场景:普通函数调用指向window、匿名函数自执行指向window、new构造函数指向实例对象,以及apply/call强制绑定this。通过代码示例对比不同调用方式下的this差异,帮助开发者准确理解并控制this指向。

前言

JavaScript this关键字指向规则测试

JavaScript是一种基于对象的动态语言,这意味着在JS中万物皆对象,函数也不例外,它们也是普通的对象类型。JavaScript支持多种设计模式来实现面向对象编程,其中this关键字是实现这一特性的关键机制。为了帮助读者更好地理解,我们先通过一组测试题来检验对this指向的掌握程度。如果全部答对,说明你已经掌握了基础,无需继续阅读后续解析。

测试题目

第一题


<script>
 var str = 'zhangsan';

 function demo() {
  var str = 'lisi';
  alert(this.str);
 }
 window.demo(); // ??

 var obj = {
  str: "wangwu",
  say: function() {
   alert(this.str);
  }
 }
 obj.say(); // ??

 var fun = obj.say;
 window.fun(); // ??
</script>

第二题


<script>
 var username = 'zhangsan';

 (function() {
  var username = 'lisi';
  alert(this.username); // ??
 })()

 function demo() {
  var username = 'wangwu';

  function test() {
   alert(this.username);
  }

  test(); // ??
 }
 demo();
</script>

第三题


<script>
 function Person() {
  this.username = 'zhangsan';
  this.say = function() {
   alert('我叫' + this.username);
  }
 }

 var p = new Person();
 p.say(); // ??

 var p1 = new Person();
 p1.say(); // ??
</script>

第四题


<script>
 var username = 'zhangsan';

 function demo() {
  alert(this.username)
 }

 var obj1 = {
  username: "lisi"
 };
 var obj2 = {
  username: "wangwu"
 };

 demo(); // ??
 demo(obj1); // ??
 demo(obj2); // ??
 demo.call(obj1); // ?? 
 demo.apply(obj2); // ??
</script>

答案

  • 第一题:zhangsan wangwu zhangsan
  • 第二题:zhangsan zhangsan
  • 第三题:我叫zhangsan 我叫zhangsan
  • 第四题:zhangsan zhangsan zhangsan lisi wangwu

(往下看,下面有详细解析哦)

this关键字的四种指向场景

this

  • 指向调用函数的对象
  • 无对象调用函数/匿名函数自调用(this指向window)
  • 通过new产生的对象
  • apply/call调用

场景一:指向调用函数的对象

一、指向调用函数的对象


<script>
 // this:指向调用函数的对象
 var str = 'zhangsan';

 function demo() {
  var str = 'lisi';

  //this->window
  console.log(this);
  alert(this.str);
 }
 window.demo(); // zhangsan

 var obj = {
  str: "wangwu",
  say: function() {
   // this->obj
   alert(this.str);
  }
 }
 obj.say(); // wangwu

 var fun = obj.say;
 window.fun(); // zhangsan
</script>
  • 当全局函数(如demo)作为window对象的方法被调用时,this指向window。
  • 当通过对象调用其方法(如obj.say)时,this指向该对象(obj)。
  • 如果将对象的方法赋值给一个普通变量(如var fun = obj.say),然后直接调用该变量(fun()),此时fun只是一个函数引用,并未通过对象调用。因此,this指向全局对象window。注意,只有obj.say()才是通过对象调用函数。
  • 核心原则:谁调用了函数,this就指向谁。

场景二:无对象调用与匿名函数自执行

二、无对象调用函数/匿名函数自调用->this指向window


<script>
 // 2.匿名函数自执行|匿名函数|无主函数 this->window
 var username = 'zhangsan';

 // 匿名函数自执行 this->window
 (function() {
  var username = 'lisi';
  console.log(this); // window
  alert(this.username); // zhangsan
 })()

 function demo() {
  var username = 'wangwu';

  // 无主函数 this->window
  function test() {
   // this->window
   alert(this.username);
  }

  test(); // zhangsan
 }
 demo();
</script>
  • 匿名函数没有名称,在浏览器环境中默认挂载到window对象上。
  • 对于内部定义的函数test(),如果它没有被任何对象显式调用(既不是window也不是demo直接调用),它就像一个“无主”函数。在这种情况下,非严格模式下,this默认指向全局对象window。

场景三:通过new关键字产生对象

三、通过new产生的对象


<script>
 // 3.通过new的对象:this指向产生的对象
 // 函数
 function Person() {
  // 属性
  this.username = 'zhangsan';
  // 方法
  this.say = function() {
   // this->p
   console.log(this); // Person对象
   alert('我叫' + this.username);
  }
 }

 // 实例化出一个对象:p就具有了username属性和say方法
 var p = new Person();
 console.log(p); // Person对象
 console.log(p.username); // zhangsan
 p.say(); // 我叫zhangsan

 // this->p1
 var p1 = new Person();
 p1.say(); // Person对象 我叫zhangsan
</script>
  • 当构造函数内部使用this定义属性和方法时,必须通过new关键字来实例化对象。new操作会创建一个新的对象,并将构造函数内部的this绑定到这个新对象上,从而使属性和方法具有实际价值。

场景四:apply与call方法调用

四、apply/call调用

首先我们需要了解apply()和call()方法的作用。

apply()和call()的本质都是调用函数,但它们允许你指定函数内部this的指向,即thisObj。


function.call([thisObj[,arg1[, arg2[, [,.argN]]]]])
function.apply([thisObj[,argArray]])

注意:

1. 虽然调用的是原函数,但函数内部的this会被强制指向传入的thisObj(即更改了对象内部的指针指向)。

2. 如果调用apply或call时没有传入第一个参数(thisObj),则默认this指向全局对象(浏览器中为window)。

3. call()与apply()的联系与区别

联系:两者的功能完全一致,第一个参数都是用于指定this指向的对象(thisObj)。

区别:主要在于传递后续参数的方式不同,当参数较多时体现明显。

call()要求将实参一一列出,作为独立的参数传递。

apply()要求将所有实参放置在一个数组中,作为第二个参数传递。

一个理解apply()/call()的实例:


<script>
 // apply()/call()
 function demo() {
  console.log(123);
 }

 // 调用函数的时候,demo.call()/demo.apply()最终调用的还是demo()
 demo(); // 123
 demo.call(); //123
 demo.apply(); // 123
</script>

<script>
 // call()/apply()的区别:
 // call()参数单独再call中罗列
 // apply()的参数通过数组表示
 function demo(m, n, a, b) {
  alert(m + n + a + b);
 }
 demo(1, 5, 3, 4); // 13
 demo.call(null, 1, 5, 3, 4); // 13
 demo.apply(null, [1, 5, 3, 4]); // 13
</script>

this的第四个用法实例


<script>
 // this的第四个用法:call(obj)/apply(obj):强制性的将this指向了obj
 var username = 'zhangsan';

 function demo() {
  alert(this.username)
 }

 var obj1 = {
  username: "lisi"
 };
 var obj2 = {
  username: "wangwu"
 };

 // call()/apply():打劫式的改变了this的指向
 demo(); // zhangsan
 demo(obj1); //zhangsan
 demo(obj2); //zhangsan
 demo.call(obj1); // lisi 
 demo.apply(obj2); // wangwu
</script>
  • 如果直接调用demo函数,无论是否传入obj1或obj2作为参数,demo依然属于window调用,this指向window。
  • 无论使用call还是apply,最终执行的仍然是demo函数,但它们会强制将this指向第一个参数指定的对象(obj1或obj2)。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对本站的支持。

作者最新文章