1. 程式人生 > >JavaScript高級程序設計學習(四)之引用類型(續)

JavaScript高級程序設計學習(四)之引用類型(續)

dso 也有 特殊字符 src sin define 訪問 ast 編碼

一、Date類型

其實引用類型和相關的操作方法,遠遠不止昨天的所說的那些,還有一部分今天繼續補充。

在java中日期Date,它所屬的包有sql包,也有util包。我個人比較喜歡用util包的。理由,順手習慣,個人也覺得比較好用。sql的Date類用的不算多。也用過。

下面就進入正題吧,不單單在java,在js中也存在日期函數,或換言之,日期對象。

var now = new Date();

通過now.getYear(),now.getMonth(),now.getMonth(),簡單的翻譯,可以理解為獲得當前的年月日。

now翻譯過來表示現在,之所以采取這樣的命名,還是那就話,規範起見。

js獲得的日期,通常情況要麽通過字符串拼接,要麽通過格式轉換,達到自己想要的那樣。

常用的格式轉換方法如下:

? toDateString()——以特定於實現的格式顯示星期幾、月、日和年;

? toTimeString()——以特定於實現的格式顯示時、分、秒和時區;

? toLocaleDateString()——以特定於地區的格式顯示星期幾、月、日和年;

? toLocaleTimeString()——以特定於實現的格式顯示時、分、秒;

? toUTCString()——以特定於實現的格式完整的 UTC日期。 與 toLocaleString()和 toString()方法一樣,以上這些字符串格式方法的輸出也是因瀏覽器 而異的,因此沒有哪一個方法能夠用來在用戶界面中顯示一致的日期信息;

日期和時間組件方法如下(大家可以參考):

getTime() 返回表示日期的毫秒數;與valueOf()方法返回的值相同 setTime(毫秒) 以毫秒數設置日期,會改變整個日期

getFullYear() 取得4位數的年份(如2007而非僅07)

getUTCFullYear() 返回UTC日期的4位數年份 setFullYear(年) 設置日期的年份。傳入的年份值必須是4位數字(如2007而非僅07)

setUTCFullYear(年) 設置UTC日期的年份。傳入的年份值必須是4位數字(如2007而非僅07)

getMonth() 返回日期中的月份,其中0表示一月,11表示十二月 getUTCMonth() 返回UTC日期中的月份,其中0表示一月,11表示十二月

setMonth(月) 設置日期的月份。傳入的月份值必須大於0,超過11則增加年份

setUTCMonth(月) 設置UTC日期的月份。傳入的月份值必須大於0,超過11則增加年份 getDate() 返回日期月份中的天數(1到31)

getUTCDate() 返回UTC日期月份中的天數(1到31)

setDate(日) 設置日期月份中的天數。如果傳入的值超過了該月中應有的天數,則增加月份

setUTCDate(日) 設置UTC日期月份中的天數。如果傳入的值超過了該月中應有的天數,則增加月份

getDay() 返回日期中星期的星期幾(其中0表示星期日,6表示星期六) getUTCDay() 返回UTC日期中星期的星期幾(其中0表示星期日,6表示星期六)

getHours() 返回日期中的小時數(0到23)

getUTCHours() 返回UTC日期中的小時數(0到23) setHours(時) 設置日期中的小時數。傳入的值超過了23則增加月份中的天數

setUTCHours(時) 設置UTC日期中的小時數。傳入的值超過了23則增加月份中的天數

getMinutes() 返回日期中的分鐘數(0到59)

getUTCMinutes() 返回UTC日期中的分鐘數(0到59)

setMinutes(分) 設置日期中的分鐘數。傳入的值超過59則增加小時數

setUTCMinutes(分) 設置UTC日期中的分鐘數。傳入的值超過59則增加小時數

getSeconds() 返回日期中的秒數(0到59)

getUTCSeconds() 返回UTC日期中的秒數(0到59)

setSeconds(秒) 設置日期中的秒數。傳入的值超過了59會增加分鐘數

setUTCSeconds(秒) 設置UTC日期中的秒數。傳入的值超過了59會增加分鐘數

getMilliseconds() 返回日期中的毫秒數

