为什么在构造函数函数中使用此关键字

why use this keyword in constructor function

本文关键字:关键字 构造函数 函数 为什么      更新时间:2023-09-26

比较代码1和代码2,哪一个是正确的?

function Rectangle(height, width) {
  this.height = height;
  this.width = width;
  this.calcArea = function() { // why use this here?
      return this.height * this.width;
  };
}

代码2我觉得这个没问题:

function Rectangle(height, width) {
      this.height = height;
      this.width = width;
      calcArea = function() {
          return this.height * this.width;
      };
    }

哪一个是正确的?

这取决于您如何看待"正确":

  • 两个声明中的任何一个都无法正确解析吗?
    • 不,两者都是有效的JavaScript
  • 哪个将计算calcArea
    • 代码1将正确地计算它,而代码2不会创建Rectangle类的成员函数,但您可以使它正确地计算,并在广告重定向方面遇到一些困难。请参见下文
  • 创建类的一个好方法是什么?
    • 不,他们都没有。请参见底部

代码1-calcArea()

如果您在代码1中创建Rectangle的新实例,则:

function Rectangle(height, width) {
    this.height = height;
    this.width = width;
    this.calcArea = function() { // why use this here?
        return this.height * this.width;
    };    
}
var rect = new Rectangle( 3, 4 );
console.log( rect.calcArea() );

将正确输出12

代码2-calcArea()

如果您在代码2中创建Rectangle的新实例,则:

function Rectangle(height, width) {
    this.height = height;
    this.width = width;
    calcArea = function() {
        return this.height * this.width;
    };
}
var rect = new Rectangle( 3, 4 );
console.log( rect.calcArea() );

将抛出错误:TypeError: rect.calcArea is not a function

相反,calcArea被附加到全局范围,所以我们可以这样做:

console.log(calcArea());

将在全局作用域的一部分中将NaN输出为calcArea,因此不知道Rectangle类的任何实例,并且全局作用域不具有heightwidth属性。

如果我们这样做:

var rect = new Rectangle( 3, 4 );
width = 7;   // Set in the global scope.
height = 10; // Set in the global scope.
console.log( calcArea() );

然后它将返回70(而不是12,因为在calcArea()中,this引用的是全局作用域,而非rect对象)。

如果我们使用.call()来调用函数来更改this所指的内容:

var rect = new Rectangle( 3, 4 );
width = 7;   // Set in the global scope.
height = 10; // Set in the global scope.
console.log( calcArea.call( rect ) );

然后它将输出12(因为this现在指的是rect对象,而不是全局范围)。

您可能不希望每次使用calcArea()时都必须这样做。

为什么代码1不是最佳

代码1会起作用,但不是最佳解决方案,因为每次创建新的Rectangle对象时,它都会创建该对象的calcArea属性,该属性与任何其他Rectangle对象的任何calcArea属性都是不同的函数。

如果你这样做,你可以看到:

function Rectangle(height, width) {
    this.height = height;
    this.width = width;
    this.calcArea = function() { // why use this here?
        return this.height * this.width;
    };    
}
var r1 = new Rectangle( 3, 4 ),
    r2 = new Rectangle( 6, 7 );
console.log( r1.calcArea.toString() === r2.calcArea.toString() ); // Line 1
console.log( r1.calcArea === r2.calcArea );                       // Line 2

当测试函数的字符串表示是否相同时,它将输出true,而当测试函数是否相同时输出false

这是什么意思?如果您创建了10000个Rectangle实例,那么您也将有10000个不同的calcArea属性实例,并且每个副本都需要额外的内存(加上分配内存和最后垃圾收集内存的时间)。

什么是更好的练习

function Rectangle(height, width) {
      this.setHeight( height );
      this.setWidth( width );
}
Rectangle.prototype.setHeight = function( height ){ this.height = height; }
Rectangle.prototype.setWidth  = function( width  ){ this.width = width; }
Rectangle.prototype.calcArea  = function(){ return this.height * this.width; }

如果你这样做:

var r1 = new Rectangle( 3, 4 ),
    r2 = new Rectangle( 6, 7 );
console.log( r1.calcArea.toString() === r2.calcArea.toString() ); // Line 1
console.log( r1.calcArea === r2.calcArea );                       // Line 2

它将返回两者的true,这意味着r1.calcArear2.calcArea引用相同的函数,而不管Rectangle有多少实例。

如果不使用this,则无法通过Rectangle的对象访问calcArea。当你说

this.calcArea = function () ...

在当前对象(this)中创建一个新变量,函数将被分配给它,这样对象就可以访问它。

尝试以下语句,无论是否使用this。你会更好地理解的。

var a = new Rectangle(1, 2);
console.log(a.calcArea());

第二个版本将设置全局变量calcArea,以便在构建对象实例时执行特定于对象的操作。设置特定对象的属性时需要使用此选项。

当您在构造函数中为方法和属性加上"this"时,它们允许使用该构造函数创建的任何新对象使用这些属性和方法,并使这些属性和方式指向新创建的对象

如果您基于Rectangle构造函数的版本创建了一个新对象,该构造函数不使用"this"作为calcArea的序言,并查看chrome调试器,则会出现以下错误:

Object #<Rectangle> has no method 'calcArea' 

简而言之,它根本没有被识别。

不使用"this"的另一个方面是该方法变得"全局"。

下面是一个要演示的代码示例:

function Rectangle(height, width) {
  this.height = height;
  this.width = width;
  calcArea = function() { // Not prefaced with 'this'
      return 'hello world';
  };
}

var aNewObj = new Rectangle(10,10);
console.log(calcArea()) // Notice this is not aNewObj.calcArea() ...just calcArea() but its still accessible.