在JavaScript中你可以通过许多不同的方式做同样的事情。
考虑以下示例:
1:
function Circle(radius) {
return {
"r" : radius,
"area" : function(){
return Circle.pi * this.r * this.r;
}
}
}
Circle.pi = 3.14159;
var a = Circle(10);
alert(a.area());
2:
function Circle(radius) {
this.r = radius;
}
Circle.pi = 3.14159;
Circle.prototype.area = function(){
return Circle.pi * this.r * this.r;
}
var a = new Circle(10);
alert(a.area());
第二个比第一个好,因为我们没有为 Circle 的任何实例定义相同的函数 area 。
但我们考虑一下 3:
function Circle(radius) {
return {
"r" : radius,
"area" : Circle.area
}
}
Circle.pi = 3.14159;
Circle.area = function(){
return Circle.pi * this.r * this.r;
}
var a = Circle(10);
alert(a.area());
有没有理由更喜欢第二种风格而不是第三种?或者我误解了一些东西?
答案 0 :(得分:4)
我肯定会使用示例2.示例1或3都没有充分利用JavaScript的面向对象功能,因为:
this
,您将失去该类的身份,即您无法再执行a instanceof Circle
之类的检查。答案 1 :(得分:2)
有没有理由更喜欢第二种风格而不是第三种?
第三种风格仍在浪费小空间,以便存储名称area
和区域功能之间的关联。
另外,因为您从Object
字面值返回新的{...}
,instanceof Circle
将无效。
第二个比第一个好,因为我们没有为Circle的任何实例定义相同的功能区域。
确实,但有时可用于定义每个方法的新副本 - 一个副本,由于闭包,可以知道它绑定到哪个对象。使用传统的原型设计,您只能获得从调用者从中检索的对象设置的this
上下文,而不是绑定到特定对象。第一种方法避免了this
的问题 - 保留事件处理程序之类的东西,代价是效率降低。
答案 2 :(得分:1)
Circle.prototype.area
和Circle.area
之间的区别在于只能通过类的实例访问。
Circle.prototype.area = function(){};
Circle.area // wrong
(new Circle()).area // ok (you need a Circle object)
和
Circle.area = function(){};
Circle.area // ok (you don't need the object, its static)
(new Circle()).area // wrong
答案 3 :(得分:0)
示例2的问题是,当您在创建对象时意外忘记使用new
运算符,并且只需调用var a = Circle(10);
(这对第3个示例很好,但对于2),那么你的构造函数会造成很大的麻烦:
this.r = radius;
由于你没有使用new
,this
将被赋予全局对象,因此构造函数确实设置了全局变量r
!
所以我非常喜欢示例3。
答案 4 :(得分:0)
我想评论“第二个比第一个好,因为我们没有为Circle的任何实例定义相同的功能区域。”在实践中,这可能是一个可以忽略不计的优点,完全无关紧要。我倾向于支持语法和人性化代码而非效率,除非性能受到显着影响。我完全忽略了javascript的Prototype功能,也避免使用“this”,基本上使用了#1技术。它对我来说很好。我发现避免“这个”可以防止对“这个”所指的内容产生很多疑惑。完全可以创建没有“原型”的继承类型结构。您可以简单地创建一个超类对象,并覆盖您想要的任何方法。道格拉斯·克罗克福德(Douglas Crockford)已经在javascript中以无数种不同的方式编写了继承。
我同意上面的卡萨布兰卡,能够使用“instanceof”测试类型是返回“this”的一个很好的优势。也许我会在未来的项目中再看看“protype”和“this”。但就目前而言,如果没有他们,我相处得很好。