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

时间:2013-12-14 05:54:44

标签: javascript this

比较代码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;
      };

    }

4 个答案:

答案 0 :(得分:1)

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

this.calcArea = function () ...

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

尝试使用和不使用this的这些语句。你会更好地理解。

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

答案 1 :(得分:1)

  

哪一个是正确的?

这取决于您查看“正确”的方式:

  • 这两个声明都无法正确解析吗?
    • 不,两者都是有效的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对象。 / p>

如果我们使用.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属性,该属性与任何{{1}不同。任何其他calcArea对象的属性。

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

Rectangle

在测试函数的字符串表示时,输出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

这是什么意思?如果您创建10,000个false实例,那么您将拥有10,000个Rectangle属性的不同实例,每个副本将需要额外的内存(加上时间分配该内存并在最后垃圾收集它) )。

什么是更好的做法?

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 - 意味着truer1.calcArea引用相同的函数,而不管r2.calcArea的实例数是多少。

答案 2 :(得分:0)

第二个版本将设置全局变量calcArea,以便在构造对象的实例时执行特定于对象的内容。设置特定对象的属性需要使用它。

答案 3 :(得分:0)

当你在构造函数中使用'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.