getUTCMilliseconds() 返回UTC日期中的毫秒數

setMilliseconds(毫秒) 設置日期中的毫秒數

二、 RegExp 類型

RegExp,簡單的說,就是正則表達式,正則表達式,在開發中用的也很多,比如表單校驗,手機號碼,郵箱,網關,昵稱,qq號,身份證等,當然在java中也有相關的方法和工具類可以完成驗證,但是那樣的話,全部請求就會走向服務器,那麽對於服務器負載也是很大的。所以這也是js的一大亮點,減少服務器壓力,同時也給用戶比較好的體驗。試問,如果走服務器的話,在過去網絡這玩意,是個新鮮貨,人們那時填寫表單點擊提交,基本都是跑服務器,但是有的時候不小心點錯了或者大意疏忽了,好不容易填完十幾個表單輸入框,最後告知你,有幾個必填項或者幾個不符合要求的項,要求你重新填寫,在那個時候,人們不得不接受,但是在這個用戶量即市場的互聯網時代,可以說用戶就是上帝,如果用戶不滿意相當於自取滅亡。

正則表達式在此就可以發揮作用了,當用戶填寫不合法,直接提示相關文字信息,當必填項沒填寫直接表單被紅框標記,現在的html5表單校驗就是基於正則和一些相關原生js方法,這個我曾經在我開發的博客中用過。挺好用的。

當然,正則表達式的作用遠遠不止這麽點,它可以根據字符匹配,這樣就有個小小的匹配功能,也可以說搜索功能,當然這個搜索肯定是不能和百度那樣的公司比的。這個搜索只不過是字符匹配。

(1)RegExp實例屬性

? global:布爾值,表示是否設置了 g 標誌。

? ignoreCase:布爾值,表示是否設置了 i 標誌。

? lastIndex:整數,表示開始搜索下一個匹配項的字符位置,從 0算起。

? multiline:布爾值,表示是否設置了 m 標誌。

? source:正則表達式的字符串表示,按照字面量形式而非傳入構造函數中的字符串模式返回。

(2)RegExp實例方法

RegExp 對象的主要方法是 exec(),該方法是專門為捕獲組而設計的。exec()接受一個參數,即 要應用模式的字符串,然後返回包含第一個匹配項信息的數組;或者在沒有匹配項的情況下返回 null。 返回的數組雖然是 Array 的實例,但包含兩個額外的屬性:index 和 input。其中,index 表示匹配 項在字符串中的位置,而 input 表示應用正則表達式的字符串。在數組中,第一項是與整個模式匹配 的字符串,其他項是與模式中的捕獲組匹配的字符串(如果模式中沒有捕獲組,則該數組只包含一項)。

var text = "mom and dad and baby"; 
var pattern = /mom( and dad( and baby)?)?/gi; 
 
var matches = pattern.exec(text); 
alert(matches.index);     // 0 
alert(matches.input);   // "mom and dad andbaby" 
alert(matches[0]);        // "mom and dad and baby" 
alert(matches[1]);        // " and dad and baby"
alert(matches[2]);        // " and baby" 
var text = "this has been a short summer";
 var pattern = /(.)hort/g; 
 
/*  * 註意:Opera 不支持 input、lastMatch、lastParen 和 multiline 屬性  * Internet Explorer 不支持 multiline 屬性  */      
   if (pattern.test(text)){  
alert(RegExp.input);            // this has been a short summer  
alert(RegExp.leftContext); // this has been a
alert(RegExp.rightContext); // summer
alert(RegExp.lastMatch); // short
alert(RegExp.lastParen); // s
alert(RegExp.multiline); // false
}

以上代碼創建了一個模式,匹配任何一個字符後跟 hort,而且把第一個字符放在了一個捕獲組中。 RegExp 構造函數的各個屬性返回了下列值: ? input 屬性返回了原始字符串; ? leftContext 屬性返回了單詞 short 之前的字符串,而 rightContext 屬性則返回了 short 之後的字符串; ? lastMatch 屬性返回近一次與整個正則表達式匹配的字符串,即 short; ? lastParen 屬性返回近一次匹配的捕獲組,即例子中的 s。

