1. 調音台的COMP是什麼
調音台的第六排標有COMP的黃色旋鈕是雅馬哈調音台一個特有的功能旋鈕。這個旋鈕的功能是壓限。作用是保護設備。一般情況下都是保持他在0db。
調音台(Mixer)又稱調音控制台,它將多路輸入信號進行放大、混合、分配、音質修飾和音響效果加工,之後再通過母線(Master)輸出。調音台是現代電台廣播、舞台擴音、音響節目製作等系統中進行播送和錄制節目的重要設備。調音台按信號輸出方式可分為模擬式調音台和數字式調音台。
調音台在輸入通道數方面、面板功能鍵的數量方面以及輸出指示等方面都存在差異,其實,掌握使用調音台,要總體上去考察它,通過實際操作和連接,自然熟能生巧。調音台分為三大部分:輸入部分、母線部分、輸出部分。母線部分把輸入部分和輸出部分聯系起來,構成了整個調音台。
COMP基本原理
主要考慮同一區域天線埠之間的協作或不同區域中天線埠的協作; CoMP在一個eNodeB下設置多個射頻模塊接入點AP(Access Point),多個用戶可以同時從同一個或不同的eNodeB中的一個或多個AP那裡得到服務。
系統從分布的AP處收集信息,進行交互和計算後分配資源以滿足用戶的QoS需求和對整個網路資源的有效利用。
2. 如何理解c/c++和php語言的區別
一、編程語言
1.根據熟悉的語言,談談兩種語言的區別?
主要淺談下C/C++和PHP語言的區別:
1)PHP弱類型語言,一種腳本語言,對數據的類型不要求過多,較多的應用於Web應用開發,現在好多互聯網開發公司的主流web後台開發語言,主要框架為mvc模型,如smarty,yaf,升級的PHP7速度較快,對伺服器的壓力要小很多,在新浪微博已經有應用,對比很明顯。
2)C/C++開發語言,C語言更偏向硬體底層開發,C++語言是目前為止我認為語法內容最多的一種語言。C/C++在執行速度上要快很多,畢竟其他類型的語言大都是C開發的,更多應用於網路編程和嵌入式編程。
2.volatile是幹啥用的,(必須將cpu的寄存器緩存機制回答得很透徹),使用實例有哪些?(重點)
1) 訪問寄存器比訪問內存單元要快,編譯器會優化減少內存的讀取,可能會讀臟數據。聲明變數為volatile,編譯器不再對訪問該變數的代碼優化,仍然從內存讀取,使訪問穩定。
總結:volatile關鍵詞影響編譯器編譯的結果,用volatile聲明的變數表示該變數隨時可能發生變化,與該變數有關的運算,不再編譯優化,以免出錯。
2)使用實例如下( 區分C程序員和嵌入式系統程序員的最基本的問題。 ):
並行設備的硬體寄存器(如:狀態寄存器)
一個中斷服務子程序中會訪問到的非自動變數(Non-automatic variables)
多線程應用中被幾個任務共享的變數
3)一個參數既可以是const還可以是volatile嗎?解釋為什麼。
可以。一個例子是只讀的狀態寄存器。它是volatile因為它可能被意想不到地改變。它是const因為程序不應該試圖去修改它。
4)一個指針可以是volatile 嗎?解釋為什麼。
可以。盡管這並不是很常見。一個例子當中斷服務子程序修改一個指向一個buffer的指針時。
下面的函數有什麼錯誤:
int square(volatile int *ptr) {
return *ptr * *ptr;
}
下面是答案:
這段代碼有點變態。這段代碼的目的是用來返指針*ptr指向值的平方,但是,由於*ptr指向一個volatile型參數,編譯器將產生類似下面的代碼:
int square(volatile int *ptr){
int a,b;
a = *ptr;
b = *ptr;
return a * b;
}
由於*ptr的值可能被意想不到地改變,因此a和b可能是不同的。結果,這段代碼可能並不是你所期望的平方值!正確的代碼如下:
long square(volatile int *ptr){
int a;
a = *ptr;
return a * a;
}
更多linux內核視頻教程文本資料免費獲取後台私信【 內核 】。
3.static const等等的用法,(能說出越多越好)(重點)
² 首先說說const的用法(絕對不能說是常數)
1)在定義的時候必須進行初始化
2)指針可以是const 指針,也可以是指向const對象的指針
3)定義為const的形參,即在函數內部是不能被修改的
4)類的成員函數可以被聲明為正常成員函數,不能修改類的成員變數
5)類的成員函數可以返回的是常對象,即被const聲明的對象
6)類的成員變數是指成員變數不能在聲明時初始化,必須在構造函數的列表裡進行初始化
(註:千萬不要說const是個常數,會被認為是外行人的!!!!哪怕說個只讀也行)
下面的聲明都是什麼意思?
const int a; a是一個正常整型數
int const a; a是一個正常整型數
const int *a; a是一個指向常整型數的指針,整型數是不可修改的,但指針可以
int * const a; a為指向整型數的常指針,指針指向的整型數可以修改,但指針是不可修改的
int const * a const; a是一個指向常整型數的常指針,指針指向的整型數是不可修改的,同時指針也是不可修改的
通過給優化器一些附加的信息,使用關鍵字const也許能產生更緊湊的代碼。合理地使用關鍵字const可以使編譯器很自然地保護那些不希望被改變的參數,防止其被無意的代碼修改。簡而言之,這樣可以減少bug的出現。
Const如何做到只讀?
這些在編譯期間完成,對於內置類型,如int, 編譯器可能使用常數直接替換掉對此變數的引用。而對於結構體不一定。
² 再說說static的用法(三個明顯的作用一定要答出來)
1)在函數體內,一個被聲明為靜態的變數在這一函數被調用過程中維持其值不變。
2)在模塊內(但在函數體外),一個被聲明為靜態的變數可以被模塊內所用函數訪問,但不能被模塊外其它函數訪問。它是一個本地的全局變數。
3)在模塊內,一個被聲明為靜態的函數只可被這一模塊內的其它函數調用。那就是,這個函數被限制在聲明它的模塊的本地范圍內使用
4)類內的static成員變數屬於整個類所擁有,不能在類內進行定義,只能在類的作用域內進行定義
5)類內的static成員函數屬於整個類所擁有,不能包含this指針,只能調用static成員函數
static全局變數與普通的全局變數有什麼區別?static局部變數和普通局部變數有什麼區別?static函數與普通函數有什麼區別?
static全局變數與普通的全局變數有什麼區別:static全局變數只初始化一次,防止在其他文件單元中被引用;
static局部變數和普通局部變數有什麼區別:static局部變數只被初始化一次,下一次依據上一次結果值;
static函數與普通函數有什麼區別:static函數在內存中只有一份,普通函數在每個被調用中維持一份拷貝
4.extern c 作用
告訴編譯器該段代碼以C語言進行編譯。
5.指針和引用的區別
1)引用是直接訪問,指針是間接訪問。
2)引用是變數的別名,本身不單獨分配自己的內存空間,而指針有自己的內存空間
3)引用綁定內存空間(必須賦初值),是一個變數別名不能更改綁定,可以改變對象的值。
總的來說:引用既具有指針的效率,又具有變數使用的方便性和直觀性
6. 關於靜態內存分配和動態內存分配的區別及過程
1) 靜態內存分配是在編譯時完成的,不佔用CPU資源;動態分配內存運行時完成,分配與釋放需要佔用CPU資源;
2)靜態內存分配是在棧上分配的,動態內存是堆上分配的;
3)動態內存分配需要指針或引用數據類型的支持,而靜態內存分配不需要;
4)靜態內存分配是按計劃分配,在編譯前確定內存塊的大小,動態內存分配運行時按需分配。
5)靜態分配內存是把內存的控制權交給了編譯器,動態內存把內存的控制權交給了程序員;
6)靜態分配內存的運行效率要比動態分配內存的效率要高,因為動態內存分配與釋放需要額外的開銷;動態內存管理水平嚴重依賴於程序員的水平,處理不當容易造成內存泄漏。
7. 頭文件中的 ifndef/define/endif 干什麼用 ?
預處理,防止頭文件被重復使用,包括pragma once都是這樣的
8. 宏定義求兩個元素的最小值
#define MIN(A,B) ((A) next;
}
else
{
return NULL;
}
}
Node* pFind = pHead;
while (pCurrent) {
pFind = pFind->next;
pCurrent = pCurrent->next;
}
return pFind;
}
2. 給定一個單向鏈表(長度未知),請遍歷一次就找到中間的指針,假設該鏈表存儲在只讀存儲器,不能被修改
設置兩個指針,一個每次移動兩個位置,一個每次移動一個位置,當第一個指針到達尾節點時,第二個指針就達到了中間節點的位置
處理鏈表問題時,」快行指針「是一種很常見的技巧,快行指針指的是同時用兩個指針來迭代訪問鏈表,只不過其中一個比另一個超前一些。快指針往往先行幾步,或與慢指針相差固定的步數。
node *create() {
node *p1, *p2, *head;
int cycle = 1, x;
head = (node*)malloc(sizeof(node));
p1 = head;
while (cycle)
{
cout > x;
if (x != 0)
{
p2 = (node*)malloc(sizeof(node));
p2->data = x;
p1->next = p2;
p1 = p2;
}
else
{
cycle = 0;
}
}
head = head->next;
p1->next = NULL;
return head;
}
void findmid(node* head) {
node *p1, *p2, *mid;
p1 = head;
p2 = head;
while (p1->next->next != NULL)
{
p1 = p1->next->next;
p2 = p2->next;
mid = p2;
}
}
3. 將一個數組生成二叉排序樹
排序,選數組中間的一個元素作為根節點,左邊的元素構造左子樹,右邊的節點構造有子樹。
4. 查找數組中第k大的數字?
因為快排每次將數組劃分為兩組加一個樞紐元素,每一趟劃分你只需要將k與樞紐元素的下標進行比較,如果比樞紐元素下標大就從右邊的子數組中找,如果比樞紐元素下標小從左邊的子數組中找,如果一樣則就是樞紐元素,找到,如果需要從左邊或者右邊的子數組中再查找的話,只需要遞歸一邊查找即可,無需像快排一樣兩邊都需要遞歸,所以復雜度必然降低。
最差情況如下:假設快排每次都平均劃分,但是都不在樞紐元素上找到第k大第一趟快排沒找到,時間復雜度為O(n),第二趟也沒找到,時間復雜度為O(n/2),第k趟找到,時間復雜度為O(n/2k),所以總的時間復雜度為O(n(1+1/2+....+1/2k))=O(n),明顯比冒泡快,雖然遞歸深度是一樣的,但是每一趟時間復雜度降低。
5. 紅黑樹的定義和解釋?B樹的基本性質?
紅黑樹:
性質1. 節點是紅色或黑色。
性質2. 根節點是黑色。
性質3. 每個葉子結點都帶有兩個空的黑色結點(被稱為黑哨兵),如果一個結點n的只有一個左孩子,那麼n的右孩子是一個黑哨兵;如果結點n只有一個右孩子,那麼n的左孩子是一個黑哨兵。
性質4 每個紅色節點的兩個子節點都是黑色。(從每個葉子到根的所有路徑上不能有兩個連續的紅色節點)
性質5. 從任一節點到其每個葉子的所有路徑都包含相同數目的黑色節點。
B樹:
1.所有非葉子結點至多擁有兩個兒子(Left和Right);
2.所有結點存儲一個關鍵字;
3.非葉子結點的左指針指向小於其關鍵字的子樹,右指針指向大於其關鍵字的子樹;
6. 常見的加密演算法?
對稱式加密就是加密和解密使用同一個密鑰。
非對稱式加密就是加密和解密所使用的不是同一個密鑰,通常有兩個密鑰,稱為「公鑰」和「私鑰」,它們兩個必需配對使用。
DES:對稱演算法,數據加密標准,速度較快,適用於加密大量數據的場合;
MD5的典型應用是對一段Message產生fingerprint(指紋),以防止被「篡改」。
RSA是第一個既能用於數據加密也能用於數字簽名的演算法。
7. https?
HTTP下加入SSL層,HTTPS的安全基礎是SSL。
8.有一個IP庫,給你一個IP,如何能夠快速的從中查找到對應的IP段?不用資料庫如何實現?要求省空間
9.簡述一致性hash演算法。
1)首先求memcached伺服器(節點)的哈希值,並將其配置到0 232的圓(continuum)。
2)然後採用同樣的方法求出存儲數據的鍵的哈希值,並映射到相同的圓上。
3)然後從數據映射到的位置開始順時針查找,將數據保存到找到的第一個伺服器上。如果超過232仍然找不到伺服器,就會保存到第一台memcached伺服器上。
11.描述一種hash table的實現方法
1) 除法散列法: p ,令 h(k ) = k mod p ,這里, p 如果選取的是比較大的素數,效果比較好。而且此法非常容易實現,因此是最常用的方法。最直觀的一種,上圖使用的就是這種散列法,公式: index = value % 16,求模數其實是通過一個除法運算得到的。
2) 平方散列法 :求index頻繁的操作,而乘法的運算要比除法來得省時。公式: index = (value * value) >> 28 (右移,除以2^28。記法:左移變大,是乘。右移變小,是除)
3) 數字選擇法:如果關鍵字的位數比較多,超過長整型範圍而無法直接運算,可以選擇其中數字分布比較均勻的若干位,所組成的新的值作為關鍵字或者直接作為函數值。
4) 斐波那契(Fibonacci)散列法:平方散列法的缺點是顯而易見的,通過找到一個理想的乘數index = (value * 2654435769) >> 28
沖突處理:令數組元素個數為 S ,則當 h(k) 已經存儲了元素的時候,依次探查 (h(k)+i) mod S , i=1,2,3…… ,直到找到空的存儲單元為止(或者從頭到尾掃描一圈仍未發現空單元,這就是哈希表已經滿了,發生了錯誤。當然這是可以通過擴大數組范圍避免的)。
12、各類樹結構的實現和應用
13、hash,任何一個技術面試官必問(例如為什麼一般hashtable的桶數會取一個素數?如何有效避免hash結果值的碰撞)
不選素數的話可能會造成hash出值的范圍和原定義的不一致
14.什麼是平衡二叉樹?
左右子樹都是平衡二叉樹,而且左右子樹的深度差值的約對值不大於1。
15.數組和鏈表的優缺點
數組,在內存上給出了連續的空間。鏈表,內存地址上可以是不連續的,每個鏈表的節點包括原來的內存和下一個節點的信息(單向的一個,雙向鏈表的話,會有兩個)。
數組優於鏈表的:
A. 內存空間佔用的少。
B. 數組內的數據可隨機訪問,但鏈表不具備隨機訪問性。
C. 查找速度快
鏈表優於數組的:
A. 插入與刪除的操作方便。
B. 內存地址的利用率方面鏈表好。
C. 方便內存地址擴展。
17.最小堆插入,刪除編程實現
18. 4G的long型整數中找到一個最大的,如何做?
每次從磁碟上盡量多讀一些數到內存區,然後處理完之後再讀入一批。減少IO次數,自然能夠提高效率。分批讀入選取最大數,再對緩存的最大數進行快排。
19. 有千萬個string在內存怎麼高速查找,插入和刪除?
對千萬個string做hash,可以實現高速查找,找到了,插入和刪除就很方便了。關鍵是如何做hash,對string做hash,要減少碰撞頻率。
在內存中維護一個大小為10000的最小堆,每次從文件讀一個數,與最小堆的堆頂元素比較,若比堆頂元素大,則替換掉堆頂元素,然後調整堆。最後剩下的堆內元素即為最大的1萬個數,演算法復雜度為O(NlogN)
(1)全局洗牌法
a)首先生成一個數組,大小為54,初始化為1~54
b)按照索引1到54,逐步對每一張索引牌進行洗牌,首先生成一個余數 value = rand %54,那麼我們的索引牌就和這個余數牌進行交換處理
c)等多索引到54結束後,一副牌就洗好了
(2)局部洗牌法:索引牌從1開始,到54結束。這一次索引牌只和剩下還沒有洗的牌進行交換, value = index + rand() %(54 - index)
演算法復雜度是O(n)
22.請分別用遞歸和非遞歸方法,先序遍歷二叉樹
24.其他各種排序方法
25.哈希表沖突解決方法?
常見的hash演算法如下:
解決沖突的方法:
也叫散列法,主要思想是當出現沖突的時候,以關鍵字的結果值作為key值輸入,再進行處理,依次直到沖突解決
線性地址再散列法
當沖突發生時,找到一個空的單元或者全表
二次探測再散列
沖突發生時,在表的左右兩側做跳躍式的探測
偽隨機探測再散列
同時構造不同的哈希函數
將同樣的哈希地址構造成一個同義詞的鏈表
建立一個基本表和溢出區,凡是和基本元素發生沖突都填入溢出區
六、系統架構
1.設計一個服務,提供遞增的SessionID服務,要求保證服務的高可靠性,有哪些方案?集中式/非集中式/分布式
2.多台伺服器要執行計劃任務,但只有拿到鎖的任務才能執行,有一個中心伺服器來負責分配鎖,但要保證服務的高可靠性。
3.如何有效的判斷伺服器是否存活?伺服器是否踢出集群的決策如何產生?
4.兩個伺服器如何在同一時刻獲取同一數據的時候保證只有一個伺服器能訪問到數據?
可以採用隊列進行處理,寫一個隊列介面保證同一時間只有一個進程能夠訪問到數據,或者對於存取資料庫的來說,資料庫也是可以加鎖處理的
5. 編寫高效伺服器程序,需要考慮的因素
性能對伺服器程序來說是至關重要的了,畢竟每個客戶都期望自己的請求能夠快速的得到響應並處理。那麼影響伺服器性能的首要因素應該是:
(1)系統的硬體資源,比如說CPU個數,速度,內存大小等。不過由於硬體技術的飛速發展,現代伺服器都不缺乏硬體資源。因此,需要考慮的主要問題是如何從「軟環境」來提升伺服器的性能。
伺服器的」軟環境「
(2)一方面是指系統的軟體資源,比如操作系統允許用戶打開的最大文件描述符數量
(3)另一方面指的就是伺服器程序本身,即如何從編程的角度來確保伺服器的性能。
主要就要考慮大量並發的處理這涉及到使用進程池或線程池實現高效的並發模式(半同步/半非同步和領導者/追隨者模式),以及高效的邏輯處理方式--有限狀態機內存的規劃使用比如使用內存池,以空間換時間,被事先創建好,避免動態分配,減少了伺服器對內核的訪問頻率,數據的復制,伺服器程序還應該避免不必要的數據復制,尤其是當數據復制發生在用戶空間和內核空間之間時。如果內核可以直接處理從socket或者文件讀入的數據,則應用程序就沒必要將這些數據從內核緩沖區拷貝到應用程序緩沖區中。這里所謂的「直接處理」,是指應用程序不關心這些數據的具體內容是什麼,不需要對它們作任何分析。比如說ftp伺服器,當客戶請求一個文件時,伺服器只需要檢測目標文件是否存在,以及是否有許可權讀取就可以了,不需要知道這個文件的具體內容,這樣的話ftp伺服器就不需要把目標文件讀入應用程序緩沖區然後調用send函數來發送,而是直接使用「零拷貝」函數sendfile直接將其發送給客戶端。另外,用戶代碼空間的數據賦值也應該盡可能的避免復制。當兩個工作進程之間需要傳遞大量的數據時,我們就應該考慮使用共享內存來在他們直接直接共享這些數據,而不是使用管道或者消息隊列來傳遞。上下文切換和鎖:並發程序必須考慮上下文的切換問題,即進程切換或線程切換所導致的系統開銷。即時I/O密集型伺服器也不應該使用過多的工作線程(或工作進程),否則進程間切換將佔用大量的CPU時間,伺服器真正處理業務邏輯的CPU時間比重就下降了。因此為每個客戶連接都創建一個工作線程是不可取的。應該使用某種高效的並發模式。(半同步半非同步或者說領導者追隨者模式)另一個問題就是共享資源的加鎖保護。鎖通常被認為是導致伺服器效率低下的一個因素,因為由他引入的代碼不僅不處理業務邏輯,而且需要訪問內核資源,因此如果伺服器有更好的解決方案,應該盡量避免使用鎖。或者說伺服器一定非要使用鎖的話,盡量使用細粒度的鎖,比如讀寫鎖,當工作線程都只讀一塊內存區域時,讀寫鎖不會增加系統開銷,而只有當需要寫時才真正需要鎖住這塊內存區域。對於高峰和低峰的伸縮處理,適度的緩存。
6. QQ飛車新用戶注冊時,如何判斷新注冊名字是否已存在?(數量級:幾億)
可以試下先將用戶名通過編碼方式轉換,如轉換64位整型。然後設置N個區間,每個區間為2^64/N的大小。對於新的用戶名,先通過2分尋找該用戶名屬於哪個區間,然後在在這個區間,做一個hash。對於不同的時間復雜度和內存要求可以設置不同N的大小~
加一些基礎的技術面試之外的職業素養的面試問題
1.你在工作中犯了個錯誤,有同事打你小報告,你如何處理?
a.同事之間應該培養和形成良好的同事關系,就是要互相支持而不是互相拆台,互相學習,互相幫助,共同進步。
b.如果小報告里邊的事情都是事實也就是說確實是本人做的不好不對的方面,那麼自己應該有則改之,提高自己。如果小報告里邊的事
情全部不是事實,就是說確實誣陷,那麼應該首先堅持日久見人心的態度,持之以恆的把本職工作做好,然後在必要的時候通過適當的
方式和領導溝通,相信領導會知道的。
2.你和同事合作完成一個任務,結果任務錯過了截止日期,你如何處理?
3.職業規劃?
4.離職原因?
5. 項目中遇到的難題,你是如何解決的?
A.時間 b要求 c.方法
3. 問個問題:上海的總面積大還是泉州的總面積大
上海簡稱滬。全市面積6340.5平方千米,佔全國總面積的0.06%
泉州土地面積11015平方公里,現轄鯉城區、豐澤區、洛江區、晉江市、石獅市、南安市、惠安縣、安溪縣、永春縣、德化縣和金門縣(待統一),以及肖厝區域。
泉州大
4. unity虛擬搖桿
在手機游戲中,虛擬搖桿游戲中的虛擬遙感很常見,先根據自己已經會虛擬搖桿來製作,虛擬搖桿醉主要的核心是
C#部分
2D虛擬搖桿
先弄個自定義的觸發事件,然後給每一個需要觸發的事件按鈕添加,EventTrigget,需要注意的是這個事件要繼承unity的介面,
製作unity的搖桿的話,需要繼承unity的的UI介面 IBeginDragHandler, IDragHandler, IEndDragHandler,IPointerClickHandler
首先先定義四個委託
public Action<GameObject, PointerEventData> onBeginDrag;
public Action<GameObject, PointerEventData> onDrag;
public Action<GameObject, PointerEventData> onEndDrag;
public Action<GameObject, PointerEventData> onClick;
其次是重寫unity繼承的四個介面,把每個委託的回調放進去這些介面函數裡面,一但滿足條件,委託會執行函數回調方法
public void OnBeginDrag(PointerEventData eventData) {
if (onBeginDrag != null)
{
onBeginDrag(gameObject, eventData);
}
}
public void OnDrag(PointerEventData eventData) {
if (onDrag != null)
{
onDrag(gameObject, eventData);
}
}
public void OnEndDrag(PointerEventData eventData) {
if (onEndDrag != null)
{
onEndDrag(gameObject, eventData);
}
}
public void OnPointerClick(PointerEventData eventData){
if (onClick != null)
{
onClick(gameObject, eventData);
}
}
有了這些委託方法之後,如何使用,這個調用方法,會在初始化注冊事件,
public static EventTrigger GetEventCallBack(GameObject obj)
{
Event trigger = obj.GetComponent<EventTrigger>();
if (trigger == null)
{
trigger = obj.AddComponent<EventTrigger>();
}
return trigger;
}
創建以一個控制虛擬搖桿StickJoyUI腳本,注冊委託事件
TriggerEvent.Get(bgObj).onBeginDrag = OnDragBegin;
TriggerEvent.Get(bgObj).onDrag = OnDrag;
TriggerEvent.Get(bgObj).onEndDrag = OnDragEnd;
TriggerEvent.Get(transform.Find("changeAttack").gameObject).onClick = OnChangeAttack;
TriggerEvent.Get(transform.Find("AttackBtn").gameObject).onClick = OnAttackBtn;
再來看看虛擬搖桿部分OnDragBegin OnDrag OnDragEnd 這個三個方法控制虛擬搖桿,
private void OnDragBegin(GameObject obj, PointerEventData evetData)
{
}
private void OnDrag(GameObject obj, PointerEventData evetData)
{ Vector2 point;
//("需要轉換的對象的父級的RectTrasform","滑鼠的位置","當前的攝像機","轉換後的ui的相對坐標")
bg為要拖拽的對象的父級對象,裡面還有一個小圓PointTf,滑鼠的位置取拖拽事件的的position,滑鼠的位置取拖拽事件的的攝像機,轉
if (RectTransformUtility.(bgTf, evetData.position, evetData.pressEventCamera, out point)) {
//拖動的方向
Vector2 v = (point - Vector2.zero).normalized;
x = v.x;
y = v.y;
if (Vector2.Distance(point, Vector2.zero) <= R)
{
pointTf.anchoredPosition = point;
}
else //超出移動的半徑
{
//位置 = 初始位置 + 方向 * 距離
pointTf.anchoredPosition = Vector2.zero + v * R;
}
}
}
private void OnDragEnd(GameObject obj, PointerEventData evetData)
{
pointTf.anchoredPosition = Vector2.zero;
x = 0;
y = 0;
}
Ps:2D角色還需要注意人物朝向問題
只需要把裡面的的X值和Y值賦予給他實時更新,然後在寫一個Flip方法判斷朝向問題,本質是修改一下縮放的X改成相反的值就好了
//朝向
void Flip()
{
if (x > 0)
{
transform.localScale = new Vector3(1, 1, 1);
}
else if (x < 0)
{
transform.localScale = new Vector3(-1, 1, 1);
}
}
3D模式:把把X值和Y賦予個移動函數的x值和z值即可
接下用js實現虛擬搖桿(思路跟上面差不多,但是數據的處理稍有差別而已)
首先引入玩家模塊
var Player = require("player");
屬性定義
cc.Class({
extends: cc.Component,
properties: {
stickNode:{
default:null,
type:cc.Node
},
fillNode:{
default:null,
type:cc.Node
},
skillBtn:{
default:null,
type:cc.Node
},
player:{
default:null,
type:Player
},
R:50,
stick_x:0,
stick_y:0
},
在初始化函數Onlade中注冊事件
onLoad () {
this.stickNode = cc.find("Stick",this.node);
this.fillNode = cc.find("Stick/fill",this.node);
this.skillBtn = cc.find("skillBtn",this.node);
//注冊開始拖拽,拖拽事件,拖拽結束事件,和點擊事件,這個更上面的四個介面類似
this.stickNode.on(cc.Node.EventType.TOUCH_START,this.onTouchStart,this);
this.stickNode.on(cc.Node.EventType.TOUCH_MOVE,this.onTouchMove,this);
this.stickNode.on(cc.Node.EventType.TOUCH_END,this.onTouchEnd,this);
this.stickNode.on(cc.Node.EventType.TOUCH_CANCEL,this.onTouchCancel,this);
this.skillBtn.on("click",this.onClickSkillBtn,this);
},
onTouchStart(event)
{
},
onTouchMove(event)
{
var pos = event.getLocation();//v2類型 坐標系
//當前這個滑鼠的世界坐標轉換成當前節點的相對坐標
pos = this.stickNode.convertToNodeSpaceAR(pos);
if(pos.magSqr()<=this.R*this.R)
{
this.fillNode.setPosition(pos);
}
else
{
this.fillNode.x = pos.normalizeSelf().x*this.R;
this.fillNode.y = pos.normalizeSelf().y*this.R;
}
this.stick_x = pos.normalizeSelf().x;
this.stick_y = pos.normalizeSelf().y;
},
onTouchEnd(event)
{
this.fillNode.x = 0;
this.fillNode.y = 0;
this.stick_x = 0;
this.stick_y = 0;
},
onTouchCancel(event)
{
this.fillNode.x = 0;
this.fillNode.y = 0;
this.stick_x = 0;
this.stick_y = 0;
},
onClickSkillBtn()
{
//執行玩家腳本使用技能的方法
this.player.playSkill();
}
PS:計算上面的pos的方向, 上面為啥半徑平方而不是把開方呢??,開方消耗性能,給半徑平方兩者比較也能比較,相對與前者開方,後者半徑平方更加節省性能,採用迂迴思路,感覺這種思想有很多地方都用到,就比如前面的浮點數處理,既然有誤差,那麼我可以放大倍數,然後要使用時候,我再縮小倍數。
5. 基帶和頻帶的區別
通常大型建築物內部的層間有樓板,房間有牆壁,室內與室內用戶之間有空間分割,BBU+RRU多通道方案就是利用這一特性。對於超過10萬平方米的大型體育場館,可將看台劃分為幾個小區,每個小區設置幾個通道,每個通道對應一面板狀天線。
通常室內分布系統採用電纜的電分布方式,而BBU+RRU方案則採用光纖傳輸的分布方式。基帶BBU集中放置在機房,RRU可安裝至樓層,BBU與RRU之間採用光纖傳輸,RRU再通過同軸電纜及功分器(耦合器)等連接至天線,即主幹採用光纖,支路採用同軸電纜。
對於下行方向:光纖從BBU直接連到RRU,BBU和RRU之間傳輸的是基帶數字信號,這樣基站可以控制某個用戶的信號從指定的RRU通道發射出去,這樣可以大大降低對本小區其他通道上用戶的干擾。
對於上行方向:用戶手機信號被距離最近的通道收到,然後從這個通道經過光纖傳到基站,這樣也可以大大降低不同通道上用戶之間的干擾。BBU+RRU方案對於容量配置非常靈活,可按容量需求,在不改變RRU和室內分布系統的前提下,通過配置BBU來支持每通道從1/6載波到3載波的擴容。
全稱Building Base band Unit ,中文名:基帶處理單元。RRU(射頻拉遠單元)和BBU(基帶處理單元)之間需要用光纖連接。一個BBU可以支持多個RRU。採用BBU+RRU多通道方案,可以很好地解決大型場館的室內覆蓋。
基帶傳輸
在信道中直接傳送基帶信號時,稱為基帶傳輸。進行基帶傳輸的系統稱為基帶傳輸系統。傳輸介質的整個信道被一個基帶信號佔用.基帶傳輸不需要數據機,設備花費小,具有速率高和誤碼率低等優點,適合短距離的數據傳輸,傳輸距離在100米內,在音頻市話、計算機網路通信中被廣泛採用。
在有線信道中,直接用電傳打字機進行通信時傳輸的信號就是基帶信號。一個企業、工廠,就可以採用這種方式將大量終端連接到主計算機。基帶數據傳輸速率為0~10Mb/s,更典型的是1Mb/s~2.5Mb/s,通常用於傳輸數字信息。
頻帶傳輸
在信道中直接傳送頻帶信號時,稱為頻帶傳輸。可以遠距離傳輸.它的缺點是速率低,誤碼率高.
一般說的頻帶傳輸是數字基帶信號經調制變換,成為能在公用電話線上傳輸的模擬信號,模擬信號經模擬傳輸媒體傳送到接收端後,再還原成原來信號的傳輸。這種頻帶傳輸不僅克服了許多長途電話線路不能直接傳輸基帶信號的缺點,而且能夠實現多路復用,從而提高了通信線路的利用率。但是頻帶傳輸在發送端和接收端都要設置數據機,將基帶信號變換為頻帶信號再傳輸。頻帶傳輸的優點是可以利於現有的大量模擬信道(如模擬電話交換網)通信.價格便宜,容易實現.家庭用戶撥號上網就屬於這一類通信.
寬頻傳輸
寬頻傳輸Broadband,是相對一般說的頻帶傳輸而言的寬頻帶傳輸。寬頻是指比音頻帶寬更寬的頻帶,它包括大部分電磁波頻譜。使用這種寬頻帶傳輸的系統,稱為寬頻傳輸系統.其通過藉助頻帶傳輸,可以將鏈路容量分解成兩個或更多的信道,每個信道可以攜帶不同的信號,這就是寬頻傳輸。寬頻傳輸中的所有信道都可以同時發送信號。如CATV、ISDN等。傳輸的頻帶很寬在>=128kbps
寬頻是傳輸模擬信號,數據傳輸速率范圍為0~400Mb/s,而通常使用的傳輸速率是5Mb/s~10Mb/s。它可以容納全部廣播,並可進行高速數據傳輸。寬頻傳輸系統多是模擬信號傳輸系統。
一般說,寬頻傳輸與基帶傳輸相比有以下優點:
(1)能在一個信道中傳輸聲音、圖像和數據信息,使系統具有多種用途;
(2)一條寬頻信道能劃分為多條邏輯基帶信道,實現多路復用,因此信道的容量大大增加;
(3)寬頻傳輸的距離比基帶遠,因數字基帶直接傳送數字,傳輸的速率愈高,傳輸的距離愈短。
不要混淆基帶,基帶信號,基帶傳輸這幾個概念。
通常情況下,(Radio Remote Unit)) ,是在遠端將基帶光信號轉成射頻信號放大傳送出去。直放站就是將基站射頻信號接收放大再傳送出去。區別就是直放站會將雜訊同時放大,而射頻拉遠則不會。
RRU基本介紹
拉遠就是把基站的基帶單元和射頻單元分離,兩者之間傳輸的是基帶信號,而光纖直放站是從基站的射頻輸出口耦合出射頻信號轉換為光信號在光纖中傳輸,然後遠端再轉為射頻放大!
RRU工作原理
射頻拉遠單元RRU(Radio Remote Unit)帶來了一種新型的分布式網路覆蓋模式,它將大容量宏蜂窩基站集中放置在可獲得的中心機房內,基帶部分集中處理,採用光纖將基站中的射頻模塊拉到遠端射頻單元,分置於網路規劃所確定的站點上,從而節省了常規解決方案所需要的大量機房;同時通過採用大容量宏基站支持大量的光纖拉遠,可實現容量與覆蓋之間的轉化。
RRU的工作原理是:基帶信號下行經變頻、濾波,經過射頻濾波、經線性功率放大器後通過發送濾波傳至天饋。上行將收到的移動終端上行信號進濾波、低雜訊放大、進一步的射頻小信號放大濾波和下變頻,然後完成模數轉換和數字中頻處理等。
RRU同基站介面的連接介面有兩種:CPRI(Common Public Radio Interface 通用公共射頻介面)及OBSAI(Open Base Station Architecture Initiative 開放式基站架構)。
信號覆蓋方式上,RRU可通過同頻不同擾碼方式,從NodeB引出。也可通過同頻不同擾碼方式,從RNC引出。這兩種覆蓋方式都是常規的方式,除此之外,對於3扇區,但配有多餘信道板以及多餘基帶處理設備的基站可以利用基帶池共享技術,將多餘的基帶處理設備設為第4小區
RRU同數字光纖直放站都可利用現有成熟的乙太網數字光纖傳輸技術傳輸基帶信號,並共同遵守標準的CPRI和OBSAI介面。使用中可實現RRU和數字光纖直放站的遠端機的互相替換。
兩者均可作為室內分布系統的信號源,選用哪一種取決於宏基站的載頻數量和該室內業務量需求。如果宏基站載頻多、容量很富裕,用數字光纖直放站拉遠更合適,同時可減少扇區擾碼。如果該室內業務量需求較大應選用RRU作信號源。如果業務量需求很大,如大型寫字樓、會展中心等,應考慮數字光纖直放站、RRU和宏基站的聯合組網。
在覆蓋距離上,兩者均可作為基站拉遠系統供用,數字光纖直放站用作載波池拉遠,RRU可用作基帶池拉遠。載波池拉遠距離取決於小區覆蓋半徑和光在光纖上的傳輸速度,數字信號在光纖中傳播,其動態范圍也較模擬信號大,這樣就可以實現遠端機更大的信號覆蓋;同時,數字信號不隨光信號的衰減而衰減,因此其傳輸(拉遠)距離也進一步增加了。經計算,最遠可達40km以上,用作基帶池拉遠的RRU基本不受距離限制,可拉得更遠。
在組網方式上,RRU作為拉遠單元可單獨使用,而數字光纖直放站由近端機和遠端機組成,在實際應用時,近端機是一個,而遠端機可以是一個或多個,組網上可並聯也可串聯,組網方式也可以多樣化,如:菊花鏈形、環形、樹形等等。
在擾碼的使用上,數字光纖直放站射頻信號的擾碼總是同施主基站的擾碼相同,數字光纖直放站也不增加基站信道板硬體容量和正交碼容量,所以在扇區內大量採用並不會增加擾碼。射頻拉遠單元RRU是利用基站剩餘的信道板和基帶處理設備組成新的扇區,通過光纖系統拉到遠處,有人稱它為基帶池技術,也有人叫它拉遠的微蜂窩技術,總之,它具有硬體容量,並且擁有新的擾碼和同步碼。由於RRU具有基站性能,在宏基站的扇區內大量採用必然會增加很多擾碼和鄰區列表,會發生導頻污染,軟切換增加。在網路優化時這是必須注意的問題。
在傳輸時延上,數字光纖直放站的傳輸時延比較大,因為存在兩次變頻過程。而RRU直接傳送基帶信號,時延不明顯。
在底噪抬升上,數字光纖直放站僅採用ADC和DAC,此過程只可能引入更多的量化雜訊,從而抬升上行雜訊。而RRU傳輸的為純基帶信號,可不用考慮底噪問題。
從成本上,採用RRU技術,可以節省常規建網方式中需要的大量機房,節約基帶單元的投資。RRU體積小,重量輕,可以應用於城區機房條件不理想或者機房匱乏的情況,但是應用前提是需要有光纖進行傳輸。但在價格方面,RRU比直放站要貴1/3左右。對於一拖一的系統,數字光纖直放站成本優勢不明顯,但一拖多,成本優勢就比較明顯了。
6. 西班牙的英語
您想問西班牙用英語怎麼說。西班牙的英語單詞為Spain。
西班牙語言languagesofspain,Spanishlanguages。西班牙語語法Spanishgrammar,GrammaroftheSpanishlanguage。西班牙語動詞spanishconjugation。
西班牙(Espa_a)全稱西班牙王國(西班牙語:ReinodeEspa_a,英語:TheKingdomofSpain),是一個位於歐洲西南部的君主立憲制國家。地處歐洲與非洲的交界,西鄰同處於伊比利亞半島的葡萄牙,北瀕比斯開灣,東北部與法國及安道爾接壤,南隔直布羅陀海峽與非洲的摩洛哥相望,領土還包括地中海中的巴利阿里群島,大西洋的加那利群島及非洲的休達和梅利利亞。該國是一個多山國家,總面積505925平方公里,其海岸線長約7800公里。
7. 廣州市天河區的面積到底是多少
天河區位於中國第三大城市廣州市老城區的東部,東到玉樹尖峰嶺、吉山獅山、前進深涌一帶,與黃埔區相連;南到珠江,與海珠區隔江相望;西從廣州大道、楊箕、先烈東路、永福路,沿廣深鐵路方向達登峰,與越秀區相接;北到筲箕窩,與白雲區和蘿崗區相接,總面積96.33平方千米。
8. nodejs + express怎麼實現Ajax方式及其簡單功能
nodejs + express怎麼實現Ajax方式及其簡單功能
4) 對庫函數的調用不需要再作說明,但必須把該函數的頭文件用include命令包含在源文件前部。
8.5 函數的嵌套調用
C語言中不允許作嵌套的函數定義。因此各函數之間是平行的,不存在上一級函數和下一級函數的問題。但是C語言允許在一個函數的定義中出現對另一個函數的調用。這樣就出現了函數的嵌套調用。即在被調函數中又調用其它函數。這與其它語言的子程序嵌套的情形是類似的。其關系可表示如圖。
圖表示了兩層嵌套的情形。其執行過程是:執行main函數中調用a函數的語句時,即轉去執行a函數,在a函數中調用b 函數時,又轉去執行b函數,b函數執行完畢返回a函數的斷點繼續執行,a函數執行完畢返回main函數的斷點繼續執行。
【例8.4】計算s=22!+32!
本題可編寫兩個函數,一個是用來計算平方值的函數f1,另一個是用來計算階乘值的函數f2。主函數先調f1計算出平方值,再在f1中以平方值為實參,調用 f2計算其階乘值,然後返回f1,再返回主函數,在循環程序中計算累加和。
long f1(int p)
{
int k;
long r;
long f2(int);
k=p*p;
r=f2(k);
return r;
}
long f2(int q)
{
long c=1;
int i;
for(i=1;i<=q;i++)
c=c*i;
return c;
}
main()
{
int i;
long s=0;
for(i=2;i<=3;i++)
s=s+f1(i);
printf("\ns=%ld\n",s);
}
9. 用C語言編寫一個計算器程序,實現加,減,乘,除,求平方根(正數),倒數等功能.
#include<iostream>
#include<cmath>
#include<string>
using namespace std;
const double pi = 3.14159265; const double e = 2.718281828459; const int SIZE = 1000;
typedef struct node//為了處理符號而建立的鏈表(如: 1+(-2)) { char data; node *next; }node;
typedef struct stack_num//存儲 數 的棧 { double *top; double *base; }stack_num;
typedef struct stack_char//存儲 運算符號 的棧 { char *top; char *base; }stack_char;
stack_num S_num;//定義 stack_char S_char;//定義
char fu[18] = {'\n', ')', '+', '-', '*', '/', '%', '^', 'Q', 'L', 'C', 'S', 'T', 'c', 's', 't', '('};
int compare[1000];//表現出各運算符號的優先順序 double shu[1000];//存儲 "數" 的數組
double dai_result;//運算的結果,是為了處理 M 運算(簡介函數里有M的定義) int biao = 0;//和dia_result 一樣,為了處理 M 運算 char line[SIZE];//輸入的所要計算的表達式
void init()//初始化 { compare[fu[0]] = -2;//用數字的大小表現出符號的優先順序
compare[fu[1]] = -1; compare[fu[2]] = 2; compare[fu[3]] = 2; compare[fu[4]] = 4; compare[fu[5]] = 4; compare[fu[6]] = 4; compare[fu[7]] = 5; for(int i = 8; i <= 15; i++) compare[fu[i]] = 6; compare[fu[16]] = 7; S_num.base = (double*)malloc(sizeof(double)*SIZE);//為棧開辟空間 S_char.base = (char*)malloc(sizeof(char)*SIZE);//同上 S_num.top = S_num.base; S_char.top = S_char.base; }
void push_num(double n)//數字進棧 { * ++S_num.top = n; }
void push_char(char c)//運算符號進棧 { * ++S_char.top = c; }
double pop_num()//數字出棧 { double m = *S_num.top; S_num.top--; return m; }
char pop_char()//運算符號出棧 { char cc = *S_char.top; S_char.top--; return cc; }
char get_top_char()//得到運算符號的棧中最頂端的運算符號 { return *S_char.top;
}
double operate(double y, char c, double x)//
對兩個數計算
(
含是雙目運算符
:
如
*, /
等等
)
{
double r;
if(c == '-')
r = x - y;
else if(c == '+')
r = x + y;
else if(c == '/' && y != 0)
r = x / y;
else if(c == '*')
r = x * y;
else if(c == '^')
{
r = 1;
for(int i = 1; i <= y; i++)
r *= x;
}
else if(c == '%')
{
int r0 = (int)x % (int)y;
r = double(r0);
}
return r;
}
double operate_one(double one, char cc)//
對一個數運算
(
含單目運算符
:
如
log(L), sin(S)
等等
)
{
double r;
if(cc == 'Q')
r = sqrt(one);
else if(cc == 'C')
r = cos(one);
else if(cc == 'S')
r = sin(one);
else if(cc == 'T')
r = tan(one);
else if(cc == 'c')
i++;
}
i++;
}
if(ge >= 3)
return 0;
else
return 1;
}
void output(double result)//
打出結果
{
printf("
所得結果是
: ");
cout<<result<<endl;
}
void check()//
檢查表達式是否合法
{
void introce();
char cc;//
決定計算器按哪種功能進行計算
double result;//
結果
void input();//
定義
if( check_kuohao() && check_char() )//
看是否合法
,
合法則計算
{
result = compute();
output(result);
cout<<"
輸入一個字元
'M'
或
'D'
或
'F',
決定是否繼續
: "<<endl;
while(cin>>cc)
{
if(cc == 'M')
{
system("cls");
introce();
printf("
您上次所得結果為
: ");
cout<<result<<endl;
cout<<"
在上次計算結果的基礎上
,
請繼續輸入想計算的表達式
"<<endl;
dai_result = result;
biao = 1;
input();//
輸入表達式
break;
}
else if(cc == 'D')
{
system("cls");
introce();
cout<<"
計算器已清零
,
請輸入您所要計算的表達式
"<<endl;
input();//
輸入表達式
break;
}
else if(cc == 'F')
{
system("cls");
cout<<"
計算器關閉
,
謝謝使用
!"<<endl;
break;
}
else
{
cout<<"
所輸入字元無效
,
請輸入一個字元
'M'
或
'D'
或
'F'!"<<endl;
continue;
}
}
}
else//
不合法,分兩種不合法
{
if(check_kuohao() == 0 && check_char() == 1)
{
cout<<"
您所輸入的表達式括弧不匹配
,
請重新輸入
:"<<endl;
input();//
輸入表達式
}
else
{
cout<<"
您所輸入的表達式不合法
,
請重新輸入
:"<<endl;
input();//
輸入表達式
}
}
}
void tackle_fuhao()//
處理負號
{
node *root, *head, *p, *q, *p1;
root = head = new node;
head->next = NULL;
int i;
for(i = 0; line[i] != '\0'; i++)//
建立鏈表
{
p = new node;
p->data = line[i];
p->next = head->next;
head->next = p;
head = p;
}
// delete p;
q = (node*)malloc(sizeof(node));
head = root;
if(root->next->data == '+' || root->next->data == '-')//
處理第一個字元
{
p = new node;
p->data = '0';
p->next = head->next;
head->next = p;
}
if(root->next != NULL)
{
for(q = root->next; q; q = q->next)
{
if(q->data == '(' && (q->next->data == '-' || q->next->data == '+'))
{
p = new node;
p->data = '0';
p->next = q->next;
q->next = p;
}
}
}
// delete q;
p1 = new node;
int qi = -1;
for(p1 = root->next; p1; p1 = p1->next)
{
line[++qi] = p1->data;
}
line[++qi] = '\0';
}
void input()//
輸入
{
cin>>line;
if(biao == 0)
tackle_fuhao();//
處理負號
check();//
檢查表達式是否合法
}
void introce()//
對計算器的符號功能的簡要介紹
{
cout<<"
計算器簡要介紹
"<<endl;
cout<<"C(cos)
S(sin)
T(tan)
a(arccos)
c(arcsin) "<<endl;
cout<<"7
8
9
/
on
t(arctan) "<<endl;
cout<<"4
5
6
*
%
L(log)"<<endl;
cout<<"1
2
3
-
M(M+)
Q(sqrt)
"<<endl;
cout<<"0
.
+
^(
乘方
) F(off)
Enter(=) "<<endl;
cout<<"
對於對數輸入
L2_5
表示以
2
為底
5
的對數
"<<endl;
cout<<"M(
在前面結果的基礎上繼續計算,
如:
上次結果為
10
,
現輸入
+10.5*2)"<<endl;
cout<<"D(
清零並繼續輸入
)"<<endl;
cout<<"F(
計算機關閉
)"<<endl;
cout<<"
輸入
P
就代表輸入圓周率
,
輸入
E
代表輸入自然對數
"<<endl<<endl;
}
void print()
{
system("color 2");
cout<<"
歡迎使用本計算器
"<<endl;
cout<<"
輸入一個字元串
on,
計算器開始啟動
"<<endl;
}
void if_start()//
是否啟動計算器
{
string start;
print();
while(cin>>start)
{
if(start != "on")
{
cout<<"
您所輸入的字元無效
,
請按照介紹的繼續輸入
:"<<endl;
continue;
}
else
break;
}
if(start == "on")
{
system("color 5");//
顏色的處理
system("cls");//
刷屏
}
introce();//
對計算器的簡要介紹
cout<<"
現在
,
請輸入您所要計算的表達式
"<<endl;
input();//
輸入所要計算的表達式
}
int main()
{
if_start();//
調用是否啟動計算器函數
return 0;
}
r = acos(one);
else if(cc == 's')
r = asin(one);
else if(cc == 't')
r = atan(one);
10. 不懂急,請問javascript對象的問題
上樓回答的很不錯了你看看這一個純JavaScript教程網站吧
我就是靠他學的http://www.ijavascript.cn/
JavaScript 是使用「對象化編程」的,或者叫「面向對象編程」的。所謂「對象化編程」,意思是把 JavaScript 能涉及的范圍劃分成大大小小的對象,對象下面還繼續劃分對象直至非常詳細為止,所有的編程都以對象為出發點,基於對象。小到一個變數,大到網頁文檔、窗口甚至屏幕,都是對象。這一章將「面向對象」講述 JavaScript 的運行情況。
對象的基本知識
對象是可以從 JavaScript「勢力范圍」中劃分出來的一小塊,可以是一段文字、一幅圖片、一個表單(Form)等等。每個對象有它自己的屬性、方法和事件。對象的屬性是反映該對象某些特定的性質的,例如:字元串的長度、圖像的長寬、文字框(Textbox)里的文字等等;對象的方法能對該對象做一些事情,例如,表單的「提交」(Submit),窗口的「滾動」(Scrolling)等等;而對象的事件就能響應發生在對象上的事情,例如提交表單產生表單的「提交事件」,點擊連接產生的「點擊事件」。不是所有的對象都有以上三個性質,有些沒有事件,有些只有屬性。引用對象的任一「性質」用「<對象名>.<性質名>」這種方法。
基本對象
現在我們要復習以上學過的內容了——把一些數據類型用對象的角度重新學習一下。
Number 「數字」對象。這個對象用得很少,作者就一次也沒有見過。不過屬於「Number」的對象,也就是「變數」就多了。
屬性
MAX_VALUE 用法:Number.MAX_VALUE;返回「最大值」。
MIN_VALUE 用法:Number.MIN_VALUE;返回「最小值」。
NaN 用法:Number.NaN 或 NaN;返回「NaN」。「NaN」(不是數值)在很早就介紹過了。
NEGATIVE_INFINITY 用法:Number.NEGATIVE_INFINITY;返回:負無窮大,比「最小值」還小的值。
POSITIVE_INFINITY 用法:Number.POSITIVE_INFINITY;返回:正無窮大,比「最大值」還大的值。
方法
toString() 用法:<數值變數>.toString();返回:字元串形式的數值。如:若 a == 123;則 a.toString() == '123'。
String 字元串對象。聲明一個字元串對象最簡單、快捷、有效、常用的方法就是直接賦值。
屬性
length 用法:<字元串對象>.length;返回該字元串的長度。
方法
charAt() 用法:<字元串對象>.charAt(<位置>);返回該字元串位於第<位置>位的單個字元。注意:字元串中的一個字元是第 0 位的,第二個才是第 1 位的,最後一個字元是第 length - 1 位的。
charCodeAt() 用法:<字元串對象>.charCodeAt(<位置>);返回該字元串位於第<位置>位的單個字元的 ASCII 碼。
fromCharCode() 用法:String.fromCharCode(a, b, c...);返回一個字元串,該字元串每個字元的 ASCII 碼由 a, b, c... 等來確定。
indexOf() 用法:<字元串對象>.indexOf(<另一個字元串對象>[, <起始位置>]);該方法從<字元串對象>中查找<另一個字元串對象>(如果給出<起始位置>就忽略之前的位置),如果找到了,就返回它的位置,沒有找到就返回「-1」。所有的「位置」都是從零開始的。
lastIndexOf() 用法:<字元串對象>.lastIndexOf(<另一個字元串對象>[, <起始位置>]);跟 indexOf() 相似,不過是從後邊開始找。
split() 用法:<字元串對象>.split(<分隔符字元>);返回一個數組,該數組是從<字元串對象>中分離開來的,<分隔符字元>決定了分離的地方,它本身不會包含在所返回的數組中。例如:'1&2&345&678'.split('&')返回數組:1,2,345,678。關於數組,我們等一下就討論。
substring() 用法:<字元串對象>.substring(<始>[, <終>]);返回原字元串的子字元串,該字元串是原字元串從<始>位置到<終>位置的前一位置的一段。<終> - <始> = 返回字元串的長度(length)。如果沒有指定<終>或指定得超過字元串長度,則子字元串從<始>位置一直取到原字元串尾。如果所指定的位置不能返回字元串,則返回空字元串。
substr() 用法:<字元串對象>.substr(<始>[, <長>]);返回原字元串的子字元串,該字元串是原字元串從<始>位置開始,長度為<長>的一段。如果沒有指定<長>或指定得超過字元串長度,則子字元串從<始>位置一直取到原字元串尾。如果所指定的位置不能返回字元串,則返回空字元串。
toLowerCase() 用法:<字元串對象>.toLowerCase();返回把原字元串所有大寫字母都變成小寫的字元串。
toUpperCase() 用法:<字元串對象>.toUpperCase();返回把原字元串所有小寫字母都變成大寫的字元串。
Array 數組對象。數組對象是一個對象的集合,里邊的對象可以是不同類型的。數組的每一個成員對象都有一個「下標」,用來表示它在數組中的位置(既然是「位置」,就也是從零開始的啦)。
數組的定義方法:
var <數組名> = new Array();
這樣就定義了一個空數組。以後要添加數組元素,就用:
<數組名>[<下標>] = ...;
注意這里的方括弧不是「可以省略」的意思,數組的下標表示方法就是用方括弧括起來。
如果想在定義數組的時候直接初始化數據,請用:
var <數組名> = new Array(<元素1>, <元素2>, <元素3>...);
例如,var myArray = new Array(1, 4.5, 'Hi'); 定義了一個數組 myArray,里邊的元素是:myArray[0] == 1; myArray[1] == 4.5; myArray[2] == 'Hi'。
但是,如果元素列表中只有一個元素,而這個元素又是一個正整數的話,這將定義一個包含<正整數>個空元素的數組。
注意:JavaScript只有一維數組!千萬不要用「Array(3,4)」這種愚蠢的方法來定義 4 x 5 的二維數組,或者用「myArray[2,3]」這種方法來返回「二維數組」中的元素。任意「myArray[...,3]」這種形式的調用其實只返回了「myArray[3]」。要使用多維數組,請用這種虛擬法:
var myArray = new Array(new Array(), new Array(), new Array(), ...);
其實這是一個一維數組,里邊的每一個元素又是一個數組。調用這個「二維數組」的元素時:myArray[2][3] = ...;
屬性
length 用法:<數組對象>.length;返回:數組的長度,即數組里有多少個元素。它等於數組里最後一個元素的下標加一。所以,想添加一個元素,只需要:myArray[myArray.length] = ...。
方法
join() 用法:<數組對象>.join(<分隔符>);返回一個字元串,該字元串把數組中的各個元素串起來,用<分隔符>置於元素與元素之間。這個方法不影響數組原本的內容。
reverse() 用法:<數組對象>.reverse();使數組中的元素順序反過來。如果對數組[1, 2, 3]使用這個方法,它將使數組變成:[3, 2, 1]。
slice() 用法:<數組對象>.slice(<始>[, <終>]);返回一個數組,該數組是原數組的子集,始於<始>,終於<終>。如果不給出<終>,則子集一直取到原數組的結尾。
sort() 用法:<數組對象>.sort([<方法函數>]);使數組中的元素按照一定的順序排列。如果不指定<方法函數>,則按字母順序排列。在這種情況下,80 是比 9 排得前的。如果指定<方法函數>,則按<方法函數>所指定的排序方法排序。<方法函數>比較難講述,這里只將一些有用的<方法函數>介紹給大家。
按升序排列數字:
function sortMethod(a, b) {
return a - b;
}
myArray.sort(sortMethod);
按降序排列數字:把上面的「a - b」該成「b - a」。
有關函數,請看下面。
Math 「數學」對象,提供對數據的數學計算。下面所提到的屬性和方法,不再詳細說明「用法」,大家在使用的時候記住用「Math.<名>」這種格式。
屬性
E 返回常數 e (2.718281828...)。
LN2 返回 2 的自然對數 (ln 2)。
LN10 返回 10 的自然對數 (ln 10)。
LOG2E 返回以 2 為低的 e 的對數 (log2e)。
LOG10E 返回以 10 為低的 e 的對數 (log10e)。
PI 返回π(3.1415926535...)。
SQRT1_2 返回 1/2 的平方根。
SQRT2 返回 2 的平方根。
方法
abs(x) 返回 x 的絕對值。
acos(x) 返回 x 的反餘弦值(餘弦值等於 x 的角度),用弧度表示。
asin(x) 返回 x 的反正弦值。
atan(x) 返回 x 的反正切值。
atan2(x, y) 返回復平面內點(x, y)對應的復數的幅角,用弧度表示,其值在 -π 到 π 之間。
ceil(x) 返回大於等於 x 的最小整數。
cos(x) 返回 x 的餘弦。
exp(x) 返回 e 的 x 次冪 (ex)。
floor(x) 返回小於等於 x 的最大整數。
log(x) 返回 x 的自然對數 (ln x)。
max(a, b) 返回 a, b 中較大的數。
min(a, b) 返回 a, b 中較小的數。
pow(n, m) 返回 n 的 m 次冪 (nm)。
random() 返回大於 0 小於 1 的一個隨機數。
round(x) 返回 x 四捨五入後的值。
sin(x) 返回 x 的正弦。
sqrt(x) 返回 x 的平方根。
tan(x) 返回 x 的正切。
Date 日期對象。這個對象可以儲存任意一個日期,從 0001 年到 9999 年,並且可以精確到毫秒數(1/1000 秒)。在內部,日期對象是一個整數,它是從 1970 年 1 月 1 日零時正開始計算到日期對象所指的日期的毫秒數。如果所指日期比 1970 年早,則它是一個負數。所有日期時間,如果不指定時區,都採用「UTC」(世界時)時區,它與「GMT」(格林威治時間)在數值上是一樣的。
定義一個日期對象:
var d = new Date;
這個方法使 d 成為日期對象,並且已有初始值:當前時間。如果要自定初始值,可以用:
var d = new Date(99, 10, 1); //99 年 10 月 1 日
var d = new Date('Oct 1, 1999'); //99 年 10 月 1 日
等等方法。最好的方法就是用下面介紹的「方法」來嚴格的定義時間。
方法
以下有很多「g/set[UTC]XXX」這樣的方法,它表示既有「getXXX」方法,又有「setXXX」方法。「get」是獲得某個數值,而「set」是設定某個數值。如果帶有「UTC」字母,則表示獲得/設定的數值是基於 UTC 時間的,沒有則表示基於本地時間或瀏覽期默認時間的。
如無說明,方法的使用格式為:「<對象>.<方法>」,下同。
g/set[UTC]FullYear() 返回/設置年份,用四位數表示。如果使用「x.set[UTC]FullYear(99)」,則年份被設定為 0099 年。
g/set[UTC]Year()返回/設置年份,用兩位數表示。設定的時候瀏覽器自動加上「19」開頭,故使用「x.set[UTC]Year(00)」把年份設定為 1900 年。
g/set[UTC]Month()返回/設置月份。
g/set[UTC]Date()返回/設置日期。
g/set[UTC]Day()返回/設置星期,0 表示星期天。
g/set[UTC]Hours()返回/設置小時數,24小時制。
g/set[UTC]Minutes()返回/設置分鍾數。
g/set[UTC]Seconds()返回/設置秒鍾數。
g/set[UTC]Milliseconds()返回/設置毫秒數。
g/setTime() 返回/設置時間,該時間就是日期對象的內部處理方法:從 1970 年 1 月 1 日零時正開始計算到日期對象所指的日期的毫秒數。如果要使某日期對象所指的時間推遲 1 小時,就用:「x.setTime(x.getTime() + 60 * 60 * 1000);」(一小時 60 分,一分 60 秒,一秒 1000 毫秒)。
getTimezoneOffset() 返回日期對象採用的時區與格林威治時間所差的分鍾數。在格林威治東方的市區,該值為負,例如:中國時區(GMT+0800)返回「-480」。
toString() 返回一個字元串,描述日期對象所指的日期。這個字元串的格式類似於:「Fri Jul 21 15:43:46 UTC+0800 2000」。
toLocaleString() 返回一個字元串,描述日期對象所指的日期,用本地時間表示格式。如:「2000-07-21 15:43:46」。
toGMTString() 返回一個字元串,描述日期對象所指的日期,用 GMT 格式。
toUTCString() 返回一個字元串,描述日期對象所指的日期,用 UTC 格式。
parse() 用法:Date.parse(<日期對象>);返回該日期對象的內部表達方式。
全局對象
全局對象從不現形,它可以說是虛擬出來的,目的在於把全局函數「對象化」。在 Microsoft JScript 語言參考中,它叫做「Global 對象」,但是引用它的方法和屬性從來不用「Global.xxx」(況且這樣做會出錯),而直接用「xxx」。
屬性
NaN 一早就說過了。
方法
eval() 把括弧內的字元串當作標准語句或表達式來運行。
isFinite() 如果括弧內的數字是「有限」的(介於 Number.MIN_VALUE 和 Number.MAX_VALUE 之間)就返回 true;否則返回 false。
isNaN() 如果括弧內的值是「NaN」則返回 true 否則返回 false。
parseInt() 返回把括弧內的內容轉換成整數之後的值。如果括弧內是字元串,則字元串開頭的數字部分被轉換成整數,如果以字母開頭,則返回「NaN」。
parseFloat() 返回把括弧內的字元串轉換成浮點數之後的值,字元串開頭的數字部分被轉換成浮點數,如果以字母開頭,則返回「NaN」。
toString() 用法:<對象>.toString();把對象轉換成字元串。如果在括弧中指定一個數值,則轉換過程中所有數值轉換成特定進制。
escape() 返回括弧中的字元串經過編碼後的新字元串。該編碼應用於 URL,也就是把空格寫成「%20」這種格式。「+」不被編碼,如果要「+」也被編碼,請用:escape('...', 1)。
unescape() 是 escape() 的反過程。解編括弧中字元串成為一般字元串。
函數函數的定義
所謂「函數」,是有返回值的對象或對象的方法。
函數的種類
常見的函數有:構造函數,如 Array(),能構造一個數組;全局函數,即全局對象里的方法;自定義函數;等等。
自定義函數
定義函數用以下語句:
function 函數名([參數集]) {
...
[return[ <值>];]
...
}
其中,用在 function 之後和函數結尾的大括弧是不能省去的,就算整個函數只有一句。
函數名與變數名有一樣的起名規定,也就是只包含字母數字下劃線、字母排頭、不能與保留字重復等。
參數集可有可無,但括弧就一定要有。
參數 是函數外部向函數內部傳遞信息的橋梁,例如,想叫一個函數返回 3 的立方,你就要讓函數知道「3」這個數值,這時候就要有一個變數來接收數值,這種變數叫做參數。
參數集是一個或多個用逗號分隔開來的參數的集合,如:a, b, c。
函數的內部有一至多行語句,這些語句並不會立即執行,而只當有其它程序調用它時才執行。這些語句中可能包含「return」語句。在執行一個函數的時候,碰到 return 語句,函數立刻停止執行,並返回到調用它的程序中。如果「return」後帶有<值>,則退出函數的同時返回該值。
在函數的內部,參數可以直接當作變數來使用,並可以用 var 語句來新建一些變數,但是這些變數都不能被函數外部的過程調用。要使函數內部的信息能被外部調用,要麼使用「return」返回值,要麼使用全局變數。
全局變數 在 Script 的「根部」(非函數內部)的「var」語句所定義的變數就是全局變數,它能在整個過程的任意地方被調用、更改。
例
function addAll(a, b, c) {
return a + b + c;
}
var total = addAll(3, 4, 5);
這個例子建立了一個叫「addAll」的函數,它有 3 個參數:a, b, c,作用是返回三個數相加的結果。在函數外部,利用「var total = addAll(3, 4, 5);」接收函數的返回值。
更多的時候,函數是沒有返回值的,這種函數在一些比較強調嚴格的語言中是叫做「過程」的,例如 Basic 類語言的「Sub」、Pascal 語言的「procere」。
屬性
arguments 一個數組,反映外部程序調用函數時指定的參數。用法:直接在函數內部調用「arguments」。