要创建自己的对象就从最简单的对象开始:实例化Object对象,并将它赋值给一个变量:
var myObject = new Object();
也可以使用简写的花括号形式:
var myObject = {};
无论通过哪种形式,最终的myObject变量都是Object对象的一个实例。首先,new关键字告诉JavaScript基于给定的对象创建一个全新的对象;然后新创建的实例被赋值给一个变量,以便通过引用这个变量来访问对象的新实例。
除非为新创建的对象添加自己的属性和方法,否则默认的Object对象本身用处不大。如果想让自己创建的对象能够被多次复制,那么就需要将其作为一个构造函数来创建,同时对访问其内部的属性和方法设置不同等级的权限。
当完成了对象实例化之后,不能再基于新实例使用new操作符创建另外的实例:
var anotherObject = new myObject();
因为myObject已经是一个实例了,所以在这个实例上使用new操作符创建另一个实例的操作是无效的。
构造函数
Function对象是创建构造函数的起点。使用Function关键字可以创建下面的myConstructor函数:
function myConstructor(a) { // 代码 }
另外一种定义函数的语法:
var myConstructor = function(a) { // 代码 }
Function对象的特殊之处在于,它的实例也能作为构造器方法,因而可以用来创建函数的新实例:
var myObject = new myConstructor();
此时,myConstructor函数类似于构造函数。当对象被实例化之后,构造器会立即执行它所包含的任何代码:
function myConstructor(message) { alert(message); this.myMessage = message; } var myObject = new myConstructor('Instantiating myObject!');
在这个例子中,传递的message参数同时也使用this关键字赋值给了myMessage属性。也就是说,通过将message参数赋值给this.myMessage,使实例拥有了一个可以随时访问的名为myMessage的属性。要从该实例中取得message的值,直接访问其myMessage属性即可:
var message = myObject.myMessage;
添加静态方法
下面的代码通过直接在myObject对象实例上使用点操作符,把name属性和alertName方法作为静态成员添加到了对象实例中。
// 创建一个Object对象的实例 var myObject = new Object(); //or var example = {}; // 添加一个属性 myObject.name = 'Jeff'; // 添加一个方法 myObject.alertName = function() { alert(this.name); } // 执行添加的方法 myObject.alertName();
这里的静态成员存在于对象的一个具体实例中而不是存在于构造函数中。虽然对这个实例而言,相应的代码是合法且可以运行的,但这也表示仅仅对Object的这个特定实例myObject能够正常运行。
共有方法
如果要在实例化新对象时包含共有方法,则需要修改构造函数的原型(prototype)。prototype属性是用来定义对象自身内部结构的一个特殊成员。如果把对象的原型想象为对象的蓝图,那么这个蓝图一旦被修改,则会立即改变基于它派生的对象和实例。
要在myConstructor的新实例中包括共有方法,只需向它的原型添加方法即可:
// 构造函数 function myConstructor(message) { alert(message); this.myMessage = message; } // 添加一个共有方法 myConstructor.prototype.clearMessage = function(string) { this.myMessage += ' ' + string; }
向prototype中添加成员将会把新方法添加到myConstructor的底层定义中,而不是添加到myConstructor实例自身:
var myObject = new myConstructor('Hello World!'); myObject.clearMessage();
私有成员
一个仅供自己内部使用的私有或特权方法,对于在库中防止别人以无法预测的方式使用内部方法特别有用。私有成员就是在一个函数中定义的变量和函数。如果要让myConstructor函数添加一个私有的alertMessage()方法和一个私有的separator属性,那么只需要在该构造函数中使用普通的var关键字和function关键字定义它们即可:
function myConstructor(message) { this.myMessage = message; // 私有属性 var separator = ' -'; var myOwner = this; // 私有方法 function alertMessage() { alert(myOwner.message); } // 在实例化时显示信息 alertMessage(); }
在这个例子中包含一个私有属性myOwner,它引用的是this。通过将this赋值给myOwner,私有方法就可以通过引用myOwner来访问myConstructor实例。私有方法是存在于构造函数作用域中的自包含的对象,它们实际上并不是prototype的方法,因此在私有方法内部this引用的实例只是私有方法的实例,而非myConstructor的实例。这个解释如下图所示:
特权方法
特权方法就是能够被公开访问,而且还能够访问私有成员的方法。特权方法是指在构造函数的作用域中使用this关键字定义的方法:
function myConstructor(message) { this.myMessage = message; var separator = ' -'; var myOwner = this; function alertMessage() { alert(myOwner.myMessage); } alertMessage(); // 特权方法 this.appendToMessage = function(string) { this.myMessage += separator + string; alertMessage(); } }
以这种方式创建特权方法后,myConstructor同样拥有了和前面使用prototype时相同的appendToMessage()方法,但此时的appendToMessage()方法位于构造函数的作用域中,因而具有通过作用域链访问私有的separator成员的权限。
共有、私有、特权和静态成员
□ 由于私有和特权成员在函数的内部,因此它们会被带到函数的每个实例中
□ 共有的原型成员是对象蓝图的一部分,适用于通过new关键字实例化的该对象的每个实例
□ 静态成员只适用于对象的一个特殊实例
下面是个相对完整的示例:
// 构造函数 function myConstructor(message) { this.myMessage = message; // 私有属性 var separator = ' -'; var myOwner = this; // 私有方法 function alertMessage() { alert(myOwner.myMessage); } alertMessage(); // 特权方法(也是共有方法) this.appendToMessage = function(string) { this.myMessage += separator + string; alertMessage(); } } // 共有方法 myConstructor.prototype.clearMessage = function(string) { this.myMessage = ''; } // 静态属性 myConstructor.name = 'Jeff'; // 静态方法 myConstructor.alertName = function() { alert(this.name); }
对象字面量
传统定义对象及其属性、方法的语法是点语法,例如:
var myObject = new Object(); myObject.propertyA = 'value'; myObject.propertyB = 'value'; myObject.methodA = function() { }; myObject.methodB = function() { }; myObject.methodC = function() { }; myObject.methodD = function() { };
而对象字面量作为两一种语法则更清晰也更便于阅读:
var myObject = { propertyA:'value', propertyB:'value', methodA:function() { }, methodB:function() { }, methodC:function() { }, methodD:function() { } }
记住:对象字面量会自动创建Object对象的实例,也就是说不能使用new关键字对其再次进行实例化。
如果要使用同样的对象字面量语法构建一个带有共有方法的构造函数,仍然需要从作为构造函数的Function对象开始:
function myConstructor() { // 私有和特权方法 }; // Public members myConstructor.prototype = { propertyA:'value', propertyB:'value', methodA:function() { }, methodB:function() { }, methodC:function() { }, methodD:function() { } }
使用点操作符和对象字面量的原理相同,区别就是表现形式。对象字面量语法不仅冗余代码少,而且也更容易阅读,推荐使用。
转载请注明:陈童的博客 » ADS2.2 JavaScript中的对象——创建对象