(3)模式的局限性

盡管 ECMAScript中的正則表達式功能還是比較完備的,但仍然缺少某些語言(特別是 Perl)所支 持的高級正則表達式特性。下面列出了 ECMAScript正則表達式不支持的特性。

? 匹配字符串開始和結尾的\A 和\Z 錨①

? 向後查找(lookbehind)②

? 並集和交集類

? 原子組(atomic grouping)

? Unicode支持(單個字符除外,如\uFFFF)

? 命名的捕獲組③

? s(single,單行)和 x(free-spacing,無間隔)匹配模式

? 條件匹配

? 正則表達式註釋

三、Function

說起來 ECMAScript中什麽有意思,我想那莫過於函數了——而有意思的根源,則在於函數實際 上是對象。每個函數都是 Function 類型的實例,而且都與其他引用類型一樣具有屬性和方法。由於函 數是對象,因此函數名實際上也是一個指向函數對象的指針,不會與某個函數綁定。函數通常是使用函 數聲明語法定義的。

function sum (num1, num2) {     

return num1 + num2; 

}

與下面這個並沒有什麽差異

var sum = function(num1, num2){   
  return num1 + num2; 
}; 
 

以上代碼定義了變量 sum 並將其初始化為一個函數。有讀者可能會註意到,function 關鍵字後面 沒有函數名。這是因為在使用函數表達式定義函數時,沒有必要使用函數名——通過變量 sum 即可以引 用函數。另外,還要註意函數末尾有一個分號,就像聲明其他變量時一樣。

下面示例不推薦使用:

var sum = new Function("num1", "num2", "return num1 + num2"); // 不推薦 
function sum(num1, num2){  
   return num1 + num2; 
} 
alert(sum(10,10));        //20 
 
var anotherSum = sum; 
alert(anotherSum(10,10)); //20 
 
sum = null; 
alert(anotherSum(10,10)); //20 

以上代碼首先定義了一個名為 sum()的函數,用於求兩個值的和。然後,又聲明了變量 anotherSum, 並將其設置為與 sum 相等(將 sum 的值賦給 anotherSum)。註意,使用不帶圓括號的函數名是訪問函 數指針,而非調用函數。此時,anotherSum 和 sum 就都指向了同一個函數,因此 anotherSum()也 可以被調用並返回結果。即使將 sum 設置為 null,讓它與函數“斷絕關系”,但仍然可以正常調用 anotherSum()。

var addSomeNumber = function (num){  
   return num + 100; 
}; 
 
addSomeNumber = function (num) {   
  return num + 200; 
}; 
 
var result = addSomeNumber(100); //300 

通過觀察重寫之後的代碼,很容易看清楚到底是怎麽回事兒——在創建第二個函數時,實際上覆蓋 了引用第一個函數的變量 addSomeNumber。

(1)函數聲明和函數表達式

我們一直沒有對函數聲明和函數表達式加以區別。而實際上,解析器在向執行環 境中加載數據時,對函數聲明和函數表達式並非一視同仁。解析器會率先讀取函數聲明,並使其在執行 任何代碼之前可用(可以訪問);至於函數表達式,則必須等到解析器執行到它所在的代碼行,才會真 正被解釋執行。

示例:

alert(sum(10,10));
function sum(num1, num2){
return num1 + num2;
}

因為在代碼開始執行之前,解析器就已經通過一個名為函數聲明提升 (function declaration hoisting)的過程,讀取並將函數聲明添加到執行環境中。對代碼求值時,JavaScript 引擎在第一遍會聲明函數並將它們放到源代碼樹的頂部。所以,即使聲明函數的代碼在調用它的代碼後 面,JavaScript 引擎也能把函數聲明提升到頂部。

如果像下面例子所示的,把上面的函數聲明改為等價 的函數表達式,就會在執行期間導致錯誤。
示例:

alert(sum(10,10)); 
var sum = function(num1, num2){    
 return num1 + num2;
 }; 

這個就會導致常見js錯誤,函數未定義錯誤。

(2)作為值函數

