本文内容
- 背景
- 把我们的对象放在一起
- 添加一个私有(Private)的属性
- 添加一个特权(Privileged)的方法
- 添加一个公共(Public)的属性和方法
- 添加一个静态(Static)的属性
- 我们自己的完整对象
- 创建一个实例对象并检查可访问性
- 结论
其实,写 JavaScript 代码可以不用“面向对象”的方式,这不是必需的,但多年的工程实践表明,面向对象的确很好地解决问题了,代码变得更优雅(更通用,更容易扩展和维护),虽然 JavaScript 不支持面向对象,但可以模拟它。因此,开发人员们就想,既然面向对象还不错,那就尝试把之前在面向对象中取得经验和成就应用到 JavaScript 的代码上。促使开发人员这么想也这么干,也是出于现实考虑,不得已而为之,随着项目中的 JavaScript 代码越来越庞大,如每个页面有 10 万行代码很常见,而 gmail 有 44.3 万行,不设计、不规划一下是不行了。为了达到这个目的,你需要先知道 JavaScript 的东西很多,比如,作用域、作用域链、闭包、对象、实例对象、继承等等,并把 JavaScript 和面向对象编程对应起来,特别是对于像我,之前用其他语言从事面向对象开发的人来说。
如果你了解 JavaScript 的继承——如何和为什么,以及 JavaScript 的作用域和闭包,那么,我们就可以把这些知识结合在一起,讨论 JavaScript 对象的私有(private)、特权(privileged)、公共(public )和静态(static )成员(属性和方法)JavaScript中的对象。
背景
对于来自面向对象背景的开发人员来说,定义和使用这些成员对所有代码来说都是关键。但对使用 JavaScript 的人来说,也许不需要这样,可如果你知道如何将“面向对象”应用到 JavaScript 上,会使你的代码更通用。
把我们的对象放在一起
我们将把讨论的内容放在构造函数对象里,然后你通过 new 关键字创建一个新的实例对象。让我们先从一个空的对象开始:
// Constructor
function Kid(name) {
// Empty, for now
}
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
现在,你可以用如下方式创建很多 Kid 实例对象:
var kenny = new Kid("Kenny");
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
添加一个私有(Private)的属性
在我们学习 JavaScript 作用域和闭包中,函数内声明的一个变量只能在函数内可用(这是局部变量)。因此,如果我们想 kid 对象有一个私有(private)属性,我们可以这样做:
// Constructor
function Kid(name) {
// Private
var idol = "Paris Hilton";
}
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
idol 属性将只对 Kid 函数/对象内可用。注意:idol 属性前边的 var 关键字。
添加一个特权(Privileged)的方法
特权(privileged)方法是一种能够访问私有(private)属性的方法,而同时向外面公开它自己(在 JavaScript 中,也由于 JavaScript 作用域和闭包)。你可以删除或替换一个特权方法,但你不能改变它的内容。如特权方法返回一个私有属性的值:
// Constructor
function Kid(name) {
// Private
var idol = "Paris Hilton";
// Privileged
this.getIdol = function () {
return idol;
};
}
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
添加一个公共(Public)的属性和方法
现在,我们有了私有属性,和从外边访问它的特权方法,让我们来看看很基本的公共属性和公共方法:
// Constructor
function Kid(name) {
// Public
this.name = name;
this.getName = function () {
return this.name;
};
}
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
公共属性对任何调用都是可用的,像 getName 方法。
但是,正如在下面代码提到的,与其他类型相比,公共方法的推荐方式是使用原型(prototype)方法,修改上面代码后,例如:
// Constructor
function Kid(name) {
// Public
this.name = name;
}
Kid.prototype.getName = function () {
return this.name;
};
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
添加一个静态(Static)的属性
静态成员被所有的实例对象和它自己所共享(即 Kid 对象),静态成员只存储在一个地方。这意味着,它的值不会被继承到其下面的实例对象:
// Constructor
function Kid(name) {
// Constructor code
}
// Static property
Kid.town = "South Park";
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
我们自己的完整对象
在我们尝试访问对象的属性和方法前,看一下这个完整的对象:
// Constructor
function Kid(name) {
// Private
var idol = "Paris Hilton";
// Privileged
this.getIdol = function () {
return idol;
};
// Public
this.name = name;
}
// Public
Kid.prototype.getName = function () {
return this.name;
};
// Static property
Kid.town = "South Park";
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
创建一个实例对象并检查可访问性
现在是测试这些不同方法在实际中是如何工作的了。我们先创建一个 Kid 实例对象,然后,测试我们得到什么不同值。测试机器结果如下所示:
// Create a new instance
var cartman = new Kid("Cartman");
// Access private property
cartman.idol; // undefined
// Access privileged method
cartman.getIdol(); // "Paris Hilton"
// Access public property
cartman.name; // "Cartman"
// Access public method
cartman.getName(); // "Cartman"
// Access static property on an instance
cartman.town; // undefined
// Access static property on the constructor object
Kid.town; // "South Park"
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
结论
当涉及对象和其成员的时候,希望你用适当的方式去选择。另外,对于之前用其他语言从事面向对象编程的 JavaScript 新手,已经回答了你可能的问题。