2009-01-14 144 views
39

我一直在使用javascript一段时间,但从来没有学过基本的语言。我正在阅读John Resig的“专业Javascript技术” - 我提出了一些问题,但我没有在书或谷歌等网站上找到答案。Javascript中的面向对象问题

John在他的书中给出了这个例子:
功能#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()); 

我还在学习有关原型财产,所以我试着写类似的东西:
功能#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()); 

它不使用原型属性创建的getName和getAge功能,但输出是一样的约翰的例子。

我把它一步,并创造了这个:
功能#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个功能之间有什么区别?原型属性的优点是什么,函数#2做了什么不正确的事情,因为它似乎更直接地代码#2而不是#1(尽管我确信#1正在做的更好,看到约翰创建它) 。

问题#2 - 如何修改函数#3以不使用setName和setAge方法,但仍保留{...}简写形式? {...}速记可以有构造函数吗?

在此先感谢帮助我学习!

编辑 我觉得我的第二个问题有点混乱。我的意思是,我怎么能使用{...}速记创建一个User对象,但后来经过我创建的对象,这样说:

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

就像在功能#1 - 或者是不可能的?

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

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

回答

22

每次函数(){}被评估时,它都会创建一个新的函数对象。因此,#1中的所有User对象都共享相同的getName和getAge函数,但在#2和#3中,每个对象都有自己的getName和getAge副本。所有不同的getName函数都表现得完全一样,所以你不能在输出中看到任何差异。

{...}速记的构造函数。评估时,它会用给定的属性构造一个新的“对象”。当你运行“新用户(...)”时,它会构建一个新的“用户”。您碰巧创建了与用户具有相同行为的对象,但它们的类型不同。

回应评论:

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

function make_user(name, age) { 
    return { 
     name: name, 
     age: age, 
     getName: function() { return name; }, 
     getAge: function() { return age; }, 
    }; 
} 

var user = make_user("Joe", "18"); 
+0

我想我的意思是问题#2是如何修改函数#3,这样我可以这样说变种人=新用户(); – BrianH 2009-01-14 18:53:44

+0

该评论并不完全正确“所有不同的getName函数都表现完全一样”。类型#2有权访问私人股票交易所 – meouw 2009-01-14 20:12:32

+0

我的观点是他们的行为在这个例子中是一样的。 – Glomek 2009-01-14 20:18:01

5

2:

您可以访问名字和年龄,不使用这样的功能。在JavaScript中,您必须使用不同的黑客手段来保护私密或受保护的内容。

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

会产生相同的输出的例子。

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

但我最大的提示是查看http://www.prototypejs.org/。这是一个JavaScript库,其中有很多很酷的功能,它们试图让javascript“更多OO *”。

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

编辑: 至于您在您的评论问:

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

问题#1

prototypemonkey patching利益。如第一个例子所示,该功能是事后添加的。您可以继续添加或替换您需要的任何方法(尽管公平的警告)。

定义像#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); 

当您使用{}(对象文本)的对象,{}是构造(不同的浏览器)。但是,基本上,不,你不能以这种格式使用构造函数。

4

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

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

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

您可以使用原型添加功能getFullName()以后通过简单地:

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

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

关于你的第二个问题你可以声明你的对象为:

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

这会给你同样的对象,而getter和setter方法。

12

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

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相同。 3)是使用JSON定义对象的示例。缺点是你不能使用新的(至少不是这个例子)来定义新对象的实例。但是,您确实可以从便捷的JSON编码风格中获益。

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

编辑 如果你想使用的功能#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 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; 
    } 
    }; 
}