因為 ECMAScript中的函數名本身就是變量,所以函數也可以作為值來使用。也就是說,不僅可以 像傳遞參數一樣把一個函數傳遞給另一個函數,而且可以將一個函數作為另一個函數的結果返回。

function callSomeFunction(someFunction, someArgument){     

return someFunction(someArgument); 

} 
 

這個函數接受兩個參數。第一個參數應該是一個函數,第二個參數應該是要傳遞給該函數的一個值。 然後,就可以像下面的例子一樣傳遞函數了。

function add10(num){    
return num + 10;
} var result1 = callSomeFunction(add10, 10);
alert(result1); //20 function getGreeting(name){
return "Hello, " + name;
} var result2 = callSomeFunction(getGreeting, "Nicholas");
alert(result2); //"Hello, Nicholas"

這裏的 callSomeFunction()函數是通用的,即無論第一個參數中傳遞進來的是什麽函數,它都 會返回執行第一個參數後的結果。還記得吧,要訪問函數的指針而不執行函數的話,必須去掉函數名後 面的那對圓括號。因此上面例子中傳遞給 callSomeFunction()的是 add10 和 getGreeting,而不 是執行它們之後的結果。

當然,可以從一個函數中返回另一個函數,而且這也是極為有用的一種技術。例如,假設有一個 對象數組,我們想要根據某個對象屬性對數組進行排序。而傳遞給數組 sort()方法的比較函數要接收 兩個參數,即要比較的值。可是,我們需要一種方式來指明按照哪個屬性來排序。要解決這個問題, 可以定義一個函數,它接收一個屬性名,然後根據這個屬性名來創建一個比較函數,下面就是這個函 數的定義。

function createComparisonFunction(propertyName) { 
 
    return function(object1, object2){       
var value1 = object1[propertyName];
var value2 = object2[propertyName]; if (value1
< value2){

return -1;
} else if (value1
> value2){
return 1;
} else {
return 0;
}
};
}

這個函數定義看起來有點復雜,但實際上無非就是在一個函數中嵌套了另一個函數,而且內部函數 前面加了一個 return 操作符。在內部函數接收到 propertyName 參數後,它會使用方括號表示法來 取得給定屬性的值。取得了想要的屬性值之後,定義比較函數就非常簡單了。

var data = [{name: "Zachary", age: 28}, {name: "Nicholas", age: 29}]; 
 
data.sort(createComparisonFunction("name")); alert(data[0].name);  //Nicholas 
 
data.sort(createComparisonFunction("age")); alert(data[0].name);  //Zachary   

這裏,我們創建了一個包含兩個對象的數組 data。其中,每個對象都包含一個 name 屬性和一個 age 屬性。在默認情況下,sort()方法會調用每個對象的 toString()方法以確定它們的次序;但得 到的結果往往並不符合人類的思維習慣。因此,我們調用 createComparisonFunction("name")方 法創建了一個比較函數,以便按照每個對象的 name 屬性值進行排序。而結果排在前面的第一項是 name 為"Nicholas",age 是 29的對象。然後,我們又使用了 createComparisonFunction("age")返回 的比較函數,這次是按照對象的 age 屬性排序。得到的結果是 name 值為"Zachary",age 值是 28的 對象排在了第一位。

(3)函數內部屬性

在函數內部,有兩個特殊的對象:arguments 和 this。其中,arguments 在第 3章曾經介紹過, 它是一個類數組對象,包含著傳入函數中的所有參數。雖然 arguments 的主要用途是保存函數參數, 但這個對象還有一個名叫 callee 的屬性,該屬性是一個指針,指向擁有這個 arguments 對象的函數。 請看下面這個非常經典的階乘函數:

function factorial(num){   
  if (num <=1) { 
        return 1;     
} else {       
  return num * factorial(num-1)  
} 
}  

IE、Firefox、Chrome和 Safari的所有版本以及 Opera 9.6都支持 caller 屬性。 當函數在嚴格模式下運行時,訪問 arguments.callee 會導致錯誤。ECMAScript 5 還定義了 arguments.caller 屬性,但在嚴格模式下訪問它也會導致錯誤,而在非嚴格模式下這個屬性始終是 undefined。定義這個屬性是為了分清 arguments.caller 和函數的 caller 屬性。以上變化都是為 了加強這門語言的安全性,這樣第三方代碼就不能在相同的環境裏窺視其他代碼了。 嚴格模式還有一個限制:不能為函數的 caller 屬性賦值,否則會導致錯誤。

