JS创建类和对象
JavaScript 創(chuàng)建類/對象的幾種方式
在JS中,創(chuàng)建對象(Create Object)并不完全是我們時常說的創(chuàng)建類對象,JS中的對象強(qiáng)調(diào)的是一種復(fù)合類型,JS中創(chuàng)建對象及對對象的訪問是極其靈活的。
JS對象是一種復(fù)合類型,它允許你通過變量名存儲和訪問,換一種思路,對象是一個無序的屬性集合,集合中的每一項(xiàng)都由名稱和值組成(聽起來是不是很像我們常聽說的HASH表、字典、健/值對?),而其中的值類型可能是內(nèi)置類型(如number,string),也可能是對象。
一、由一對大括號括起來
varemptyObj={};
varmyObj=
{
'id':1,//屬性名用引號括起來,屬性間由逗號隔開
'name':'myName'
};
//varm=newmyObj();//不支持
不知你注意到對象都是用 var 聲明的沒有,像上面的代碼,就只是簡單的聲明一個對象,它只有一份拷貝,你不能像實(shí)例化類對象一樣對它采用new操作,像上面代碼的注釋部分。這樣就極大的限制了對象的重用,除非你建立的對象只需要一份拷貝,否則考慮用其他方法建立對象。
下面一起看看如何訪問對象的屬性和方法。
varmyObj=
{
'id':1,
'fun':function(){
document.writeln(this.id+'-'+this.name);//以"對象.屬性"方式訪問
},
'name':'myObj',
'fun1':function(){
document.writeln(this['id']+'+'+this['name']);//以集合方式訪問
}
};
myObj.fun();
myObj.fun1();
//結(jié)果
//1-myObj1+myObj
二、用 function 關(guān)鍵字模擬 class
在 function 中用 this 引用當(dāng)前對象,通過對屬性的賦值來聲明屬性。如果用var聲明變量,則該變量為局部變量,只允許在類定義中調(diào)用。
functionmyClass(){
this.id=5;
this.name='myclass';
this.getName=function(){
returnthis.name;
}
}
varmy=newmyClass();
alert(my.id);
alert(my.getName());
//結(jié)果
//5
//myclass
三、在函數(shù)體中創(chuàng)建一個對象,聲明其屬性再返回
在函數(shù)體中創(chuàng)建對象可利用第一點(diǎn)的方法,或先 new Object(); 再為各屬性賦值。
不過用這種方式創(chuàng)建的對象在VS2008 SP1中是沒有智能提示的。
functionmyClass(){
varobj=
{
'id':2,
'name':'myclass'
};
returnobj;
}
function_myClass(){
varobj=newObject();
obj.id=1;
obj.name='_myclass';
returnobj;
}
varmy=newmyClass();
var_my=new_myClass();
alert(my.id);
alert(my.name);
alert(_my.id);
alert(_my.name);
//結(jié)果
//2
//myclass
//1
//_myclass
一、定義類或?qū)ο?br />1.工廠方式
創(chuàng)建對象car
var oCar = new Object;
oCar.color = "red";
oCar.doors = 4;
oCar.mpg = 23;
oCar.showColor = function(){
alert(this.corlor);
};
創(chuàng)建多個car
function createCar(color, doors, mpg) {
var tempcar = new Object;
tempcar.color = color;
tempcar.doors = doors;
tempcar.mpg = mpg;
tempcar.showColor = function () {
alert(this.color)
};
return tempcar;
}
var car1 = createCar("red", 4, 23);
var car2 = createCar("blue", 3, 25);
car1.showColor(); //outputs "red"
car2.showColor(); //outputs "blue"
這個例子中,每次調(diào)用函數(shù)createCar(),都要創(chuàng)建新函數(shù)showColor(),意味著每個對象都有自己的showColor()版本,事實(shí)上,每個對象都共享了同一個函數(shù)。
有些開發(fā)者在工廠函數(shù)外定義對象的方法,然后通過屬性指向該方法,從而避開這個問題。
function showColor(){
alert(this.color);
}
function createCar(color, doors, mpg) {
var tempcar = new Object;
tempcar.color = color;
tempcar.doors = doors;
tempcar.mpg = mpg;
tempcar.showColor =showColor;
return tempcar;
}
var car1 = createCar("red", 4, 23);
var car2 = createCar("blue", 3, 25);
car1.showColor(); //outputs "red"
car2.showColor(); //outputs "blue"
從功能上講,這樣解決了重復(fù)創(chuàng)建函數(shù)對象的問題,但該函數(shù)看起來不像對象的方法。所有這些問題引發(fā)了開發(fā)者定義的構(gòu)造函數(shù)的出現(xiàn)。
2.構(gòu)造函數(shù)方法
function Car(sColor, iDoors, iMpg) {
this.color = sColor;
this.doors = iDoors;
this.mpg = iMpg;
this.showColor = function () {
alert(this.color)
};
}
var oCar1 = new Car("red", 4, 23);
var oCar2 = new Car("blue", 3, 25);
oCar1.showColor(); //outputs "red"
oCar2.showColor(); //outputs "blue"
就像工廠函數(shù),構(gòu)造函數(shù)會重復(fù)生成函數(shù),為每個對象都創(chuàng)建獨(dú)立的函數(shù)版本。不過,也可以用外部函數(shù)重寫構(gòu)造函數(shù),同樣,這么做語義上無任何意義。
3.原型方式
function Car(){
}
Car.prototype.color = "red";
Car.prototype.doors= 4;
Car.prototype.mpg= 23;
Car.prototype.showColor = function(){
alert(this.color);
}
var oCar1 = new Car();
var oCar2 = new Car();
它解決了前面兩種方式存在的兩個問題。但并不盡人意。首先,這個構(gòu)造函數(shù)沒有參數(shù)。使用原型方式時,不能通過構(gòu)造函數(shù)傳遞參數(shù)初始化屬性的值,這點(diǎn)很令人計厭,但還沒完,真正的問題出現(xiàn)在屬性指向的是對象,而不是函數(shù)時。考慮下面的例子:
function Car(){
}
Car.prototype.color = "red";
Car.prototype.doors= 4;
Car.prototype.mpg= 23;
Car.prototype.drivers = new Array("Mike","Sue");
Car.prototype.showColor = function(){
alert(this.color);
}
var oCar1 = new Car();
var oCar2 = new Car();
oCar1.drivers.push("Matt");
alert(oCar1.drivers);//outputs "Mike,Sue,Matt"
alert(oCar2.drivers);//outputs "Mike,Sue,Matt"
4.混合的構(gòu)造函數(shù)/原型方式
function Car(sColor, iDoors, iMpg) {
this.color = sColor;
this.doors = iDoors;
this.mpg = iMpg;
this.drivers = new Array("Mike", "Sue");
}
Car.prototype.showColor = function () {
alert(this.color);
};
var oCar1 = new Car("red", 4, 23);
var oCar2 = new Car("blue", 3, 25);
oCar1.drivers.push("Matt");
alert(oCar1.drivers); //outputs "Mike,Sue,Matt"
alert(oCar2.drivers); //outputs "Mike,Sue"
現(xiàn)在就更像創(chuàng)建一般對象了。所有的非函數(shù)屬性都有構(gòu)造函數(shù)中創(chuàng)建,意味著又可用構(gòu)造函數(shù)的參數(shù)賦予屬性默認(rèn)值了。因?yàn)橹粍?chuàng)建showColor()函數(shù)的一個實(shí)例,所以沒有內(nèi)存浪費(fèi)。
5.動態(tài)原型方法
function Car(sColor, iDoors, iMpg) {
this.color = sColor;
this.doors = iDoors;
this.mpg = iMpg;
this.drivers = new Array("Mike", "Sue");
if (typeof Car._initialized == "undefined") {
Car.prototype.showColor = function () {
alert(this.color);
};
Car._initialized = true;
}
}
var oCar1 = new Car("red", 4, 23);
var oCar2 = new Car("blue", 3, 25);
oCar1.drivers.push("Matt");
alert(oCar1.drivers); //outputs "Mike,Sue,Matt"
alert(oCar2.drivers); //outputs "Mike,Sue"
動態(tài)原型方法的基本想法與混合的構(gòu)造函數(shù)/原型方式相同,即在構(gòu)造函數(shù)內(nèi)定義非函數(shù)屬性,而函數(shù)屬性則利用原型屬性定義。唯一的區(qū)別是賦予對象方法的位置。
6.混合工廠方式
這種方式通常是在不能應(yīng)用前一種方式時的變通方法。它的目的是創(chuàng)建假構(gòu)造函數(shù),只返回另一種對象的新實(shí)例。
function Car() {
var tempcar = new Object;
tempcar.color = "red";
tempcar.doors = 4;
tempcar.mpg = 23;
tempcar.showColor = function () {
alert(this.color)
};
return tempcar;
}
與經(jīng)典方式不同,這種方式使用new運(yùn)算符,使它看起來像真正的構(gòu)造函數(shù)。
7.采用哪種方式
如前所述,目前使用最廣泛的是混合的構(gòu)造函數(shù)/原型方式。些外,動態(tài)原型方法也很流行,在功能上與前者等價,可以采用這兩種方式中的任何一種。
二、修改對象
1.創(chuàng)建新方法
可以用prototype屬性為任何已有的類定義新方法,就像處理自己的類一樣。
例:
Array.prototype.indexOf = function(vItem){
for(var i=0;i<this.length;i++){
if(vItem == this[i]){
return i;
}
}
retunr -1;
}
最后,如果想給ECMAScript中的每個本地對象添加新方法,必須在Object對象的prototype屬性上定義它。
2.重定義已有方法
就像能給自己的類定義新方法一樣,也可重定義已有的方法。函數(shù)名只是指向函數(shù)的指針,因此可以輕易地使它指向其他函數(shù)。
如
Function.prototype.toString = function(){
return "Function code hidden";
}
function sayHi(){
alert("hi");
}
alert(sayHi.toString());//outputs "Function code hidden"
Class - 類創(chuàng)建
Class類實(shí)現(xiàn)了在JavaScript中聲明一個新的類, 并通過構(gòu)造函數(shù)實(shí)例化這個類的機(jī)制。通過使用Class.create()方法, 你實(shí)際上聲明了一個新的類, 并定義了一個initialize()方法作為構(gòu)造函數(shù), 一旦你在這個聲明的類的prototype中實(shí)現(xiàn)了改該方法, 你就可以使用new操作符來創(chuàng)建并實(shí)例化一個類。
Knowledge Prepare - 知識準(zhǔn)備
在JavaScript中, 當(dāng)你定義了一個新的函數(shù), 你實(shí)際上聲明了一個新的類, 而這個函數(shù)本身就相當(dāng)于類的構(gòu)造函數(shù)。 下面的代碼向你展示了兩種不同的方式來創(chuàng)建一個新的Person類, 而Person.prototype的定義也緊跟在函數(shù)定義之后。
var Person = function(name) {// 一個匿名函數(shù), 并將這個函數(shù)賦值給一個Person變量, 此時Person成為一個類
this.name = name;
}
function Person(name) {// 直接定義一個叫做Person的函數(shù)表示Person類
this.name = name;
}
Person.prototype = {// 定義Person的prototype域
printName: function() { // 定義一個print函數(shù)
alert(this.name);
}
}
當(dāng)你通過函數(shù)的方式聲明了一個類之后, 你就可以通過new操作符來實(shí)例化這個類。這樣, 你就可以調(diào)用類的成員函數(shù)來完成你的邏輯。
var person = new Person("Joe Smith"); // 使用new操作符來新建一個Person的實(shí)例, 并賦給變量person
person.printName(); // person就可以看作是一個實(shí)例的引用(reference), 所以可以通過這個引用來調(diào)用Person類中的成員函數(shù)
我們來總結(jié)一下創(chuàng)建一個新的類的實(shí)例的整個流程和步驟:
1. 通過定義一個函數(shù)的方式(匿名或者實(shí)名)來聲明一個新的類.
2. 如果有必要, 定義這個新的類的prototype域.
3. 使用new操作符緊跟你所定義的函數(shù)來創(chuàng)建一個新的類的實(shí)例. 一旦JavaScript編譯器碰到了new操作符, 它實(shí)際上創(chuàng)建了一個空的類實(shí)例變量.
4. 將所有這個類的prototype域中的屬性與方法復(fù)制到這個新的實(shí)例中, 并將其成員函數(shù)中所有的this指針指向這個新創(chuàng)建的實(shí)例.
5. 接下來, 執(zhí)行緊跟在new操作符后面的那個函數(shù).
6. 當(dāng)你執(zhí)行這個函數(shù)時, 如果你試圖對一個不存在的屬性進(jìn)行賦值, JavaScript編譯器將自動為你在這個實(shí)例范圍內(nèi)新創(chuàng)建這個屬性.
7. 函數(shù)執(zhí)行完畢后, 將這個初始化完成的實(shí)例返回.
在Prototype中, 使用Class對象, 你可以以一個比較簡單的方式來聲明一個新的對象。通過使用Class.create(), prototype為你創(chuàng)建了一個默認(rèn)的構(gòu)造函數(shù)initialize(), 一旦你實(shí)現(xiàn)這一函數(shù), 就可以以一個類似Java中構(gòu)造函數(shù)的方式來創(chuàng)建一個新的類的實(shí)例。
Source View - 源碼解析
var Class = {// 全局靜態(tài)類, 用于聲明一個新的類并提供構(gòu)造函數(shù)支持
create: function() {
return function() { // 返回一個函數(shù), 代表著這個新聲明的類的構(gòu)造函數(shù)
// 一個命名為initialize的函數(shù)將被這個類實(shí)現(xiàn)作為類的構(gòu)造函數(shù)
this.initialize.apply(this, arguments);// initialize函數(shù)將在你實(shí)例化一個變量的時候被調(diào)用執(zhí)行(即上面7個步驟中的第5步)
}
}
}
Field & Function Reference - 屬性方法一覽
Class ( 靜態(tài) )
|
Method / Property |
Kind |
Arguments |
Description |
|
create() |
靜態(tài)方法 |
/ |
用于聲明一個新的類并提供了一個名為initialize構(gòu)造函數(shù)支持 |
Analysis & Usage - 分析與使用
通過Class類, 你可以很容易地使用構(gòu)造函數(shù)的方式創(chuàng)建一個新的類, 這對于Java程序員來說或許更加容易被接受。下面我們列出了Java和JavaScript各自聲明和創(chuàng)建一個新的類的代碼對比, 我們可以看到, 他們是如此相似:
var Person = Class.create(); // 類的聲明 |public class Person { // 類的聲明
Person.prototype = { | private String name;
initialize: function(name) {// 構(gòu)造函數(shù) | public Person(String name){ // 構(gòu)造函數(shù)
this.name = name; | this.name = name;
} | }
printName: function() {// 成員函數(shù) | public void printName(){// 成員函數(shù)
alert(this.name); | System.out.println(name);
} | }
} |}
var person = new Person("Joe Smith");// 創(chuàng)建實(shí)例 |Person person = new Person("Joe Smith");// 創(chuàng)建實(shí)例
person.printName(); // 函數(shù)調(diào)用 |person.printName(); // 函數(shù)調(diào)用
總結(jié)
- 上一篇: 国内漫画家有多难国内漫画家有多难找
- 下一篇: 买个风扇挑花了眼买这个风扇