面向对象的问题在Javascript中

我已经使用JavaScript了一段时间,但从来没有学过语言的基础。 我正在阅读John Resig的“专业Javascript技术” – 我提出了一些问题,但是我没有在书中或google上find答案。

约翰在他的书中给出了这个例子:
function#1

function User( name, age ){ this.name = name; this.age = age; } // Add a new function to the object prototype User.prototype.getName = function(){ return this.name; }; User.prototype.getAge = function(){ return this.age; }; var user = new User( "Bob", 44 ); console.log("User: " + user.getName() + ", Age: " + user.getAge()); 

我仍然在学习原型属性,所以我试着写类似的东西:
function#2

 function User (name, age ) { this.name = name; this.age = age; this.getName = function() { return this.name; }; this.getAge = function() { return this.age; }; } var user = new User( "Bob", 44 ); console.log("User: " + user.getName() + ", Age: " + user.getAge()); 

它不使用prototype属性来创buildgetName和getAge函数,但输出与John的示例相同。

我更进了一步,创造了这个:
function#3

 var User = { name: "", age: 0, setName: function(name) { this.name = name; }, setAge: function(age) { this.age = age; }, getName: function() { return this.name; }, getAge: function() { return this.age; } }; User.setName("Bob"); User.setAge(44); console.log("User: " + User.getName() + ", Age: " + User.getAge()); 

再次 – 它看起来不像约翰的例子(我不得不添加setter方法),但输出是相同的。

问题1 – 3个function有什么区别? 原型属性的优点是什么,函数#2做了什么不正确的事情,因为它看起来更直接的代码#2而不是#1(虽然我确信#1做得更好,看到约翰创build它) 。

问题#2 – 我怎样才能修改函数#3不使用setName和setAge方法,但仍然保持{…}速记? {…}速记可以有构造函数吗?

预先感谢帮助我学习!

编辑我觉得我的第二个问题有点混乱。 我的意思是我怎么可以用{…}简写来创build一个User对象,但是在我创build这个对象之后,可以这样说:

 var user = new User("Bob", 44); 

就像在function#1中 – 或者是不可能的?

编辑#2哇! 谢谢大家的真棒答案。 这真的让我更加清楚。 所以如果我理解正确的话,#1和#2之间的差别不是太大。 如果我只创build一个“用户”对象 – 他们可能根本就没有什么不同。 但是,如果我的程序创build了许多用户对象,那么#1很可能会更有效率,并使用更less的内存,因为所有的对象将共享相同的function。

我真的很感谢所有的好的答案 – 谢谢!

每次函数(){}被计算时,它都会创build一个新的函数对象。 因此,#1中的所有用户对象共享相同的getName和getAge函数,但在#2和#3中,每个对象都有自己的getName和getAge副本。 所有不同的getName函数都performance得完全一样,所以在输出中看不到任何不同。

{…}简写一个构造函数。 在评估时,它会用给定的属性构造一个新的“对象”。 当你运行“新用户(…)”,它构造一个新的“用户”。 您碰巧创build了一个与用户具有相同行为的对象,但是它们的types是不同的。

回应评论:

你不能,直接。 你可以创build一个按照#3创build一个新对象的函数。 例如:

 function make_user(name, age) { return { name: name, age: age, getName: function() { return name; }, getAge: function() { return age; }, }; } var user = make_user("Joe", "18"); 

如果你想在JavaScript中做OOP,我强烈build议查找闭包。 我开始用这三个网页学习这个主题:

http://www.dustindiaz.com/javascript-private-public-privileged/

http://www.dustindiaz.com/namespace-your-javascript/

http://blog.morrisjohns.com/javascript_closures_for_dummies

1,2和3之间的差异如下:1)是向现有对象添加新方法的示例。 2)与#1相同,除了用户function中的对象中包含某些方法。 3)是使用JSON定义对象的一个​​例子。 缺点是你不能使用新的(至less不是这个例子)来定义该对象的新实例。 但是,您将获得方便的JSON编码风格的好处。

如果你还不知道,你一定要阅读JSON。 当你理解JSON时,JavaScript将会变得更有意义。

编辑如果你想在function#3中使用新的,你可以写为

 function User() { return { name: "", age: 0, setName: function(name) { this.name = name; }, setAge: function(age) { this.age = age; }, getName: function() { return this.name; }, getAge: function() { return this.age; } }; } 

当然所有这些function和属性都将被公开。 为了使他们私密,你需要使用闭包。 例如,您可以使用此语法使年龄和名称保密。

 function User() { var age=0; var name=""; return { setName: function(name_) { name = name_; }, setAge: function(age_) { age = age_; }, getName: function() { return name; }, getAge: function() { return age; } }; } 

2:

您可以访问名称和年龄,而不使用这些function。 在JavaScript中,你必须使用不同的黑客来保持私人或保护的东西。

这个

 User.name = "BoB"; User.age = 44; 

将会产生与你的例子相同的输出。

没有构造函数,因为它们以其他语言显示。 最简单的方法就是定义init()函数并在实例化对象后立即调用它。

但我最大的提示是看看http://www.prototypejs.org/ 。 这是一个JavaScript库,有很多很酷的function,试图让JavaScript“更多OO *”。

使用原型库可以使类更像真正的OOP类。 它还具有构造函数。

编辑:至于你在你的评论中问:

 person = new User(); person.name = "Bob"; person.age = 44; 

你的例子#1显示了prototype属性的用法。 该属性可用于您创build的所有JavaScript对象,并允许您将属性或函数添加到对象声明中,因此您有一个具有2个属性的对象,稍后添加了4个函数(getter和setter)。

您应该看到原型属性作为在运行时修改对象规范的方式,假设您有一个名为name的对象:

 var Name = { First: "", Last: "" }; 

您可以使用原型稍后添加一个函数getFullName(),方法如下:

 Name.prototype.getFullName = function() { return this.First + " " + this.Last; } 

在示例2中,您将对象声明中的这些getter和setter声明内联,因此最终它们是相同的。 最后在第三个示例中使用JavaScript对象表示法,您应该看到JSON 。

关于你的问题2你可以声明你的对象为:

 var User = { name: "", age: 0 }; 

这会给你没有getters和setter的同一个对象。

问题#1

prototype有猴子补丁的好处。 如第一个例子所示,该function是事后添加的。 您可以继续添加或replace您需要的任何方法(尽pipe公正的警告)。

定义像#2这样的对象更像是经典的OOP。 但是,所有的OOP语言都不允许使用猴子补丁。

问题2

在你的第三个函数中,你甚至不需要getset函数 – nameage是公共属性( {}的潜在缺点)。

 var User = { name: "", age: 0 }; User.name = 'Bob'; User.age = 44; console.log("User: " + User.name + ", Age: " + User.age); 

当使用{} (对象文字)创build对象时, {}是构造函数(在浏览器上变化)。 但是,基本上,不,你不能使用这种格式的构造函数。

你似乎在这里有一些很好的答案,但你可能想看看这个问题: 最好的方法,以成员variables在面向对象的JavaScript 。 这是我的答案 ,描述了差异和相似之处。

如果你对JSON风格的JavaScript类声明的谈话感兴趣…

http://mahtonu.wordpress.com/2010/04/13/json-style-javascript-object-declaration/