(4)函數屬性和方法

前面曾經提到過,ECMAScript 中的函數是對象,因此函數也有屬性和方法。每個函數都包含兩個 屬性:length 和 prototype。其中,length 屬性表示函數希望接收的命名參數的個數。

如下所示:

function sayName(name){     
alert(name); 
}       
 
function sum(num1, num2){  
   return num1 + num2; 
} 
 
function sayHi(){     
alert("hi"); 
} 
 
alert(sayName.length);      //1 
alert(sum.length);          //2 
alert(sayHi.length);        //0 
 

在 ECMAScript 核心所定義的全部屬性中,耐人尋味的就要數 prototype 屬性了。對於 ECMAScript 中的引用類型而言,prototype 是保存它們所有實例方法的真正所在。換句話說,諸如 toString()和 valueOf()等方法實際上都保存在 prototype 名下,只不過是通過各自對象的實例訪 問罷了。在創建自定義引用類型以及實現繼承時,prototype 屬性的作用是極為重要的。在 ECMAScript 5中,prototype 屬性是不可枚舉的,因此使用 for-in 無法發現。

每個函數都包含兩個非繼承而來的方法:apply()和 call()。這兩個方法的用途都是在特定的作 用域中調用函數,實際上等於設置函數體內 this 對象的值。首先,apply()方法接收兩個參數:一個 是在其中運行函數的作用域,另一個是參數數組。其中,第二個參數可以是 Array 的實例,也可以是 arguments 對象。

function sum(num1, num2){    
 return num1 + num2;
 } 
 
function callSum1(num1, num2){   
  return sum.apply(this, arguments);   
     // 傳入 arguments 對象 
} 
 
function callSum2(num1, num2){    
 return sum.apply(this, [num1, num2]);   
 // 傳入數組 
} 
 
alert(callSum1(10,10));   //20 
alert(callSum2(10,10));   //20 

註意:

在嚴格模式下,未指定環境對象而調用函數,則 this 值不會轉型為 window。 除非明確把函數添加到某個對象或者調用 apply()或 call(),否則 this 值將是 undefined。

四、基本包裝類型

說到包裝類型,在Java中不得不提基本數據類型的包裝類。

在此溫習下

Java基本數據類型及其對應的包裝類

int - Integer

byte - Byte

long - Long

short - Short

char - Char

float - Float

double - Double

boolean - Boolean

在js中包裝類型屬於引用類型,Java同樣如此。

ECMAScript提供了三個包裝類,String,Boolean,Number,分別對應的類型,字符類型,布爾類型,數字類型。

對於包裝類型不做太多講解,學過Java的人容易上手,沒有學過Java的人理解也不存在困難。

這裏講解是包裝類有什麽用,最直接直白的作用就是,類型轉換非常簡單。不需要什麽parseInt,toString,parseFloat等等進行調用轉換方法。直接var b = new String(“1”),即可將其轉為字符串類型。

其他也同理。

String,Boolean,Number我就在此不提太多了。

有一個要提Global,這個要提的原因主要是設計URL編碼和解碼問題,這個在實際應用中非常廣,比如郵件驗證,url加密。

編碼和解碼,可理解為加密和解密的過程,代碼如下:

<html>
<meta charset="utf-8">
<head>
<script>
var uri = "http://www.baidu.com/illegal?userId=1"; 
 

alert(encodeURI(uri)); 
 

alert(encodeURIComponent(uri)); 
</script>
</head>
<body>
</body>
</html>

使用 encodeURI()編碼後的結果是除了空格之外的其他字符都原封不動,只有空格被替換成了 %20。而 encodeURIComponent()方法則會使用對應的編碼替換所有非字母數字字符。這也正是可以 對整個URI使用encodeURI(),而只能對附加在現有URI後面的字符串使用encodeURIComponent() 的原因所在。

