黄子涵

5.14 引用

this 引用是一种在 JavaScript 的代码中随时都可以使用的只读变量。在 Java 或 C++ 中也有功能类似的 this 引用。在 Java 以及 C++ 中,this 应该被看作是隐式传递的参数,而在 JavaScript 中,this 引用可以在最外层代码(函数之外)使用,所以从直觉上更像是一个可以随时使用的只读变量。

this 引用引用的是一个对象。对于最外层代码与函数内部的情况,其引用目标是不同的。此外,即使在函数内部,根据函数调用方式的不同,引用对象也会有所不同。需要注意的是,this引用有着会根据代码的上下文语境自动改变其引用对象的特性。

5.14.1 this 引用的规则

在此,总结一下 this 引用的规则。

  • 在最外层代码中,this 引用引用的是全局对象。
  • 在函数内,this 引用根据函数调用方式的不同而有所不同(参见表 5.3)。

需要注意的是,对于函数内部的情况,this 引用的引用对象并不是根据函数的内容或声明方式而改变的,而是根据其调用方式而改变。也就是说,即使是同一个函数,如果调用方式不同,this 引用的引用对象也会有所不同。

表 5.3 函数内部的 this 引用
函数的调用方式 this 引用的引用对象
构造函数调用 所生成的对象
方法调用 接收方对象
apply 或是 call 调用 由 apply 或 call 的参数指定的对象
其他方式的调用 全局对象

对于构造函数调用的情况,this 引用的引用对象是所生成的对象。

表 5.2 的方法调用的说明中的接收方对象是这样一种对象。

  • 通过点运算符或中括号运算符调用对象的方法时,在运算符左侧所指定的对象。

方法是对象的属性所引用的函数。下面是一个关于方法和接收方对象的具体例子。

var hzh = {
       x: 3,
       huangzihan: function() { console.log("方法已经被调用!" + this.x); }       
}

console.log("使用点运算符调用huangzihan方法:");
hzh.huangzihan();    // 对象hzh是接收方对象。huangzihan是方法。
console.log("");
console.log("使用中括号运算符调用huangzihan方法:");
hzh['huangzihan'](); // 对象hzh是接收方对象。黄子涵是方法。
[Running] node "e:\HMV\JavaScript\JavaScript.js"
使用点运算符调用huangzihan方法:
方法已经被调用!3

使用中括号运算符调用huangzihan方法:
方法已经被调用!3

[Done] exited with code=0 in 0.174 seconds

现在说明上面的例子。首先是将对象的引用赋值给了变量 hzh。这个对象有两个属性。属性 x 的值为数值 3,属性 huangzihan 的值是一个函数。将该函数称为方法 huangzihan。

可以通过点运算符或中括号运算符对 hzh 调用方法 huangzihan。这时,方法调用的目标对象被称为接收方对象(也就是说,hzh 所引用的对象是一个接收方对象)。被调用的方法内的 this 引用引用了该接收方对象。

由于 this 引用具有这样的特性,JavaScript 的方法拥有了与 Java 或 C++ 中的方法相似的功能。

5.14.2 this 引用的注意点

虽然 JavaScript 的 this 引用在方法调用中的执行方式和 Java 或 C++ 中的基本相同,但仍应注意它们之间存在一些细微的差别。在 Java 这样的基于类的语言中,this 所引用的接收方对象始终是该类的实例,而在 JavaScript 中,却不一定总是如此。

JavaScript 的 this 引用的引用对象,会随着方法调用方式的不同而改变。下面是一个简单的例子,用于说明通过其他的接收方对象调用某个函数,或是在没有接收方对象的情况下,this 引用的操作是不同的。

var hzh = {
       x: 3,
       huangzihan: function() { console.log("方法已经被调用!" + this.x); }       
}

var hcq = hzh.huangzihan;             // 将 hzh.huangzihan 引用的 Function 对象赋值给全局变量 hcq

console.log("调用全局函数hcq:");
hcq();
console.log("");

var x = 5;                            // 确认 this 引用确实引用了全局变量
console.log("再次调用全局函数hcq:");
hcq();
console.log("");

var hzh2 = { x:4, huangzihan2:hcq }; // 将 hzh 的方法( Function 对象的引用)赋值给了另一个对象 hzh2 的属性
console.log("调用hzh2对象的huangzihan2方法:");
hzh2.huangzihan2();                  // 方法内的 this 引用引用了对象 huangzihan2
[Running] node "e:\HMV\JavaScript\JavaScript.js"
调用全局函数hcq:
方法已经被调用!undefined

再次调用全局函数hcq:
方法已经被调用!undefined

调用hzh2对象的huangzihan2方法:
方法已经被调用!4

[Done] exited with code=0 in 0.177 seconds

在 Java 中常常可以省略 this,不用明确地写出。因为在查找方法内的名称时总是会在同一个类的域名与方法名中搜索。而在 JavaScript 中就不能像这样省略 this 了。如果在上面的例子中将 this.x 改写为 x,它的含义将会变为全局变量 x。

在方法内部调用方法的情况

在方法内部调用方法时也需要对 this 引用多加注意,下面是一个例子。通常在 Java 或 C++ 中的方法内进行方法调用时会省略 this,然而在 JavaScript 的方法内调用其他的方法时,必须像下面的例子那样通过 this 引用来实现。

// 从 huangzihan 方法内调用 huangzihan2 方法时,必须通过 this 引用,以this.huangzihan2() 的方式实现
var hzh = {
       x: 3,
       huangzihan: function () {
              console.log("huangzihan已经被调用!" + this.x);
              this.huangzihan2();
       },
       huangzihan2: function () {
              console.log("huangzihan2方法已经被调用!" + this.x);
       }
}

console.log("访问hzh对象的huangzihan方法:");
hzh.huangzihan();
[Running] node "e:\HMV\JavaScript\JavaScript.js"
访问hzh对象的huangzihan方法:
huangzihan已经被调用!3
huangzihan2方法已经被调用!3

[Done] exited with code=0 in 0.195 seconds

在上面的例子中,如果将 this.huangzihan2() 写成 huangzihan2(),则会在全局函数中搜索 huangzihan2。在没有语法错误时,嵌套的函数将按作用域由内至外的顺序来查找名称。

posted @ 2022-05-28 13:13  黄子涵  阅读(23)  评论(0编辑  收藏  举报