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

Javascript 为什么在构造函数中使用此关键字,javascript,this,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) {

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

    }

如果不使用
,则无法通过矩形对象访问
Calcara
。当你说

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

尝试这些语句,包括和不包括
this
。你会更明白的

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

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

在构造函数中用“this”作为方法和属性的开头时,它们允许使用该构造函数创建的任何新对象使用这些属性和方法,并使这些属性和方法指向新创建的对象

如果您基于矩形构造函数的版本创建了一个新对象,而该矩形构造函数没有使用“this”作为Calcrea的序言,并查看chrome调试器,则会出现以下错误:

Object #<Rectangle> has no method 'calcArea' 
哪一个是正确的

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

}
这取决于您如何看待“正确”:

  • 两个声明都不能正确解析吗?
    • 不,两者都是有效的JavaScript
  • 哪一个将计算Calcrea?
    • 代码1将正确地计算它,而代码2不会创建Rectangle类的成员函数,但是您可以让它正确地计算,这有点困难。见下文
  • 创建类的一个好做法是什么?
    • 没有,他们两个都没有。看下面
代码1-calcArea()

如果在代码1中创建一个新的
矩形实例
,则:

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中创建一个新的
矩形实例
,则:

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.calcrea不是函数

calcArea
与全球范围相连,因此我们可以:

console.log(calcArea())

将在全局范围的一部分中输出
NaN
作为
Calcrea
,因此不知道
矩形
类的任何实例,并且全局范围没有
高度
宽度
属性

如果我们这样做:

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()
中,
引用全局范围,而不是
rect
对象)

如果我们更改此引用的调用函数:

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
(因为
现在指的是
rect
对象,而不是全局范围)

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

为什么代码1不是最佳的

代码1可以工作,但不是最佳解决方案,因为每次创建新的矩形对象时,它都会创建该对象的calcArea属性,该属性与任何其他矩形对象的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
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个
矩形
实例,那么
calcArea
属性也将有10000个不同的实例,并且每个副本都需要额外的内存(加上分配该内存并在最后对其进行垃圾收集的时间)

什么是更好的练习?

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; }
如果你这样做了:

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
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.calcrea
r2.calcrea
引用相同的函数,而不管有多少个
Rectangle
实例。

在第一个代码段中,
calcrea
new Rectangle()创建的
Rectangle
的属性
。在第二个代码段中,
calcArea
是一个全局变量。@ChrisMartin如何确保它是全局变量?请阅读,尤其是“声明变量”部分。使用
this.calcArea=function()…
将创建一个附加到类
矩形
实例的属性-因此,如果创建10000个
矩形
实例,则还将创建10000个
Calcrea
函数实例。应该做的是将成员函数附加到类的原型上,比如:
函数矩形(w,h){this.setWidth(w);this.setHeight(h);};Rectangle.prototype.setWidth=函数(w){this.width=w;};Rectangle.prototype.setHeight=函数(h){this.height=h;};Rectangle.prototype.calcrea=function(){返回this.width*this.height;}
@mt0op只是想知道为什么在那里使用这个