在大多數面嚮對象語言中,對象老是由類中實例化而來,類和對象的關係就像模具跟模件同樣。Javascript中沒有類的概念,就算ES6中引入的class也不過是一種語法糖,本質上仍是利用原型實現。在原型編程語言中,類並非必需的,對象不必定須要由類實例化而來,而是經過克隆另一個對象來獲得。java
原型模式是用來建立對象的一種模式。在以類爲中心的語言中,要建立一個對象首先要指定這個對象的類型,而後實例化一個對象。使用原型模式建立對象時沒必要關心對象的具體類型,而是找到一個對象,而後經過克隆來建立一個如出一轍的對象。因此在前者中若是要根據一個對象建立多個相同的對象,咱們須要先保存這個對象的全部屬性信息,而後將屬性信息設置到新建立的對象上,而在原型模式中咱們只須要使用克隆就能完成一樣的功能。編程
在某些玄幻小說中常常會出現某些修真大能,以分身的形式遊走世間。這個過程很適合原型模式的應用:瀏覽器
function Master(){app
this.blood = 100;編程語言
this.level = 6;ide
}函數
var noumenon = new Master();工具
noumenon.level = 9;學習
var ektype = Object.create(noumenon);this
console.log(ektype);
ES5提供了原生的克隆方法:Object.create,不支持這個方法的瀏覽器可使用以下代碼:
function clone(obj)
function F(){};
F.prototype = obj;
return new F();
}
var ektype = clone(noumenon);
經過以上代碼,咱們看到了如何經過原型模式來克隆出一個如出一轍的的對象。原型模式的真正意義並不是建立一個如出一轍的對象,而是提供一種建立對象的方式,Javascript的面向對象機制是基於原型模式的,他的對象系統就是使用原型模式,經過克隆來建立的,克隆是建立一個對象的過程和手段。以繼承爲例:
function Person(name){
this.name = name;
}
function Developer(lang){
this.language = lang;
}
var p = new Person('coder');
Developer.prototype = p;
var dev = new Developer('Javascript');
基於原型的繼承體系,子類的每次實例化都是對其構造函數的prototype屬性的克隆。因此每次建立Developer對象,其實都是在對p對象的克隆。
在Java等以類爲中心的面嚮對象語言中,常用new實例化一個對象。可是Javascript是基於原型的面嚮對象語言,在這裏new運算符建立對象的方式與Java中的new運算符並不相同,Javascript中的new運算符也是經過克隆來實例化對象的,克隆的是構造器函數的原型對象,new運算符的做用等同於以下代碼:
function Person(name){
this.name = name;
}
function Developer(lang){
this.language = lang;
}
var p = new Person('coder');
Developer.prototype = p;
function _new(_Constructor) {
var that = Object.create(_Constructor.prototype);
var args = Array.prototype.slice.call(arguments, 1);
var other = _Constructor.apply(that, args);
return (typeof other === 'object' && other) ? other : that;
}
_new(Developer, 'JavaScript')
從這咱們也能夠看出,Javascript的原型實際上存在着諸多矛盾,它的某些複雜語法看起來就像那些基於類的語言,這掩蓋了它的原型機制。因此jQuery中儘可能避免使用new運算符來建立對象。
根據前面所說Javascript中新建立的對象都是基於原有對象的克隆,因此在Javascript中存在一個最原始的對象:Object.prototype,全部對象都是由它克隆而來。
這裏所說的克隆是在Javascript原型模式這一大環境下的一種語義表達,在計算機的物理世界中並不存在真正的克隆。因此這裏對於克隆應當理解爲產生一個擁有__proto__屬性指向原對象的對象的過程,原對象成爲被克隆的對象,也就是構造函數的prototype對象。
擁有以上共識後,咱們能夠獲得在Javascript中原型編程的基本規則:
Javascript中絕大多數數據都是對象
要獲得一個對象,不是經過實例化類,而是找到一個對象做爲原型並克隆它
對象會記住它的原型
若是對象沒法響應某個請求,他會把這個請求委託給它本身的原型
早先程序使用最簡單的輸入輸出方式,用戶在鍵盤輸入數據,程序將信息輸出在屏幕上。現代程序要求使用圖形用戶界面(Graphical User Interface,GUI),界面中有菜單、按鈕等,用戶經過鼠標選擇菜單中的選項和點擊按鈕,命令程序功能模塊。本章學習如何用Java語言編寫GUI科學試驗,如何經過GUI實現輸入和輸出。
AWT和Swing
先前用Java編寫GUI程序,是使用抽象窗口工具包AWT(Abstract Window Toolkit).如今多用Swing。Swing能夠看做是AWT的改良版,而不是代替AWT,是對AWT的提升和擴展。因此,在寫GUI程序時,Swing和AWT都要做用。它們共存於Java基礎類(Java Foundation Class,JFC)中。
儘管AWT和Swing都提供了構造圖形界面元素的類,但它們的重要方面有所不一樣:AWT依賴於主平臺繪製用戶界面組件;而Swing有本身的機制,在主平臺提供的窗口中繪製和管理界面組件。Swing與AWT之間的最明顯的區別是界面組件的外觀,AWT在不一樣平臺上運行相同的程序,界面的外觀和風格可能會有一些差別。然而,一個基於Swing的應用程序可能在任何平臺上都會有相同的外觀和風格。
Swing中的類是從AWT繼承的,有些Swing類直接擴展AWT中對應的類。例如,JApplet、JDialog、JFrame和JWindow。
使用Swing設計圖形界面,主要引入兩個包:
javax.swing包:包含Swing的基本類;
java.awt.event包:包含與處理事件相關的接口和類。
因爲Swing太豐富,不可能在一本教科書中給出Swing的全面介紹,但本章所介紹的有關Swing的知識,已足以讓讀者編寫至關精美的GUI程序。
組件和容器
組件(component)是圖形界面的基本元素,用戶能夠直接操做,例如按鈕。容器(Container)是圖形界面的的複合元素,容器能夠包含組件,例如面板。
Java語言爲每種組件都預約義類,程序經過它們或它們的子類各類組件對象,如,Swing中預約義的按鈕類JButton是一種類,程序建立的JButton對象,或JButton子類的對象就是按鈕。Java語言也爲每種容器預約義類,程序經過它們或它們的子類建立各類容器對象。例如,Swing中預約義的窗口類JFrame是一種容器類,程序建立的JFrame或JFrame子類的對象就是窗口。
爲了統一管理組件和容器,爲全部組件類定義超類,把組件的共有操做都定義在Component類中。一樣,爲全部容器類定義超類Container類,把容器的共有操做都定義在Container類中。例如,Container類中定義了add()方法,大多數容器均可以用add()方法向容器添加組件。
Component、Container和Graphics類是AWT庫中的關鍵類。爲能層次地構造複雜的圖形界面,容器被看成特殊的組件,能夠把容器放入另外一個容器中。例如,把若干按鈕和文本框分放在兩個面板中,再把這兩個面板和另外一些按鈕放入窗口中。這種層次地構造界面的方法,能以增量的方式構造複雜的用戶界面。
事件驅動程序設計基礎
1.事件、監視器和監視器註冊
圖形界面上的事件是指在某個組件上發生用戶操做。例如,用戶單擊了界面上的某個按鈕,就說在這個按鈕上發生了事件,這個按鈕對象就是事件的擊發者。對事件做監視的對象稱爲監視器,監視器提供響應事件的處理方法。爲了讓監視器與事件對象關聯起來,須要對事件對象做監視器註冊,告訴系統事件對象的監視器。
以程序響應按鈕事件爲例,程序要建立按鈕對象,把它添加到界面中,要爲按鈕做監視器註冊,程序要有響應按鈕事件的方法。當「單擊按鈕」事件發生時,系統就調用已爲這個按鈕註冊的事件處理方法,完成處理按鈕事件的工做。
2.實現事件處理的途徵
java語言編寫事件處理程序主要有兩種方案:一個是程序重設handleEvent(Eventevt),採用這個方案的程序工做量稍大一些;另外一個方案是程序實現一些系統設定的接口。java按事件類型提供多種接口,做爲監視器對象的類須要實現相應的接口,即實現響應事件的方法。當事件發生時,系統內設的handleEvent(Event evt)方法就自動調用監視器的類實現的響應事件的方法。
java.awt.event包中用來檢測並對事件作出反應的模型包括如下三個組成元素:
源對象:事件「發生」這個組件上,它與一組「偵聽」該事件的對象保持着聯繫。
監視器對象:一個實現預約義的接口的類的一個對象,該對象的類要提供對發生的事件做處理的方法。
事件對象:它包含描述當事件發生時從源傳遞給監視器的特定事件的信息。
一個事件驅動程序要作的工做除建立源對象和監視器對象以外,還必須安排監視器瞭解源對象,或向源對象註冊監視器。每一個源對象有一個已註冊的監視器列表,提供一個方法能向該列表添加監視器對象。只有在源對象註冊了監視器以後,系統纔會將源對象上發生的事件通知監視器對象。
3.事件類型和監視器接口
在java語言中,爲了便於系統管理事件,也爲了便於程序做監視器註冊,系統將事件分類,稱爲事件類型。系統爲每一個事件類型提供一個接口。要做爲監視器對象的類必須實現相應的接口,提供接口規定的響應事件的方法。
再以程序響應按鈕事件爲例,JButton類對象button能夠是一個事件的激發者。當用戶點擊界面中與button對應的按鈕時,button對象就會產生一個ActionEvent類型的事件。若是監視器對象是obj,對象obj的類是Obj,則類Obj必須實現AWT中的ActionListener接口,實現監視按鈕事件的actionPerformed方法。button對象必須用addActionListener方法註冊它的監視器obj。
程序運行時,當用戶點擊button對象對應的按鈕時,系統就將一個ActionEvent對象從事件激發對象傳遞到監視器。ActionEvent對象包含的信息包括事件發生在哪個按鈕,以及有關該事件的其餘信息。
表 11-1 給出有必定表明性的事件類型和產生這些事件的部分Swing組件。實際事件發生時,一般會產生一系列的事件,例如,用戶點擊按鈕,會產生ChangeEvent事件提示光標到了按鈕上,接着又是一個ChangeEvent事件表示鼠標被按下,而後是ActionEvent事件表示鼠標已鬆開,但光標依舊在按鈕上,最後是ChangeEvent事件,表示光標已離開按鈕。可是應用程序一般只處理按下按鈕的完整動做的單個ActionEvent事件。
表 11-1 組件和事件類型事件類型組件描述
ActionEventJButton,JCheckBox
JComboBox,JMenuItem
JRadioButton點擊、選項或選擇
ChangeEventJSlider調整一個可移動元素的位置
AdjustmentEventJScrollBar調整滑塊位置
ItemEventJComboBox,JCheckBox
JRadioButton
JRadioButtonMenuItem
JCheckBoxMenuItem從一組可選方案中選擇一個項
目
ListSelectionEventJList選項事件
KeyEvent
MouseEventJComponent 及其派生類操縱鼠標或鍵盤
CareEventJTextArea,JTextField選擇和編輯文本
WindowEventWindow 及其派生類 JFrame對窗口打開、關閉和圖標化
每一個事件類型都有一個相應的監視器接口,表11-2列出了每一個接口的方法。實現監視器接口的類必須實現全部定義在接口中的方法。
表 11-2 監視器接口方法監視器接口方法獲取事件源的方法
ActionListeneractionPerformedgetSource,getActionCommand
ChangeListenerstateChangedgetSource
AdjustmentListeneradjustmentValueChangedgetAdjustable
FocusListenerfocusGained,
focusLost
ItemListeneritemStateChangedgetItemSelectable(),getSource()
ListSelectionListenervalueChangede.getSource().getSelectedValue()
KeyListenerkeyPressed,
keyReleased,
keyTyped
CareListenercareUpdate
MouseListenermouseClicked,
mouseEntered,
mouseExited,
mousePressed,
mouseReleased
MouseMontionListenermouseDragged,
mouseMoved
WindowListenerwindowClosed,
windowClosing,
windowDeactivated,
windowDeiconified,
windowIconified,
windowOpened