第五章*****************************************************************************************
什么是索引數組: 下標都是數字的數組
關聯數組:
什么是: 可自定義下標名稱的數組
為什么: 為了讓每個元素都有一個專門的名稱
好處: 1. 便于維護;2.快速查找
何時: 1. 希望每個元素都有明確的意義時
? ? ? 2. 快速定位想要的元素時
如何: 2件事(創建、訪問)
創建分2步:
??? 1. 先創建空數組:var arr=[];
??? 2.向空數組中添加新元素,要使用自定義的下標名稱
? ? ? ?EX:ym["name"]="楊冪"
? ? ? ? ? ?ym["math"]=81;
? ? ? ? ? ?ym["chs"]=59;
? ? ? ? ? ?ym["eng"]=89;
訪問: 用法和訪問索引數組完全一樣,同變量的用法,只不過要使用自定義的下標名稱
關聯數組中.length屬性失效,永遠等于0
因為關聯數組中沒有數字下標,length無法+1
遍歷關聯數組(鍵值對的集合): 只能用for( in )
for(var key in arr){? /*in:自動依次取出arr中每個下標名稱保存在變量key中;key:當前房間號:鍵*/
?arr[key]; ? ? ? ? ? ? ? //當前元素值: value,當前屬性名: key
} ? ? ? ? ? ? ? ? ? ? ? ?? /*強調: key不能加引號, 因為每次循環都在變化*/
索引數組:無法提前預知元素的具體位置,只能靠遍歷查找,受元素個數和元素存儲位置影響極大(慢)
關聯數組:直接通過下標定位元素位置,查找速度和元素個數及元素位置無關(快)
關聯數組原理:hash算法: 根據一個字符串,計算出盡量不重復的一個序號。相同的字符串計算出的序號一定相同,相同下標的值會覆蓋原先的值
向關聯數組中保存元素:
? ? 將自定義下標名交給hash算法,計算一個散列的位置序號。將元素保存到序號指定位置
從關聯數組中取值時:
? ? 將自定義下標名交給hash算法,計算出和存入時完全相同的序號,引擎直接去序號位置獲得元素
? ? 優點: 不受存儲位置和元素個數的影響
_______________________________________________________________________________________________
1. 數組API
什么是數組: 存儲多個數據,并提供了操作數據的API的對象
API: 別人已經實現的,咱們用現成的程序
將數組轉字符串有2種:
?String(arr): 將arr中每個元素都轉為字符串,用逗號連接
? ? 何時: 給數組拍照,查看數組的中間修改狀態,判斷操作前后數組是否發生了變化
?arr.join("自定義連接符"): 將arr中每個元素都轉為字符串,用自定義的連接符連接元素
? ? 何時: 只要不希望使用逗號連接符時
固定套路: 1. 把單詞拼接為句子
? ? ? ? ? 2. 無縫拼接:
? ? ? ? ? ?? 錯誤: arr.join() <=> String(arr) ?=>輸出為逗號連接
? ? ? ? ? ?? 正確: arr.join("")
? ? ? ? ? ?? 重要用途: 判斷數組是否為空
? ? ? ? ? 3.動態生成頁面元素(只會在元素之間添加連接符,所以要在arr.join("...")前后補全標簽)
? ? ? ? ? ? ?2步:①?var html="<ANY>"+arr.join("</ANY><ANY>")+"</ANY>";
? ? ? ? ? ? ? ? ? ? 或 var html="<ul>"+uls.join("")+"</ul>";
? ? ? ? ? ? ? ?? ② elem.innerHTML=html;
console.log(String(arr)),console.log(arr),console.dir(arr)
console.log(arr); 先輸出dir的結構,刷新后變為String(arr)
僅輸出內容,不關心結構: console.log(String(arr))
查看數組存儲結構: console.dir(arr) ? ? ? ? ? /*dir查看結果時,不遵循先后執行的順序*/
判斷數組中是否含有某個元素:
數組可用indexOf搜索某個元素的下標,返回在數組中找到的給定元素的第一個索引,若不存在,則返回-1,但數組元素需要完全相等(===)才會搜索成功,且不識別NaN
如: var arr = ['啦啦',2,4];
? ? arr.indexOf('啦');? ? //-1
? ? arr.indexOf('啦啦');? //0
使用ES6的擴展運算符(...)代替cancat,可以更方便的合并數組
如: var arr1 = [1,2,3];
? ? var arr2 = [4,...arr1,5];? ? //[4,1,2,3,5]
toLocaleString()可將數組中的每個元素用逗號(,)隔開,組成字符串(調用join()方法)
var?str = arr.toLocaleString()
_______________________________________________________________________________________________
拼接和選取: 都無權修改原數組,只能返回新數組對象
拼接: 將多個數組或元素,和當前數組拼接為一個新數組
? ? ? 如何:var newArr=arr1.concat(值1,值2,arr2,...);
? ? ? 強調: 1.不修改原數組,只返回新數組
? ? ? ? ? ? 2. 可打散數組類型的參數為單個元素,再拼接 ? ? ? ? ? /*concat獨有*/
? ? ? 注意:?若是大數組會消耗大量內存,可用arr1.push.apply(arr1, arr2)代替,將arr2合并到arr1中
選取: 復制原數組中指定開始位置到結束位置之間的多個元素,組成新數組———原數組保持不變
? ? ? 如何:var subArr=arr.slice(starti,endi+1);
? ? ? 強調: 1.不修改原數組,僅復制出想要的元素組成新數組
? ? ? ? ? ? 2.如果一個API的兩個參數都是下標時,就含頭不含尾
? ? ? 簡寫: 1. 如果參數位置離結尾近,可用負數下標:
? ? ? ? ? ? ?? arr.length-n 可簡寫為:-n(倒數第n個(不包含尾))(API自動加length)
? ? ? ? ? ? 2. 可省略第二個參數(-1),表示一直選取到結尾
? ? ? ? ? ? 3. 兩個參數都可省略: 完整復制一個數組(地址值不同)
_______________________________________________________________________________________________
兩個對象作比較(arr2==arr1):
不做任何轉換,直接比較兩個對象的地址值,用于判斷兩個變量是否引用同一個對象
引用類型的對象(arr2=arr1):用新變量修改對象,等效于直接修改原對象,新舊變量都受影響(地址值相同)
復制數組(地址值不同):①選取復制: var arr2=arr1.slice();
? ? ? ? ? ? ? ? ? ? ? ②復制索引數組:for(var?i=0;i<arr2.length;i++){arr2[i]=arr1[i]};
? ? ? ? ? ? ? ? ? ? ? ③復制關聯數組:for(var key in arr1){key; arr2[key]=arr1[key]};
_______________________________________________________________________________________________
修改數組: splice(強調: 直接修改原數組)
刪除元素:arr.splice(starti,n)
? 刪除starti位置開始的n個元素
? 強調: 不必考慮含頭不含尾(n是個數)
? 其實有返回值: 返回被刪除的元素組成的臨時數組
? ??var deletes=arr.splice(starti,n);? ? ? ? ? ? /*deletes保存了刪除的元素*/
? 簡寫: 1. 支持負數下標,表示倒數第n個(自動用length-n)
? ? ? ? 2. 省略n(從starti 刪到結尾)
插入新元素:arr.splice(starti,0,值1,值2,...)? ? ? ?//刪除0個
? ? 在starti位置插入新的值1,值2,...
? ? 強調: 1.原starti位置的值及其之后的值被向后順移
? ? ? ? ? 2.不支持打散數組類型參數(如果插入一個數組,將變成二維數組)
替換:?arr.splice(starti,n,值1,值2,...)
? ? 先刪除舊的,再在同一位置插入新的
? ? 先刪除starti開始的n個元素,再在starti位置插入值1,值2,...
? ? 強調: 刪除的個數和插入的個數不必相同
翻轉: ?arr.reverse();
_______________________________________________________________________________________________
排序:
什么是: 將數組中的元素按從小到大或從大到小的順序重新排列
何時: 任何數據在給用戶展示前,必須先排序
如何:arr.sort(); ? ? ? ? ? ? /*將 arr 數組按字符串升序,直接修改原數組*/
? 原理: 將所有元素都轉為字符串,再按字符串升序排列
? 何時: 只有按字符串升序排列時,才用默認的sort()
問題: 只能按字符串升序排列
解決:自定義比較器函數:
? 什么是: 專門比較任意兩值大小的函數
? 何時: 如果sort默認的排序規則不是想要的,可自定義比較器代替sort中默認的排序規則
要求: 2個參數: a,b
返回值: 如果a>b,就返回正數
? ? ? ? 如果a<b,就返回負數
? ? ? ? 否則返回0
最簡單的數字升序比較器
function cmp(a,b){return a-b;}; ? ? ? /*定義比較器函數*/
arr.sort(cmp); ? ? ? ? ? ? ? ? ? ? ? ?/*傳入sort()中*/
簡化為:arr.sort(function(a,b){return a-b});? ?/*cmp=function(a,b){return a-b;}*/
? ? ? ? ? ? ? /* 對對象的值進行排序: arr.sort(function(a,b){ return obj[a]-obj[a] }) */
如何使用: 將比較器函數對象作為參數傳入sort()函數中
強調:不加()? ? ? ? ? ? ?/*cmp: 回調函數callback,不加()*/
回調函數:自己定義的函數,自己不調用,不只調用一次,而是傳入另一個函數中,被另一個函數反復調用
何時: 只要對數字元素排序,都要自定義比較器函數
遞歸調用:函數內又調用了自己(效率極低,幾乎所有的遞歸都可用循環代替)
問題2: 如何降序:
解決: 只要顛倒比較器結果的正負號,就可改升序為降序
最簡單的數字降序比較器
function cmp(a,b){return b-a};
arr.sort(cmp);
簡化為: arr.sort(function(a,b){return b-a});
_______________________________________________________________________________________________
2. 棧和隊列
說明: js中沒有專門的棧和隊列結構,都是用普通數組模擬的
棧stack:
什么是棧: 一端封閉,只能從另一端進出的數組
? ? ? ? ? 棧是限定僅在表頭/表尾進行插入/刪除操作的線性表
何時: 只要希望始終使用最后進入數組的新元素時(先進后出)
如何:
? 1. 結尾出入棧:
????結尾入棧: arr.push(值)<=> ?arr[arr.length]=值?? /*在末尾追加一個新值*/
? ?? 強調: 1. 其實push可壓入多個值: arr.push(值1, 值2)
? ? ? ? ?? 2. 不支持打散數組參數 ? ? ? ? ? ? ? ? ? ? //可用來創建二維數組
????結尾出棧: var last=arr.pop();? ? ? ? ? ? ? ? ? ?/*移出數組末尾的最后一個元素*/
? 2. 開頭出入棧:
????開頭入棧: arr.unshift(值)? ? ? ? ? ? ? ? ? ? ? ? /*在開頭插入一個值*/
? ?? 強調: 開頭入棧后的元素順序和結尾入棧后的元素順序是相反的
????開頭出棧: var first=arr.shift();? ? ? ? ? ? ? ?/*移出數組開頭的第一個元素*/
隊列queue:
什么是: 只能從結尾進入,從開頭出的數組,是事件循環(Event Loop)的基礎結構
何時: 只要希望按照先來后到的順序使用數組元素時
如何: 1. 從結尾入隊列:arr.push(值);
? ? ? 2. 從開頭出隊列:var first=arr.shift();
堆:
堆數據結構是一種樹狀結構,它使用key-value的形式存儲,是無序的
變量的存放:
基本數據類型:?保存在棧內存中,占有固定大小的空間,通過按值來訪問
引用類型:?保存在堆內存中,因為值的大小不固定,所以不能保存到棧內存中,但內存地址大小是固定的,可以保存在棧內存中。當查詢引用類型的變量時,先從棧中讀取內存地址,然后通過內存地址找到堆中的值,一般叫做按引用訪問
_______________________________________________________________________________________________
總結: 向數組中添加元素4種:
1. concat():①不修改原數組,返回新數組
? ? ? ? ? ?? ②在結尾拼接元素
? ? ? ? ? ?? ③支持打散數組類型參數,另一個是.apply(),只有這兩個能打散數組
2. splice():①直接修改原數組
? ? ? ? ? ?? ②在任意位置插入新元素
? ? ? ? ? ?? ③不支持打散數組類型參數
3. push():①直接修改原數組
? ? ? ? ?? ②只能在結尾拼接元素
? ? ? ? ?? ③不支持打散數組類型參數
4. shift():①直接修改原數組
? ? ? ? ? ? ②只能在開頭拼接元素
? ? ? ? ? ? ③不支持打散數組類型參數
取出數組元素: 4種:
1. slice():①可獲取任意位置的任意個元素
? ? ? ? ? ? ②不修改原數組,返回選中的元素組成的新數組
2. splice():①刪除任意位置的任意個元素
? ? ? ? ? ?? ②直接修改原數組
? ? ? ? ? ?? ③返回被刪除的元素組成的新數組
3. pop():只能從結尾刪除一個元素,并返回
4. shift():只能從開頭刪除一個元素,并返回
_______________________________________________________________________________________________
3.二維數組
什么是: 數組中的元素,又引用了另一個子數組
何時:
? 1. 保存橫行豎列的二維數據
? 2. 一個大的數組中,還需要對元素進行更細致分類
如何創建: 2種:
1. 先創建空數組,再添加子數組:
var arr=[];
? arr[0]=[0,0,0,0];
? arr[1]=[0,0,0,0];
? ...
2. 創建數組同時,初始化子數組
var arr=[
? [0,0,0,0],
? ... ,
? [0,0,0,0]
];
訪問:arr[r][c](r行號,c列號)? 用法和普通數組的元素及變量完全一樣
越界: 二維數組的行下標r,不能越界,越界報錯
遍歷二維數組:
for(var r=0;r<data.length;r++){ ? ? ? ? //外層循環控制行
? for(var c=0;c<data[r].length;c++){ ? ?//內層循環控制列
? ? data[r][c] ? ? ? ? ? ? ? ? ? ? ? ?? //獲得當前元素
}?}
創建二維數組:
var arr=[];
for (var i=0;i<N;i++ ){
? arr[i]=[]; ? ? ? ? ? ? ? ?//創建一個二維數組,內容為空
? for (var j=0;j<M;j++){? ? //為二維數組賦值 或填充n個空元素: arr1[i]=new Array(n);
? arr[i][j]=0;
} }
冒泡排序算法(一維數組):
function bubblesort(arr){
? for(varr=1;r<arr.length;r++){ ? ? ? ? //外層循環控制輪數
? ? for(vari=0;i<arr.length-r;i++){ ? ? //內層循環控制每輪中的比較次數
? ? ? if(arr[i]>arr[i+1]){ ? ? ? ? ? ? ? //如果i位置的值>i+1位置的值
? ? ? ? arr[i]^=arr[i+1]; ? ? ? ? ? ? ? ?//交換兩位置的值
? ? ? ? arr[i+1]^=arr[i];
? ? ? ? arr[i]^=arr[i+1];
} } } }
第六章*****************************************************************************************
三、String類型
什么是: 由多個字符組成的"只讀"字符數組
String API: 強調: 所有String API都無權修改原字符串,只能返回新字符串
VS 數組: 相同:?1. 下標;如:str[1] ? ?2. .length
? ? ? ? ? ?? 3.var subArr=arr.slice(starti,endi+1);(選取,無權修改原數組)
? ? ? ?? 不同: 類型不同, API不通用
內置對象: ES標準中規定的,瀏覽器廠商已經實現的對象
包括11個:
? String? Number? Boolean? ————— ?這3個是包裝類型
? Array ? Date ? ?Math ? RegExp
? Error
? Function ?Object
? Global (在瀏覽器中被window代替)
包裝類型
什么是:專門包裝原始類型的值,并提供操作原始類型值的API
為什么: 原始類型的值本身不具有任何功能,才需要包裝類型對象的幫助,完成功能
何時: 一般不必手動使用
? ? ? 只要試圖用原始類型的值調用函數時,都會自動創建包裝類型的對象,調用對象的函數執行操作
注意: 只要引用了字符串的屬性(.屬性),字符串就會通過調用new String(str)的方式轉換成對象,這個對象繼承了字符串的方法,并被用來處理屬性的引用,一旦屬性引用結束,這個新創建的對象就會銷毀(實質上并不一定創建和銷毀,但整個過程看起來是這樣的)
比如: n.toFixed(2) => ?typeof n => ?number
? ? ? <=>new Number(n).toFixed(2)
?? str.charCodeAt() =>typeof str =>string
?? <=>new String(str).charCodeAt()
大小寫轉換
將字符串中所有字母,統一轉為大寫或小寫
str.toLowerCase() ? ? ? ?? 轉小寫
str.toUpperCase() ? ? ? ?? 轉大寫
何時: 不區分大小時,都要先轉為一致的大小寫,再比較或判斷:?驗證碼,用戶名,電子郵件
獲得指定位置的字符:?str.charAt(i)? =>? str[i]
獲得指定位置字符的unicode號:?str.charCodeAt(i) ? ? ?? 獲得str中i位置的字符的unicode號
將unicode號,反向轉回文字: ? String.fromCharCode(unicode號) ?? 一次只能轉一個字,要用循環
獲取子字符串:3種
str.slice(starti, endi+1)
str.substring(starti, endi+1) ?? 用法同slice,但不支持負數參數(負數自動轉為0,取較小的值作為開始位置)
str.substr(starti, n)? ? ? ? ? ? ? ? 從starti開始,獲取n個字符,n是個數,省略則到結尾為止
_______________________________________________________________________________________________
查找關鍵詞: 4種:
1. 查找一個固定關鍵詞的位置(僅查找規則內的第一個)
var i=str.indexOf("關鍵詞",fromi)
? 在str中fromi位置之后,查找下一個"關鍵詞"的位置
返回值: 找到的關鍵詞的下標位置i
? ? ? ? 如果沒找到,返回-1
? 簡寫: 省略fromi,默認從0開始
var i=-1;
do{
? i=str.indexOf("關鍵詞",i+1);
? if(i!=-1)
? ? console.log("在位置"+i+"發現關鍵詞");
? else break;
}while(true);
2. 查找最后一個關鍵詞的位置
var i=str.lastIndexOf("關鍵詞");
用于獲取文件的擴展名(取最后一個.后的剩余字符串)
indexOf的問題: 只能查找一個固定關鍵詞的位置
解決: 正則表達式模糊匹配多種關鍵詞
3. 判斷字符串中是否包含符合規則的關鍵詞
var i=str.search(/reg/i) ?? /*reg: 正則表達式,在str中找到第一個符合正則要求的敏感詞的位置*/
返回值: 返回關鍵詞的下標位置i
? ? ? ? 如果沒找到返回-1
? 問題: 正則表達式默認都是區分大小寫的
? 解決:在第二個/后加i,表示忽略(ignore)大小寫
? 何時: 只要僅判斷有沒有關鍵詞時,首選search
? 問題: 1. 只能查找第一個關鍵詞,無法找所有
? ? ? ? 2. 僅返回位置,無法返回關鍵詞內容
4. 查找所有關鍵詞的內容
var kwords=str.match(/reg/ig); ? ? ? ?//也可使用字符串,結果為查找到的字符串
返回值: 返回所有關鍵詞組成的數組
? ? ? ? 如果沒找到,返回null
使用正則時: 數組的第一個元素(下標為0)表示第一個分組,下標為2的是第二個分組
使用/g時: 下標為0的是找到的第0個分組,下標為1的是第一個分組,下標為2的是第二個分組
使用字符串時,下標為0的是找到的字符串,index是下標,input是要查找的字符串
? 問題: 正則表達式默認只匹配第一個符合條件的敏感詞
? 解決:在第二個/后加g,表示查找全部(global)
? 何時: 僅希望獲得關鍵詞內容時
? 問題: 只能獲得內容,無法獲得每個敏感詞的位置
? 解決: 查找每個關鍵詞內容,又查找位置: regExp.exec()
_______________________________________________________________________________________________
替換: 將字符串中找到的關鍵詞,替換為指定的新內容(2種), (無權修改原字符串,只能返回新字符串)
1. 簡單替換: 將所有關鍵詞都替換為同一種新值
str=str.replace(/reg/ig,"新值");
2. 高級替換: 根據每個關鍵詞的不同,動態選擇替換不同的新值
str=str.replace(/reg/ig,function(kw){ ? ? ?/*回調函數,kw 自動獲得本次找到的關鍵詞*/
? return ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*根據不同的kw,動態返回不同的值*/
})
衍生:刪除: 將關鍵詞替換為""
str=str.replace(/reg/ig,"")
str.replace(/(^\s+)|(\s+$)/g, "") ? ? ? ? //去掉字符串首尾的空字符
切割: 按指定關鍵字,將一個字符串切割為多段子字符串(2種)
返回: 返回的是多個子字符串組成的數組,切割后的結果中,不包含分隔符
注意:當分隔符不為空字符("")時,分隔符在邊界或連續出現兩個時,會形成一個空字符
? ? ?分隔符的個數 = str.split("分隔符").length-1? ?//字符串分隔后組成的數組長度-1
1. 簡單: 分隔符是固定的:
var subStrs=str.split("分隔符") ? ? ? ? ? ?//不修改原字符串
2. 復雜: 分隔符不是固定的:
var subStrs=str.split(/reg/i);
固定套路: 將字符串打散為字符數組: var chars=str.split("");
多字符切割: var newStr = oldStr.split(/\:|\./g);
? ? ? ? ? ? var newStr = oldStr.split(/[共]|[注]|[元]/g);
function zhao(str){ ? ? ? ? //查找一個字符串中每個字符連續出現的次數
? var arr1=str.split("");
? arr1.sort(); ? ? ? ? ? ?? //查找一共出現的次數用arr.sort()先排序再查找
? for(var i=0,j=1;i<arr1.length;i++){
? ? if(arr1[i]===arr1[i+1]){
? ? ? j++;
? ? }else{
? ? ? console.log(arr1[i]+":"+j);
? ? ? j=1;
}?}?}
//截取url的后lastNum*2個字段
function getUrlInfo(lastNum){
var infoArr = location.href.split(/\?|\/|\&|\=/g);
? var arr = infoArr.slice(-lastNum*2);
? var result = new Object();
? for(var i=0; i<arr.length; i+=2){
? ? result[arr[i]] = arr[i+1];
? }
? return result;
}
_______________________________________________________________________________________________
正則表達式:Regular Expression
什么是: 規定一個字符串中字符出現規律的規則
何時:2種:?1.模糊查找多種關鍵詞
? ? ? ? ? 2.驗證用戶輸入的格式
如何:
1.最簡單的正則表達式,就是關鍵詞原文本身
2.字符集
什么是: 規定一位字符 備選字符列表 的集合
何時: 只要一位字符,有多種可能備選時
如何:[備選字符列表]? ? ? ? ? ? ? ? ? ? ? ? //?表示選擇其中之一
強調: 中間不要加逗號(,)
? ? ? 一個字符集([])只能規定一位字符的備選字
簡寫: 如果字符列表中 部分備選字符的unicode是連續的,可用-省略中間字符
比如:?[0-9] ? ? ? ? ? ?? 一位數字
? ? ? [a-z] ? ? ? ? ? ?? 一位小寫字母
? ? ? [A-Z] ? ? ? ? ? ?? 一位大寫字母
? ? ? [A-Za-z] ? ? ? ? ? 一位字母
? ? ? [0-9A-Za-z] ? ? ?? 一位字母或數字
? ? ? [\u4e00-\u9fa5] ? ?一位漢字
特殊:[^字符列表] ? ? ?? 除了××
3.預定義字符集
什么是: 對常用特定字符集的更簡化寫法:4個:
? \d ? ? ?? 一位數字 ?=> [0-9]
? \w ? ? ?? 一位字母,數字或_ ?=> [0-9A-Za-z_]
?\s ? ? ? 一位空字符: 空格,Tab...
?.? ? ? ? 通配符(匹配除回車、換行\n\r外的任意字符)
? \D? ? ? ? 類似[^0-9],非數字
? \W? ? ? ? 類似[^0-9A-Za-z_],除\w外的符號
? \S? ? ? ? 非\s的所有內容
\***: 是轉義字符,表示引用符 ? 比如: \. ?匹配點字符 ? \$匹配美元符號
空字符和空字符串不一樣,空字符用|表示
4.量詞
什么是: 規定一位字符集出現次數的規則
何時: 只要規定一位字符集出現的位數/次數
如何: 量詞必須緊跟在修飾的字符集之后,用來修飾相鄰的前一個字符集
包括: 2大類:
? ① 有明確數量邊界的:
? ?? 字符集{n,m} 至少n個,最多m個
? ?? 字符集{n,} ?至少n個,多了不限
? ?? 字符集{n} ? 必須n個
? ② 沒有明確數量邊界的:
? ?? 字符集? ? 可有可無,最多1個
? ?? 字符集* ? 可有可無,多了不限
? ??字符集+? ?至少一個,多了不限
5.選擇和分組
選擇:或
何時: 只要在多個規則中,任選其一匹配時
? 規則1|規則2|規則三...? (只要滿足3個規則之一即可) ?? /*|在正則中,優先級最低*/
分組: 用()將多個規則分為一組
何時: 只要希望一個量詞同時修飾多個字符集時,就要先將多個字符集分為一組(),再用量詞修飾分組
為什么: 默認字符集僅修飾相鄰的前一個字符集
比如: ??var reg=/(\d{2})\/(\d{2})\/(\d{4})/g; ? ?//將'07/29/2017'分為3組
反向引用:
var str = '2017-07-29'.replace(/(\d{4})-(\d{2})-(\d{2})/g, '$2/$3/$1'); ?//str: 07/29/2017
忽略分組: 不希望捕獲某些分組,只需要在分組內加上?:即可
var str = '2017-07-29'.replace(/(?:\d{4})-(\d{2})-(\d{2})/g,'$2/$1'); ? ? //str: 29/07
$1~$9存放著正則表達式中最近的9個正則表達式的提取結果,這些結果按照子匹配的出現順序依次排列
語法: RegExp.$n
這些屬性是靜態的,除了replace中的第二個參數可以省略RegExp外,其它地方使用都要加上RegExp
身份證號: 15位數字? 2位數字? 1位數字或Xx? /*后兩部分,可有可無,最多1次*/
? ? reg = \d{15} ?? (\d\d ? [0-9Xx]) ? ? ?
reg = /(^[1-9]\d{5} ?(18|19|([23]\d))\d{2} ?((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31) ?\d{3}[0-9Xx]$)|(^[1-9]\d{5} ?\d{2} ?((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31) ?\d{2}$)/
手機號: +86或0086 ? ? 可有可無,最多一次
???????? 空格 ? ? ? ? 可有可無,多了不限
???????? 1
???????? 3,4,5,7,8 ?? 選一個
???????? 9位數字
??? (\+86|0086)?\s*1[34578]\d{9}
reg = /^0?(13[0-9]|14[57]|15[012356789]|17[013678]|18[0-9])\d{8}$/
微 信 wei xin w x
? ? (微|w(ei)?)\s*(信|x(in)?)
6.指定匹配位置:3種:
?^字符串開頭,比如: 字符串開頭的空字符:^\s+
?$字符串結尾,比如: 字符串結尾的空字符:\s+$
? ? ? ? ? ? ? ? 比如: 開頭或結尾的空字符:^\s+|\s+$
?\b單詞邊界:包括: ?^$ 空格 標點符號,比如: 查找單詞no,匹配單詞no:?\bno\b
純英文格式電子郵件: var reg = /^[0-9A-Za-z_-]+@[0-9A-Za-z_-]+(\.[0-9A-Za-z_-]+)+$/
銀行卡: 借記卡、儲蓄卡19位, 貸記卡、信用卡16位, 存折17位
? \B?非單詞邊界
var reg = /([a-z])\1*/ig;?? //定義正則表達式變量
var reg =new RegExp("^[a-zA-Z]{9,20}$");
var kw = str.match(reg);? ? //使用此變量時,不需使用斜杠
判斷是否是圖片(帶參數):? /\.(png|jpe?g|gif|svg)(\?.*)?$/.test(str)
判斷是否是視頻(帶參數):? /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/.test(str)
_______________________________________________________________________________________________
/([a-z])\1*/ ? ? ? ?//表示: ?第一位必須是小寫字母,\1表示匹配和第一個()中完全相同的內容
? ? ? ? ? ? ? ? ? ? ? ? ? ?? *表示可有可無,多了不限,就算沒有和它匹配的也選擇它
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?+表示至少一個,多了不限,有一個和它匹配的才選擇它
當 ? 緊跟在任何一個其他限制符(* ?+ ?? ?{n} ?{n,}? {n,m})后面時,匹配模式是非貪婪的,會盡可能少的匹配所搜索的字符串
默認的貪婪模式則盡可能多的匹配所搜索的字符串
? ? 例如: ?對于字符串"oooo","o+"將盡可能多的匹配"o",得到結果 ['oooo'],而 "o+?"?將盡可能少的匹配"o",得到結果 ['o','o','o','o']
m? 多行,將開始和結束字符(^和$)視為在多行上工作,也就是分別匹配每一行的開始和結束(由 \n 或 \r 分割),而不只是只匹配整個輸入字符串的最開始和最末尾處
s? 與m相反,單行匹配
第七章*****************************************************************************************
四、RegExp類型
什么是: 專門封裝一條正則表達式,并提供使用正則表達式執行查找和驗證的API
何時: 1. 使用正則表達式驗證用戶輸入的字符串格式
? ? ? 2. 即查找關鍵詞內容,又查找關鍵詞位置
如何:
創建: 2種
① 直接量(字面量)
var reg=/正則/ig;? ? ? ? ? ?? //i: 忽略(ignore)大小寫;g: 查找全部(global)
何時: 如果正則表達式是固定不變的
強調: //之中不支持js表達式,不支持動態生成正則表達式,如果再出現/,就必須改為\/
②?使用正則表達式的構造函數
var reg=new RegExp("正則","ig");
如: var reg=new RegExp("^[a-zA-Z]","g")? ? ?//使用引號時,不加斜杠
? ? var reg=new RegExp(/^[a-zA-Z]/,"gi")? ? //有斜杠時,不加引號
何時: 如果正則表達式需要動態拼接生成
強調: ""中再出現\或",都要改為\\和\"
API: 2個
① 即查找內容,又查找位置
var arr=reg.exec(str) ? ? ? ? /*在str中依次查找下一個符合reg規則的關鍵詞的內容和位置*/
返回值: 返回一個數組arr: 與正則表達式匹配的文本,后面依次為各個子表達式()的文本,用逗號分隔
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?最后一個arr["input"] 是要查找的內容str
? ? ? ?arr[0]本次找到的關鍵詞的內容
? ? ? ?arr["index"]本次找到的關鍵詞的下標位置
? ? ? ? 如果沒找到,就返回null
問題: 每次只返回本次找到的一個關鍵詞
解決: 用循環反復調用reg.exec
原理: 每次調用exec,做3件事:
? ?? 1. 將本次找到的關鍵詞保存在arr的0位置
? ?? 2. 將本次找到的關鍵詞位置保存在arr的index位置
? ?? 3. 每個reg對象都有一個.lastIndex屬性, 標識下次開始的查找位置,開始時為0
? ? ? ? 每執行完一次exec,exec會自動修改為:?reg.lastIndex=當前位置index+關鍵詞長度
function cha(str){
? var? reg=/./g; ? ? ? ? ? ? ? ? ? ? //在全局查找關鍵詞
? for(var i=0;i<str.length;i++){ ? ? //str.length: 字符串的長度
? ? var arr=reg.exec(str);
? ? console.log(arr[0]); ? ? ? ? ? ? //關鍵詞的內容
? ? console.log(reg.lastIndex-1);? ? //關鍵詞的下標位置
}?}
② 驗證字符串的格式
var bool=reg.test(str);? ? ? ? ? ? ? ?/*驗證str是否符合reg的規則要求*/
驗證通過返回true,不通過返回false,可直接當做判斷條件
問題: test默認只要部分匹配就返回true
解決:從頭到尾完全匹配(驗證),必須在正則表達式中: 前加^,后加$
_______________________________________________________________________________________________
五、Math類型
什么是: 專門保存數學計算的常量和函數的對象 的API
何時: 只要進行數學計算
如何:
創建: Math不用創建,不能new,直接使用
? ?? 所有常量和API都用Math直接調用
API
取整: 3種:
1.上取整: 只要超過,就取下一個整數
Math.ceil(num)
2.下取整: 只要超過,就省略小數部分
Math.floor(num)
Math.floor(num) ? VS ? parseInt(str)
只能對純數字 ? ? ? ? ? 能先去掉數字之后的非數字字符,再取整
3.四舍五入取整
Math.round(num)
Math.round ? ? ? ? ? ? ?? VS ? ? ? ? ?? n.toFixed(d)
缺: 只能取整,不能指定小數位數 ? ? ?? 優: 可指定任意小數位數四舍五入
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?金錢: Number(parseFloat(num).toFixed(2))
優:?將返回number,可直接計算? ? ? ? ? 缺: 將返回字符串類型,需要先轉換為數字類型,再計算
可自定義round函數
4. 乘方和開平方
Math.pow(底數,冪); ?? 乘方
Math.sqrt(n); ? ? ? ? 開平方
5. 最大值和最小值
Math.max(值1,值2,值3,...)
Math.min(值1,值2,值3,...)
問題: max/min不支持獲得數組中的最大/小值,求出數組中的最大/最小值
解決:Math.max.apply(null,arr)? ? ? ? ?/*apply: 調用,可自動打散數組類型參數*/
6. 隨機數
Math.random() ? ? ? ?? 取值: 0~1,默認得到一個隨機小數
公式:在任意[min,max]之間生成一個隨機整數:var r=parseInt(Math.random()*(max-min+1)+min)
簡寫: 如果min=0,即[0, max]之間: var r=parseInt( Math.random()*(max+1) )
例: 隨機數組中的數:var index = parseInt(Math.random()*arr.length)
_______________________________________________________________________________________________
六、Date類型
什么是: 專門封裝一個時間點,并提供操作時間的API
何時: 只要存儲時間或者計算時間
如何:
創建: 4種
1. 創建日期對象,并自動獲得當前系統時間
var now=new Date();//強調: 只能獲得客戶端本地時間,標準格式,即格林尼治標準時(GMT)
2. 創建日期對象,并封裝自定義時間點
var date=new Date("yyyy/MM/dd hh:mm:ss");? /*字符串中的月份為自動-1后的值*/
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? //時間格式也可為: '2017-12-30 21:15:00'
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? //或: 2018-03-06T17:12(部分瀏覽器有時差問題)
部分手機(如iPhone)獲取時間的方式與其它瀏覽器不同,需要兼容處理:
new Date("2017-02-05 12:10:10.12")可能會發生錯誤,函數返回錯誤是"Invalid Date"
var str = "2018-04-13 22:45:00";
var arr = str.split(/[- : \/]/);
var date = new Date(arr[0], arr[1]-1, arr[2], arr[3], arr[4] || '00', arr[5] || '00');
因為iOS不能識別 - 形式,也可以替換為斜杠形式:
date = date.replace(/-/g, '/');? ? // 2018/06/03 00:00:00
若不是字符串: var date=new Date(yyyy, MM-1,dd,hh,mm,ss);
如果只關心日期,不關心時間,后半部分時分秒可省略。省略后,默認是00:00:00
3. 用毫秒數創建日期對象
原理: 日期對象中保存的是1970年1月1日0點至今的毫秒數———整數
為什么: 時間段,不受時區影響
? ? ?? 相同的毫秒數: 在不同時區可顯示不同的時間點
總結: 將來數據庫中保存的時間都是毫秒數,不要用文字
何時: 只要將毫秒數轉化為當地時間格式時
var ms=date.getTime(); ? ? ? ? ? /*將標準格式的date轉化為毫秒數 ms*/
var now=new Date().getTime();? //獲取客戶端1970年1月1日0點至今的毫秒數(縮寫),時間戳
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?//注意時區問題
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?// +new Date()、Date now()? ? 返回毫秒數
var date1=new Date(ms); //將毫秒數?ms 轉化為操作系統當前所在時區的對應時間(必須是Number類型)
4. 復制一個日期對象:
為什么: 日期的計算只能直接修改原日期對象
后果: 計算后,無法保存計算前的原日期
何時: 如果用戶希望同時保留計算前后的開始時間和結束時間時,都要先將開始時間復制一份,再用副本計算結束時間
如何:
var date2=new Date(date1);
_______________________________________________________________________________________________
API: 3句話:
1. 8個單位: FullYear年 ? Month月 ? Date日 ? ? Day星期 ? ? ? ? ? ?———沒有s
? ? ? ? ? ?Hours小時? Minutes分鐘 ?Seconds秒 ?Milliseconds毫秒 ? ———都以s結尾
2. 每個單位都有一對兒getXXX()/setXXX()方法
? ?getXXX()? ?負責獲得指定單位上的數值
??setXXX(n) ?? 負責修改指定單位上的數值,可自動調整時間進制
?? 特例: Day(星期)沒有setXXX()方法
3. 取值范圍:除date(從1開始,31結束)外,其余都是從 0 開始到進制減 1 結束
?? FullYear: ? ? ? ? ? ? ? ? ? 和現實中年份一致
?? Month: 0~11 ? ? ? ? ? ? ?? 現實中: 1~12,計算機中的月份值比現實中少1,需要修正
?? Date: 1~31 ? ? ? ? ? ? ? ? 和現實一樣
?? Day: 0~6 ? ? ? ? ? ? ? ? ? 現實: 日~六,和現實中一致
?? Hours: 0~23 ? ? ? ? ? ? ? ?和現實一樣
?? Minutes/Seconds: 0~59 ? ? ?和現實一樣
_______________________________________________________________________________________________
日期計算
1. 兩日期對象可相減: 結果是毫秒差(ms),可用于倒計時
2. 對任意單位做加減:3步:
? ①取值: var date1=now.getDate();
? ②做加減: date1+=30;
? ? ? ? ? ? ?例如: 16+30=46
? ③放回去: now.setDate(date1); ? ? ? ? ? ?/*setDate可自動調整進制*/
簡寫:now.setDate(now.getDate()+n);
問題: setDate直接修改原日期對象,無法保留開始時間
解決: 在計算前,都要先將開始時間復制一個副本,再用副本計算結束時間
倒計時:
now/=1000, end/=1000;
放在定時器中:
now++;
varT?= parseInt((end-now)/1000);? ? ?//共剩多少時間(單位:秒)
var d = parseInt(T/(3600*24));? ? ? ? //剩多少天
var h = parseInt(T%(3600*24)/3600);? ?//剩多少小時
var m = parseInt(T%(3600)/60);? ? ? ? //剩多少分鐘
var s =T%60;? ? ? ? ? ? ? ? ? ? ? ? ?//剩多少秒
日期格式化(new Date()系統時間,轉字符串)
date.toString() ? ? ? ? ? ? ? 返回當地時間格式的完整版本(系統時間格式)
date.toLocaleString() ? ? ? ? 返回當地時間格式的簡化版本(有時分秒),不同平臺有可能不一樣
date.toLocaleDateString() ? ? 僅保留了日期部分
date.toLocaleTimeString() ? ? 僅保留了時分秒部分
date.toGMTString() ? ? ? ? ? ?獲得 0 時區的國際標準時間
_______________________________________________________________________________________________
new Date($.ajax({async: false}).getResponseHeader("Date")); ? ?//獲取服務器相應頭附帶的時間
輸出客戶端時間:
var weeks=["星期日","星期一","星期二","星期三","星期四","星期五","星期六"];
function fillTime(time){?return time>=10?time:"0"+time;?} ? ?//補全時間
var now = new Date();
var day = now.getDay();
var year ? ?=?now.getFullYear();? ? ? ? ? ? ?//年份
var month ? = fillTime(now.getMonth()+1);? ? //月份
var date ? ?= fillTime(now.getDate());? ? ? ?//日期
var hours ? = fillTime(now.getHours());? ? ? //小時
var minutes = fillTime(now.getMinutes());? ? //分鐘
var seconds = fillTime(now.getSeconds());? ? //秒
var dateTime=year+'-'+month+'-'+date+' '+hours+':'+minutes+':'+seconds+'('+weeks[day]+')';
console.log(dateTime); ? ?//2017-09-02 13:21:06(星期六)
const formatNumber = n =>{
? n = n.toString()
? return n[1] ? n : '0' + n
}
const formatTime = date =>{
? const year = date.getFullYear()
? const month = date.getMonth() + 1
? const day = date.getDate()
? const hour = date.getHours()
? const minute = date.getMinutes()
? const second = date.getSeconds()
? return [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(':')
}
獲取相鄰的一段天數:
var base = +new Date(2018, 1, 1);? ? ? ? //獲取時間的毫秒數
var oneDay = 24 * 3600 * 1000;
for (var i = 0; i < 500; i++){
? var now = new Date(base += oneDay);
? date.push([now.getFullYear(), now.getMonth() + 1, now.getDate()].join('/'));
}
UTC時間和GMT(本地)時間之間的轉換:
GMT轉為UTC:
var now = new Date();
var nowUTC = new Date(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(),
? ? ? ? ? ? ? ? ? ? ? now.getUTCHours(), now.getUTCMinutes(), now.getUTCSeconds());
UTC轉為GMT:
var nowGMT = Date.UTC(nowUTC.getFullYear(), nowUTC.getMonth(), nowUTC.getDate(),
? ? ? ? ? ? ? ? ? ? ? nowUTC.getHours(), nowUTC.getMinutes(), nowUTC.getSeconds());
var now = new Date(nowGMT)
注:?以北京時間為準,UTC總是比GMT小8個小時
常用API***************************************************************************************
Math.atan(n) ? ? ? ? ? ? ? //返回'反正切函數'arctan(n)的值,單位弧度,可轉換為角度
? 例: (Math.atan(a/b))*180/Math.PI
Math.abs(x) ? ? ? ? ? ? ? ?//返回數字的絕對值
? 例: Math.abs(a) || 1;
Math.min(x,y) ? ? ? ? ? ? ?//返回指定的數字中帶有最低值的數字
stringObject.substr(start,length) ?? //從字符串中抽取從start下標開始的指定數目(length)的字符
+str+1 ? ? ? ? ?//+可使字符串變為數字類型再計算
x=Number(x); ? ?//手動將字符串類型的數字轉換成Number類型,不直接修改原變量的值,而是返回新值