which one is correct?
这取决于你如何看待 “正确”:
- 要么声明不能被正确解析?
- 哪一个会计算
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()
如果创建Rectangle
在随后码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.calcArea is not a function
calcArea
是,而是附着在全球范围内,所以我们可以做:
console.log(calcArea());
将输出NaN
为calcArea
在全球范围内的一部分,所以没有一个Rectangle
类的任何实例的知识和全球范围内不具有height
或width
属性。
如果我们这样做:
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
的属性,对象是一个不同的功能任何其他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
测试功能是否相同的时候。
这是什么意思?如果您创建了1万个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.calcArea
和r2.calcArea
指的是相同的功能,不管有多少实例的Rectangle
有。
在第一个片段中,'calcArea'是'new Rectangle()'创建的'Rectangle'的一个属性。在第二个片段中,'calcArea'是一个全局变量。 –
@ChrisMartin我们如何确保它是全球性的? – thefourtheye
阅读https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Values,_variables,_and_literals,特别是“声明变量”部分。 –