我更喜欢在大型项目中使用OOP,就像我现在正在研究的那样.我需要在JavaScript中创建几个类,但是,如果我没有弄错的话,至少有几种方法可以做到这一点.什么是语法,为什么会以这种方式完成?
我想避免使用第三方库 - 至少在开始时.
寻找其他答案,我找到了文章面向对象的JavaScript编程,第一部分:继承 - Doc JavaScript,讨论了JavaScript中的面向对象编程.是否有更好的继承方式?
在另一个问题中,用户指出该new关键字使用起来很危险,并提出了一种不使用的对象创建解决方案new.我不相信这是真的,主要是因为我使用了Prototype,Scriptaculous和其他优秀的JavaScript库,并且每个人都使用了new关键字.
尽管如此,昨天我在YUI剧院观看道格拉斯·克罗克福德的演讲,他说的完全一样,他new在代码中不再使用关键字(Crockford on JavaScript - Act III:Function the Ultimate - 50:23分钟).
使用new关键字"不好" 吗?使用它有哪些优缺点?
在JavaScript中,我想创建一个对象实例(通过new运算符),但是将任意数量的参数传递给构造函数.这可能吗?
我想做的是这样的事情(但下面的代码不起作用):
function Something(){
// init stuff
}
function createSomething(){
return new Something.apply(null, arguments);
}
var s = createSomething(a,b,c); // 's' is an instance of Something
Run Code Online (Sandbox Code Playgroud)
答案
从这里的回复中可以清楚地看出,没有内置的方式.apply()与new运营商通话.然而,人们提出了一些非常有趣的解决方案.
我首选的解决方案是Matthew Crumley的这个解决方案(我已将其修改为通过该arguments属性):
var createSomething = (function() {
function F(args) {
return Something.apply(this, args);
}
F.prototype = Something.prototype;
return function() {
return new F(arguments);
}
})();
Run Code Online (Sandbox Code Playgroud) 所以这些年来我终于停止了我的脚,并决定"正确"学习JavaScript.语言设计中最令人头疼的元素之一是它的继承实现.有Ruby经验,我很高兴看到闭包和动态打字; 但是对于我的生活来说,无法弄清楚使用其他实例进行继承的对象实例会带来什么好处.
javascript oop inheritance language-design prototype-programming
所以我有这两个例子,来自javascript.info:
例1:
var animal = {
eat: function() {
alert( "I'm full" )
this.full = true
}
}
var rabbit = {
jump: function() { /* something */ }
}
rabbit.__proto__ = animal
rabbit.eat()
Run Code Online (Sandbox Code Playgroud)
例2:
function Hamster() { }
Hamster.prototype = {
food: [],
found: function(something) {
this.food.push(something)
}
}
// Create two speedy and lazy hamsters, then feed the first one
speedy = new Hamster()
lazy = new Hamster()
speedy.found("apple")
speedy.found("orange")
alert(speedy.food.length) // 2
alert(lazy.food.length) // 2 (!??)
Run Code Online (Sandbox Code Playgroud)
从示例2开始:当代码到达时 …
基于javascript原型的面向对象编程风格很有趣,但是在很多情况下你需要能够从类创建对象.
例如,在矢量绘图应用程序中,工作空间通常在绘图开始时为空:我无法从现有工作空间创建新的"行".更一般地说,动态创建对象的每种情况都需要使用类.
我已经阅读了很多教程和书"Javascript:好的部分",但在我看来,没有办法定义尊重1)封装的类和2)有效的成员方法声明(我的意思是:成员)正在定义的方法,并在每个类实例之间共享).
要定义私有变量,正在使用闭包:
function ClassA()
{
var value = 1;
this.getValue = function()
{
return value;
}
}
Run Code Online (Sandbox Code Playgroud)
这里的问题是"ClassA"的每个实例都有自己的成员函数"getValue"的副本,这是无效的.
要有效地定义成员函数,正在使用原型:
function ClassB()
{
this.value = 1;
}
ClassB.prototype.getValue = function()
{
return this.value;
}
Run Code Online (Sandbox Code Playgroud)
这里的问题是成员变量"value"是公共的.
我不认为这个问题可以轻易解决,因为在创建对象期间需要定义"私有"变量(以便对象可以访问其创建的上下文,而不暴露those值)而基于原型的成员函数定义必须在对象创建后完成,因此原型有意义("this.prototype"不存在,我已经检查过).
或者我错过了什么?
编辑:
首先,感谢您的有趣答案.
我只想为我的初始消息添加一点精度:
我真正想做的是拥有1)私有变量(封装是好的,因为人们只能访问他们需要的东西)和2)有效的成员方法声明(避免拷贝).
似乎简单的私有变量声明只能通过javascript中的闭包来实现,这就是为什么我专注于基于类的方法.如果有一种方法可以用基于原型的方法实现简单的私有变量声明,那对我来说没问题,我不是一个激烈的基于类的方法proponnent.
在阅读答案后,似乎简单的解决方案是忘记私有,并使用特殊的编码约定来阻止其他程序员直接访问"私有"变量...
我同意,我的标题/第一句话对于我想在这里讨论的问题有误导性.
通过以下问题阅读,我觉得大多数答案都忽略了为什么有些人(Crockford)选择不使用"新"关键字.这不是为了防止在没有"new"关键字的情况下意外调用函数.
根据Crockford关于原型继承的以下文章,他实现了一种对象创建技术,该技术更清楚地展示了JS的原型性质.现在甚至在JS 1.8.5中实现了这种技术.
他反对使用新的论点可以更清楚地概括为:
"这种间接性旨在使语言对经过专业训练的程序员来说更加熟悉,但却没有做到这一点,正如我们从Java程序员对JavaScript的非常低级的看法中看到的那样.JavaScript的构造函数模式并不适合经典人群.也模糊了JavaScript真正的原型性质.因此,很少有程序员知道如何有效地使用这种语言."
我并不一定认为"新"有害,但我确实认为它"掩盖了JavaScript真正的原型性质",因此我在这一点上必须同意Crockford.
您对使用"更清晰"的原型对象创建技术,而不是使用"new"关键字有什么看法?