與 encodeURI()和 encodeURIComponent()方法對應的兩個方法分別是 decodeURI()和 decodeURIComponent()。其中,decodeURI()只能對使用 encodeURI()替換的字符進行解碼。例如, 它可將%20 替換成一個空格,但不會對%23 作任何處理,因為%23 表示井字號(#),而井字號不是使用 encodeURI()替換的。同樣地,decodeURIComponent()能夠解碼使用 encodeURIComponent()編碼,的所有字符,即它可以解碼任何特殊字符的編碼。

示例如下所示:

<html>
<meta charset="utf-8">
<head>
<script>
var uri = "http%3A%2F%2Fwww.baidu.com%2Fillegal%20value.htm%23start"; 
 

alert(decodeURI(uri)); 

alert(decodeURIComponent(uri)); 
 
</script>
</head>
<body>
</body>
</html>

這裏,變量 uri 包含著一個由 encodeURIComponent()編碼的字符串。在第一次調用 decodeURI() 輸出的結果中,只有%20 被替換成了空格。而在第二次調用 decodeURIComponent()輸出的結果中, 所有特殊字符的編碼都被替換成了原來的字符,得到了一個未經轉義的字符串(但這個字符串並不是一 個有效的 URI)。

註意:

URI方法 encodeURI()、encodeURIComponent()、decodeURI()和 decode- URIComponent()用於替代已經被ECMA-262第3版廢棄的escape()和unescape() 方法。URI方法能夠編碼所有 Unicode字符,而原來的方法只能正確地編碼 ASCII字符。 因此在開發實踐中,特別是在產品級的代碼中,一定要使用URI方法,不要使用 escape() 和unescape()方法。

eval這個方法我常用,主要是將json格式數據解析出來。

另外再提一個Math對象,該對象如其名"數學",主要涉及數學相關的

技術分享圖片

同時還有min和max方法,最小值和最大值

直接var num = Math.max(3,2,1,0)

var num2 = Math.min(1,2,3,4)

就可以得出最大值和最小值。

加入購物車進行計算涉及該方法

? Math.ceil()執行向上舍入,即它總是將數值向上舍入為接近的整數;

? Math.floor()執行向下舍入,即它總是將數值向下舍入為接近的整數;

對象在 JavaScript 中被稱為引用類型的值,而且有一些內置的引用類型可以用來創建特定的對象, 現簡要總結如下:

? 引用類型與傳統面向對象程序設計中的類相似,但實現不同;

? Object 是一個基礎類型,其他所有類型都從 Object 繼承了基本的行為;

? Array 類型是一組值的有序列表,同時還提供了操作和轉換這些值的功能;

? Date 類型提供了有關日期和時間的信息,包括當前日期和時間以及相關的計算功能;

? RegExp 類型是 ECMAScript支持正則表達式的一個接口,提供了基本的和一些高級的正則表 達式功能。 函數實際上是 Function 類型的實例,因此函數也是對象;而這一點正是 JavaScript有特色的地 方。由於函數是對象,所以函數也擁有方法,可以用來增強其行為。 因為有了基本包裝類型,所以 JavaScript 中的基本類型值可以被當作對象來訪問。三種基本包裝類 型分別是:Boolean、Number 和 String。以下是它們共同的特征:

? 每個包裝類型都映射到同名的基本類型;

? 在讀取模式下訪問基本類型值時,就會創建對應的基本包裝類型的一個對象,從而方便了數據 操作;

? 操作基本類型值的語句一經執行完畢,就會立即銷毀新創建的包裝對象。 在所有代碼執行之前,作用域中就已經存在兩個內置對象:Global 和 Math。在大多數ECMAScript 實現中都不能直接訪問 Global 對象;不過,Web 瀏覽器實現了承擔該角色的 window 對象。全局變 量和函數都是 Globa

? Math.round()執行標準舍入,即它總是將數值四舍五入為接近的整數(這也是我們在數學課 上學到的舍入規則)。

繼續昨天沒總結完了,該篇是昨天和今天的內容補充。

JavaScript高級程序設計學習(四)之引用類型(續)