【问题标题】:why use this keyword in constructor function为什么在构造函数中使用 this 关键字
【发布时间】:2013-12-14 05:54:44
【问题描述】:

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

    }

【问题讨论】:

  • 在第一个sn-p中,calcAreanew Rectangle()创建的Rectangle的一个属性。在第二个 sn-p 中,calcArea 是一个全局变量。
  • @ChrisMartin 我们如何确保它是全球性的?
  • 阅读developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/…,尤其是“声明变量”部分。

标签: javascript this


【解决方案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 对象)。

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

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 属性,该属性与任何其他 @ 的任何 calcArea 属性不同。 987654354@对象。

如果你这样做,你会看到这个:

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

这是什么意思?如果您创建 10,000 个 Rectangle 实例,那么您还将拥有 10,000 个不同的 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 实例。

【讨论】:

    【解决方案2】:

    如果不使用thiscalcArea 将无法通过 Rectangle 对象访问。当你说,

    this.calcArea = function () ...
    

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

    试试这些语句,不管有没有this。你会明白的。

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

    【讨论】:

    • 使用this.calcArea = function() ... 将创建一个附加到Rectangle 类实例的属性 - 因此,如果您创建10,000 个Rectangle 实例,那么您还将创建10,000 个calcArea 函数实例.应该做的是将成员函数附加到类的原型 - 例如:function Rectangle(w,h){this.setWidth(w); this.setHeight(h);}; Rectangle.prototype.setWidth = function(w){ this.width = w;}; Rectangle.prototype.setHeight = function(h){ this.height = h;}; Rectangle.prototype.calcArea = function(){ return this.width*this.height;};
    • @MT0 OP 只是想知道为什么在那里使用this
    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        猜你喜欢
        • 2014-07-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-04-26
        • 1970-01-01
        • 2019-09-05
        • 1970-01-01
        相关资源
        最近更新 更多