javascript
基于对象的JavaScript编程
基于對象的JavaScript編程
-JavaScript Object-Oriented Programming
???????????????????? By-Ryan Frishberg
接觸ajax一直不是很深入,然后對于JavaScript的所謂基于對象的理解更是膚淺的很,g了很多中文的文章看著一頭霧水,找了一篇2001年老外的文章看了看,我*!講的既簡單又涉及到了精髓,忍不住花了兩天翻譯了一下,這是第一部分,第二部分抽時間也去翻一下,本人英文水平處于"倫敦郊區"水平,大家多噴。-.-
這個可能讓你很震驚,但是JavaScript是一種很強大的基于對象(object-based或者prototype-based,隨便你怎么稱呼)的編程語言。的確如此,JavaScript是一種強大的編程語言,并不是只能制造圖片滾動效果和平淡或華麗的展現效果。可是,很少使用者能認識到JavaScript潛在的強大的功能。如果你恰恰屬于這個行列,那這篇文章正好適合你。
首先,JavaScript跟java一樣不是一門純粹的OOP(Object-Oriented-Programming)語言,但是它是一門基于對象的編程語言。但是,你為什么要用JavaScript的對象呢?原因是這樣你不僅能熟悉JavaScript的工作原理,而且在編寫腳本時,你還可以自己創建JavaScript對象,而不總是像你現在這樣只編寫一些順序執行的代碼。這些編寫的JavaScript對象你也可以在以后重復利用。
?????? 我希望這篇文章能夠促成那些渴望學習面向對象技術的中級JavaScript工程師形成對JavaScript面向對象世界的持續興趣,從而成為專家。
???? 在這篇導讀里,你能學到:
???????? JavaScript的基本數據類型(JavaScript's primitive data types )
?????? 在JavaScript中什么是對象(What an object is in JavaScript )
?????? 怎樣創建一個普通的對象(How to create custom objects )
?????? 構造器是什么(What a constructor is )
?????? 對象的基本屬性是什么(What an object's prototype property is )
JavaScript的基本數據類型
JavaScript有五種基本數據類型:
?????????? Undefined,
?????????? Null,
?????????? Boolean,
?????????? Number,
?????????? String。
?????? 在這篇導讀中,我們會大量的用到后面三種類型
Boolean 類型是一種包含或者true或者false兩種值的邏輯實體。例如:
var BooleanValue = true;
Number類型是一種用來描述數的大小的一組數值。例如:
var NumericalValue = 354;
String 類型是一組包含零到多個字符的類型。例如:
var StringValue = "This is a String";
Typeof
typeof 是JavaScript中一個常用的操作符。它能告訴你正在操作的數據的類型。這有意義嗎?讓我們來看幾個例子:
var BooleanValue = true;
var NumericalValue = 354;
var StringValue = "This is a String";
alert(typeof BooleanValue) // 顯示 "boolean"
alert(typeof NumericalValue) // 顯示 "number"
alert(typeof StringValue) // 顯示 "string"
對象
對象是屬性的集合。這些屬性可以是基本數據類型,其他的對象或者是函數(這里先暫時稱為方法,后面會有別的名稱)。構造函數(簡單說是構造器)是一種用來創建一個對象的方法——這個我們會在后面詳細討論。JavaScript有許多內置的對象,如:Array, Image, 和Date對象。你們很多人都很熟悉怎樣使用Image對象來構建華麗的滾動效果。那么,當你使用這些代碼:
var Image1 = new Image(); ?
Image1.src = "myDog.gif";
事實上你已經創建了一個Image對象,并且給你自己的 Image對象設置了一個屬性值:src屬性。Image1是一個新的Image對象;換句話說,它是一個Image類型的實例。使用JavaScript中的‘.’符號,上面代碼就取得了你自己的image對象的src屬性并設置了它的值。現在,我們來學習怎么創建自己的對象:
function myFunc(){ ?
} ?
?
var myObject = new myFunc(); ?
alert(typeof myObject); ?// 顯示 "object"
我們剛剛創建了自己的對象。事實上我們已經構建了一個myFunc對象的實例,myFunc()是一個構造方法;構造方法指出了該對象在被創建時要進行的初始化工作,盡管我們這個構造方法里沒有什么初始化的工作(原文:it lays out the blueprint from which objects that are created from it will follow (although, in this case, it doesn't lay out much of a blueprint).)。這樣,JavaScript是怎樣知道要創建一個myFunc的對象,而不是返回這個方法的返回值的呢?讓我們來比較一下上面的例子和下面這個,一般方法更經常的用法:
function myFunc(){ ?
?return 5; ?
} ?
?
var myObject = myFunc(); ?
alert(typeof myObject); // 顯示 "number"
當前的這個例子里,我們把5賦值給了myObject,這樣,這兩段腳本的區別在哪呢?答案:new關鍵字。就是它告訴了JavaScript的編譯器遵循myFunc()構造方法中設置的初始化內容創建了一個對象。事實上,當我們創建了一個Image對象,我們也進行了相同的過程,只不過這里用了自己的構造方法而已,而在創建Image對象是用了JavaScript內置的Image()構造方法。
到目前為止,我們已經學習了怎樣建一個構造函數,怎樣用這個構造函數去構建一個對象實例。在我們的例子里,我們創建了一個myFunc()構造器,并且創建了一個myFunc對象的實例,并把它賦給了變量myObject。
???? 這些都很好很強大,但是什么才是關鍵呢?是的,就像我們給Image對象添加屬性那樣,myObject也可以被分配各種各樣的屬性:
function myFunc(){ ?
} ?
?
var myObject = new myFunc(); ?
myObject.StringValue = "This is a String"; ?
alert(myObject.StringValue); // 顯示 "This is a String"
瞧,現在我們已經給我們自己的對象添加了一個屬性。可是,當我們新建一個myFunc對象的實例時(用構造方法myFunc()),我們也必須要手動的將同樣的屬性賦值給新的實例,例如:
function myFunc(){ ?
} ?
?
var myObject = new myFunc(); ?
myObject.StringValue = "This is a String"; ?
var myObject2 = new myFunc(); ?
alert(myObject2.StringValue); // 顯示 "undefined"
那么,我們應該怎么操作才能給所有的myFunc對象實例添加屬性呢?在操作方法內部,我們就可以做到。this這個關鍵字在構造方法內部的時候指向當前正被創建的對象實例。例如:
function myFunc(){ ?
?this.StringValue = "This is a String"; ?
} ?
?
var myObject = new myFunc(); ?
var myObject2 = new myFunc(); ?
alert(myObject2.StringValue); // 顯示 "This is a String"
現在,所有的myFunc對象都會有一個初始值為“this is a String”的字符串型的屬性StringValue,同時每個對象實例的屬性StringValue都可以擁有自己獨特的值。也就是說,我們可以改變任何一個myFunc對象實例的stringValue屬性的值,而不影響其他的myFunc實例:
function myFunc(){ ?
?this.StringValue = "This is a String"; ?
} ?
?
var myObject = new myFunc(); ?
myObject.StringValue = "This is myObject's string"; ?
var myObject2 = new myFunc(); ?
alert(myObject.StringValue); // 顯示 "This is myObject's string" ?
alert(myObject2.StringValue); // 顯示 "This is a String"
???? 通過給構造方法添加參數的方法我們也可以達到相同的效果:
function myFunc(StringValue){ ?
?this.StringValue = StringValue; ?
} ?
?
var myObject = new myFunc("This is myObject's string"); ?
var myObject2 = new myFunc("This is a String"); ?
alert(myObject.StringValue); // 顯示 "This is myObject's string" ?
alert(myObject2.StringValue); // 顯示 "This is a String"
在myFunc()構造方法中,this.StringValue 指向當前創建的對象實例的StringValue屬性,而StringValue則指向做為參數傳過來的該方法的局部變量。這樣,我們就把屬性指向了對象實例,那方法有如何呢?(附:In the myFunc() constructor, this.StringValue refers to the property being assigned to the newly created object, while StringValue refers to the function's local variable that was passed as an argument. So, now that we've assigned properties to objects, what about methods?
原文里function和method翻譯起來費勁,還是看一下原文吧要是沒讀懂。-、-)
對象方法
???? 除了屬性以外,對象也可以包含方法,對象的方法是一個可以執行的函數。來看看這個例子。下面這個例子中,我們創建一個Circle對象。首先我們要定義幾個函數,然后將他們指定給我們的Circle對象。現在我們來定義Circle()構造函數,同時創建一到兩個它的具體實例:,
function Circle(radius){ ?
?this.radius = radius; ?
} ?
?
var bigCircle = new Circle(100); ?
var smallCircle = new Circle(2);
然后,我們再定義兩個可能用到的函數:
function getArea(){ ?
?return (this.radius*this.radius*3.14); ?
} ?
?
function getCircumference(){ ?
?var diameter = this.radius*2; ?
?var circumference = diameter*3.14; ?
?return circumference; ?
}
如果你要進行精確的計算的話,你可以用Math.PI來替代3.14,但這里我們就用pi的近似值來增強例子的可讀性。
???? 除了一個內容外這些函數都很簡單:this.radius指向什么內容?this這個關鍵字總是指向當前對象,在這個例子里就是這個Circle對象。所以this.radius就指向了這個Circle對象的radius屬性。那么,我們怎樣將這兩個函數添加到我們的對象中呢?事實上它沒有你想象的那么麻煩。我們先來改改我們的Circle()構造器:
function Circle(radius){ ?
?this.radius = radius; ?
?this.getArea = getArea; ?
?this.getCircumference = getCircumference; ?
}
上面的代碼將函數getArea和getCircumference添加到我們的Circle對象上,從而他們就成了我們的Circle對象中的方法。我們可以像使用其他函數一樣使用對象的方法,但是我們必須通過一個包含它的具體的對象實例來調用它:
alert(bigCircle.getArea()); // 顯示 31400 ?
alert(bigCircle.getCircumference()); // 顯示 618 ?
alert(smallCircle.getArea()); // 顯示 12.56 ?
alert(smallCircle.getCircumference()); // 顯示 12.56
保持整潔
如果我們想保持我們的屬性和方法在相同的地方-Circle構造方法內部。有很多方法可以做到。先來看一下內部函數。內部函數就是在一個函數內部的函數。這是我們要做的:
function Circle(radius){ ?
?function getArea(){ ?
? ?return (this.radius*this.radius*3.14); ?
?} ?
?function getCircumference(){ ?
? ?var diameter = this.radius*2; ?
? ?var circumference = diameter*3.14; ?
? ?return circumference; ?
?} ?
this.radius = radius; ?
this.getArea = getArea; ?
this.getCircumference = getCircumference; ?
}
除了方法的位置發生了變化其他都一樣。現在在我們的兩個函數內部,因為內部函數能取得包含它的外部函數的局部變量,我們用radius取代了this.radius。這樣,它就能取得做為參數傳遞給外部函數Circle()構造器的局部變量了,這樣我們就可以這樣簡單的使用了:
function Circle(radius){ ?
?function getArea(){ ?
? ?return (radius*radius*3.14); ?
?} ?
?function getCircumference(){ ?
? ?var diameter = radius*2; ?
? ?var circumference = diameter*3.14; ?
? ?return circumference; ?
?} ?
?this.radius = radius; ?
?this.getArea = getArea; ?
?this.getCircumference = getCircumference; ?
}
oK,現在讓我們來改變一下一個對象的radius的值,然后去的它的面積:
bigCircle.radius=50; ?
alert(bigCircle.getArea()); // 顯示 31400
瞧,先等等!返回值是31400,而不是期望的7850.哪里錯了呢?好吧,radius引用了我們賦給構造方法的值,而不是對象的屬性的值。這樣我們雖然改變了對象的radius的值,但是方法getArea()和getCircumference(),還在使用舊的radius值。因此,我們應該使用指向了當前對象的this.radius,不管屬性是在對象初始化的前后進行的改變。
???? OK,我們已經創建了一個完整的對象構造器(定義了一個對象的函數)。我們再來看看另一種在我們Circle()構造器內部建立方法的途徑:
function Circle(radius){ ?
?this.radius = radius; ?
?this.getArea = function(){ ?
? ?return (this.radius*this.radius*3.14); ?
?} ?
?this.getCircumference = function(){ ?
? ?var diameter = this.radius*2; ?
? ?var circumference = diameter*3.14; ?
? ?return circumference; ?
?} ?
} ?
?
var bigCircle = new Circle(100); ?
var smallCircle = new Circle(2); ?
?
alert(bigCircle.getArea()); // displays 31400 ?
alert(smallCircle.getCircumference()); // displays 12.56
在這里我們邂逅了另一種定義函數的方法,我們可以這樣做:
functionName = function([parameters]){ ?
?// function body ?
}
我們可以這樣來建參數:
functionName = function(parameter1,parameter2,parameter3){ ?
?//function body ?
}
盡管這種建立函數的方法不是很常用,但是在建立對象時,這卻是一個很好用的捷徑。這個過程同樣避免了同名方法的出現。例如,另一個對象可以擁有一個同名的不同方法,如:getArea() 而不會產生沖突。這種可能是因為這些函數被嵌套在了類構造器里。
對象種類
JavaScript總共有三種對象:原生對象,宿主對象,以及用戶自定義對象。
原生對象是JavaScript自己內建的對象,如String,Number,Array,Image,Date,Math,等等。
宿主對象是瀏覽器支持的對象,如:window,document,forms等等
用戶自定義對象就是程序員自己編寫的對象了。
在JavaScript中,除了基本數據類型任何一個包含屬性和方法的元素都是對象是它的基本思想。我們可以使用JavaScript的內建構造方法(就像我們已經創建的那樣)去創建對象。
var Image1 = new Image(50,100); ? ?
Image1.src = "myDog.gif";
在這里我們使用了JavaScript自有的Image()構造函數創建了一個具有如下屬性值的對象:
?????? width = 50
?????? height = 100
?????? src = "myDog.gif"
JavaScript中也包含了一個基本的Object()構造器,也可以用它來創建一個對象:
var myObj = new Object();
我們可以給一個基本對象添加屬性和方法,JavaScript中的所有對象都繼承自JavaScript的基本的Object對象。
回顧一下一個基本數據類型的String:
var myString = "This is my string"; ? ?
alert(myString); // 顯示 "This is my string" ? ?
alert(typeof myString); // 顯示 "string"
同時,我們也可以創建一個String類型的對象,通過這樣的構造方法:
var myString = new String("This is my string"); ? ?
alert(myString); // 顯示 "This is my string" ? ?
alert(typeof myString); // 顯示 "object"
???? 現在我們構建了一個String類型的對象。我們也可以同樣創建Number和Boolean類型的對象。但這樣做又有什么好處呢?是的,一旦我們這樣做了,就可以給這些對象添加獨特的屬性和方法。一個基本數據類型的實例包含了它的構造函數定義的屬性和方法,但是它卻不能擁有任何自己獨有的屬性和方法。例如,一個String基本類型就擁有length這個屬性以及substring方法以及其它的通過它的構造函數獲得的屬性和方法。但是,一個String對象可以含有String()構造函數設置的屬性和方法,也可以包含任何自己獨有的特性。我們來創建一個Number對象,并給他添加一個方法:
var myNumber = new Number(2); ? ?
myNumber.doubleIt = new Function("return this*2"); ? ?
alert(myNumber.doubleIt()); // 顯示: 4 ? ?
alert(typeof myNumber); // 顯示"object"
我們僅僅創建了一個新的Number的對象實例,為它定義了一個方法:doubleIt()。請注意myNumber是一個“類對象”。這是因為對象可以包含自己獨有的屬性和方法,但是基本數據類型,如String,Boolean,Number,undefined,還有null卻不能同樣擁有。這是他們之間的區別。
可以看到,在上面的例子中,我們實際上創建了另外一個對象---一個Function對象。然而,這個Function對象是與眾不同的。一般情況下,我們創建一個對象時,首先輸入new關鍵字,然后緊跟著對象的構造函數,這樣就可以返回一個普通的對象實例。接著我們就可以在生成的對象(通常用變量來保存)上添加屬性和方法。可是,因為Function對象同時也是一整塊可以調用的代碼,JavaScript將它設置的與眾不同,并且指出它不僅僅是一個對象(可以隨意添加屬性和方法),而且是一個可以調用的代碼塊。這樣,當我們輸入:
alert(typeof myNumber.doubleIt) // 顯示 "function"
就像你希望的那樣,顯示了“function”而不是“object”。Function()構造函數可以接受一些參數(arguments)。除了最后一個參數成為了這個函數的函數體,其他的參數都成了你的函數的參數(parameters):
var myFunc = new Function("parameter1","parameter2", ? ?
?"parameter3"," // function body");
現在我們可以傳入三個參數來調用這個函數:
myFunc("argument1","argument2","argument3");
函數對象
因為很多原因JavaScript的Function對象變得不同尋常。首先,它包含一整塊可調用的代碼。再者,一個函數對象還是一個完整的對象—它總是有能力包含獨特的屬性和方法。建立函數時就自動的建立了一個Function對象:
function myFuncObj(){} ? ?
myFuncObj.someVariable = "x"; ? ?
alert(myFuncObj.someVariable) // 顯示 "x" ?
即使沒有使用new關鍵字,Function()構造函數還是創建了一個對象,一個普通的能包含屬性和方法的對象。請注意Function()構造器是一個特殊的構造器—其他的構造器都必須使用new關鍵字來調用,或者有一個簡單數據類型的返回值而不是一個對象。
我們來看一下一個基本數據類型String,和一個String類的比較:
var pimitiveString1 = "This is a primitive string"; ? ?
var pimitiveString2 = String("This is a primitive string"); ? ?
var stringObject = new String("This is a String object"); ? ?
? ?
primitiveString1.prop = "This is a property"; ? ?
primitiveString2.prop = "This is a property"; ? ?
stringObject.prop = "This is a property"; ? ?
? ?
alert(primitiveString1.prop) // 顯示 "undefined" ? ?
alert(primitiveString2.prop) // 顯示 "undefined" ? ?
alert(stringObject.prop) // 顯示 "This is a property" ? ?
? ?
alert(typeof primitiveString1); // 顯示 "string" ? ?
alert(typeof primitiveString2); // 顯示 "string" ? ?
alert(typeof stringObject) // 顯示 "object"
你可以看到,不適用new關鍵字,我們無法創建一個對象并將它賦給一個變量,取而代之的是它將一個返回的基本數據類型(String基本類型)賦給了那個變量。你也可以看到primitiveString1 和 primitiveString2都不是對象,這樣我們就不能給他們添加屬性。當使用typeof關鍵字時primitiveString1/primitiveString2 和 stringObject 返回了不一樣的結果。其他的如Date, Image, Option, 還有其他的類也一樣。例如:
var x = Date(); ? ?
alert(typeof x); // 顯示 "string"
無論你怎么創建一個函數(很多方法)你會自動創建一個對象:
var myFuncObj = new Function(); ? ?
var myFuncObj = Function(); ? ?
var myFuncObj = function(){} ? ?
function myFuncObj(){}
這里我們用了不同的方法創建了Function對象,他們都能夠包含一塊可以調用的代碼,同時也可以包含自己的屬性和方法。
小結
繼續之前,讓我們來看幾個關鍵點:
?????????????????? JavaScript包含五種基本數據類型:Undefined, Null, Boolean, Number, 和 String.
?????????????????? 在JavaScript中除了基本數據類型,一切都是對象。
?????????????????? 對象是屬性的無序集合。屬性可以表現為基本數據類型,對象,函數對象(這里一般稱為方法)。
?????????????????? 總起來說JavaScript包含三種類別的對象,原生對象,宿主對象,以及用戶自定義對象(就像我們前面定義的Circle對象)。
?????????????????? 對象構造器/構造函數是一個用來創建一個新的對象類型的函數。在這個函數中我們定義了一個對象的基本屬性和方法,通常也給他們賦了初始值。
?????????????????? 可以使用new關鍵字調用構造器來創建一個對象的實例。我們既可以使用JavaScript內建的構造函數來創建一個原生對象,也可以使用自己定義的構造函數來創建一個自定義對象。
任何一個對象中都包含一個變量—this,它指向調用方法時候的那個實例對象,也就是當前對象,例如:
?????????????????????????????????????????? myObj.myFunc()
?????????????????????????????????????????? yourObj.myFunc()
第一個例子中,方法myFunc()中的this指向了myObj。而第二個例子中,myFunc()里的this是指向yourObj這個對象的。
?????????????????? ?
?
?
?原文地址:http://articles.sitepoint.com/article/oriented-programming-1/1
?
轉載于:https://www.cnblogs.com/wgjcn/archive/2009/10/28/1591149.html
總結
以上是生活随笔為你收集整理的基于对象的JavaScript编程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 防止SQL SERVER的事件探查器跟踪
- 下一篇: 汇总:一些不错的使用频率比较高的JS函数