面向对象的问题在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
在你的第三个函数中,你甚至不需要get
和set
函数 – name
和age
是公共属性( {}
的潜在缺点)。
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/