引用類型相似於Java中的類,但和傳統的面嚮對象語言所支持的類和接口截然不同,本章介紹ECMAScript提供的原生引用類型。html
引用類型的值通常均被認爲是Object類型的實例,Object類型也是ECMAScript中使用最多的類型。java
建立Object實例的方法有兩種,第一種是使用new操做符後跟Object構造函數:node
var person = new Object(); person.name = "XXX"; person.age="22";
另外一種方式是使用對象字面量表示法:正則表達式
var person = { name: "XXX", age: 22 };
對參數的訪問可使用點表示法,也能夠是用方括號表示法。express
var name = person.name; var age = person["age"];
使用方括號的優勢是方括號中的字符串能夠用變量表示。數組
通常使用點表示法更直觀一些。瀏覽器
hivar value = numbers.reduce(function(prev, cur, index, array){ var res = prev + cur; console.log(prev + " + " + cur + " = " + res); return res; }); console.log("result = " + value); /** 1 + 2 = 3 3 + 3 = 6 6 + 4 = 10 10 + 5 = 15 15 + 6 = 21 21 + 7 = 28 result = 28 */
建立數組的基本方式也有兩種。第一種是使用Array構造函數:app
var colors = new Array(); //建立一個數組
var colors = new Array(3); //建立一個包含三個元素的數組
也能夠想Array構造函數傳遞應該包含的項目dom
var colors = new Array("red", "blue", "green"); //建立一個包含三個元素的數組
以上兩段代碼中的new操做符能夠省略。函數
第二種方法是使用數組字面量表示法。
var colors = ["red", "blue", "green"]; //建立一個包含三個字符串的數組 var names = []; //建立一個空數組 var values =[1, 2, ]; //不要這樣,這樣會差ungjianyige2或3個元素的數組 var options = [,,,,]; //不要這樣,這樣會建立一個5-6個元素的數組
數組的長度存放在數組對象的length屬性中。
var colors = ["red", "blue", "green"]; console.log(colors.length); //3 colors[99] ="black"; console.log(colors.length); //100
檢測一個數組對象是否是數組類型,可使用instanceof操做符,也可使用Array.isArray(value)方法。
Array的toString和toLocalString方法,首先調用各個元素的toString和toLocalString方法,而後用逗號拼接成字符串返回。
使用join方法可使用其餘字符串拼接。
var colors = ["red", "blue", "green"];
console.log(colors.join("||")); //red||blue||green
console.log(colors.join()); //red,blue,green
Array還提供了棧和隊列使用的方法。
棧使用push和pop方法,只在數組末尾進行操做。
隊列使用push和shift方法,在隊尾進隊頭出。隊列還提供了unshift方法,在對頭推入元素。
數組的反序使用reverse方法,將元素倒序排列。
默認狀況是數組排序都是先調用各個元素的toString方法,而後對字符串進行排序。這樣排列數值數組就會出現問題:
var array = [1,2,4,13,25]; var temp = array.sort(); console.log(array); //[ 1, 13, 2, 25, 4 ] console.log(temp); //[ 1, 13, 2, 25, 4 ]
sort方法能夠接收一個比較函數做爲參數,以便咱們指定哪一個值位於哪一個值前面。
var array = [1,2,4,13,25]; array.sort(compare); console.log(array); //[ 1, 2, 4, 13, 25 ] function compare(v1, v2){ return v1 - v2; }
concat方法將參數加入到當前數組,並返回增長後的數組。當前數組內容不變。
var array = [1,2,4,13,25]; var a2 = array.concat([9,4,[6,7,1]]); console.log(a2.length); //8 console.log(array.length); //5 console.log(a2); //[ 1, 2, 4, 13, 25, 9, 4, [ 6, 7, 1 ] ]
slice()方法接收一個或兩個參數,返回子數組,第一個參數表示開始位置,第二個參數表示結束位置。 slice方法不影響原數組。
var array = [1,2,4,13,25]; var subArray = array.slice(2, 4); var subArray2 = array.slice(2); console.log(subArray); //[ 4, 13 ] console.log(subArray2); //[ 4, 13, 25 ]
splice()方法,能夠用來刪除、插入、替換。刪除時,接收兩個參數,第一個參數表示要刪除的位置,第二個參數表示要刪除的項數;插入時接收三個參數:起始位置、要刪除的項數(0)和要插入的項。
var colors = ["red", "blue", "green"]; var removed = colors.splice(0, 1); console.log(colors); //[ 'blue', 'green' ] console.log(removed); //[ 'red' ] removed = colors.splice(1, 0, "yellow", "gray"); console.log(colors); //[ 'blue', 'yellow', 'gray', 'green' ] console.log(removed); //[] removed = colors.splice(1, 1, "red", "pink"); console.log(colors); //[ 'blue', 'red', 'pink', 'gray', 'green' ] console.log(removed); //[ 'yellow' ]
indexOf()方法和ilastIndexOf()方法,都接收兩個參數:要查找的項和表示查找起點位置的索引(可選)。indexOf從頭開始查找,lastIndexOf從末尾開始向前查找。
這兩個方法返回要查找的項在數組中的位置,沒有找到的狀況下返回-1。比較過程當中使用的是全等操做符(===)。
數組的迭代方法有:
var numbers = [1, 2, 3, 4, 5, 6, 7]; var everyResult = numbers.every(function(item, index, array){ return (item > 2); }); console.log(everyResult); //false var someResult = numbers.some(function(item, index, array){ return (item > 2); }); console.log(someResult); //true
var numbers = [1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 1, 2]; var filterResult = numbers.filter(function(item, index, array){ return (item > 2); }); console.log(filterResult); //[ 3, 4, 5, 6, 7, 7, 6, 5, 4 ]
var numbers = [1, 2, 3, 4, 5, 6, 7]; var mapResult = numbers.map(function(item, index, array){ return (item * 2); }); console.log(mapResult); //[ 2, 4, 6, 8, 10, 12, 14 ]
ECMAScript5還提供了兩個歸併數組的方法:reduce()和reduceRight()函數,這兩個函數都會迭代數組中全部的項,而後構建一個最終返回的值。其中reduce()從左向右逐個遍歷,而reduceRight()從右向左逐個遍歷。
兩個方法都接收兩個參數:一個在每一項上調用的函數(四個參數:前一個值、當前值、項的索引和數組對象),另外一個是做爲歸併基礎的初始值(可選)。
函數返回的值會做爲第一個參數自動傳給下一個函數執行,第一次執行的時候,前一個值(第一個參數)是數組第一個元素,當前值(第二個參數)是數組第二個元素。
var numbers = [1, 2, 3, 4, 5, 6, 7]; var value = numbers.reduce(function(prev, cur, index, array){ var res = prev + cur; console.log(prev + " + " + cur + " = " + res); return res; }); console.log("result = " + value); /** 1 + 2 = 3 3 + 3 = 6 6 + 4 = 10 10 + 5 = 15 15 + 6 = 21 21 + 7 = 28 result = 28 */
ECMAScript中的Date類型是在早期Java中的java.util.Date類型的基礎上構建的。爲此,Date類型使用自UTC 1970年1月1日0時開始通過的毫秒數來保存日期。Date類型保存的日期可以精確到1970年1月1日以前或以後的285616年。
建立日期對象可使用new操做符,也能夠用Date.now()返回當前的毫秒數(通常用於判斷一段代碼的執行時間,startTime endTime)。
var date = Date.now(); var date1 = new Date(Date.parse("2016-01-06")); var date2 = new Date(); console.log(date); //1452065871699 console.log(date1); //Wed Jan 06 2016 08:00:00 GMT+0800 (CST) (由於是東8時區因此是8點) console.log(date2); //Wed Jan 06 2016 15:37:51 GMT+0800 (CST)
ECMAScript經過RegExp類型來支持正則表達式。建立正則表達式也有兩種方法,第一種是字面量表達式 var expression = /pattern/ flags; 其中,flag可取的值有三個:
模式中全部的元字符必須轉義。須要轉義的元字符有: ()[]{}\^$|?*+.
第二種建立正則表達式的方法是使用new操做符 var expression = new RegExp(pattern, flag); 。
var re = null, temp = null, i; for(i=0; i <10; i++){ re = /cat/g; temp = re.test("catastrophe"); console.log(temp); //true } temp = re.test("catophetast"); console.log(temp); //false for(i=0; i<10; i++){ re = new RegExp("cat", "g"); temp = re.test("catophetast"); console.log(temp); //true } temp = re.test("catophetast"); console.log(temp); //false
RegExp有下列屬性,用於判斷模式的信息。(這些屬性實際上沒什麼用,由於你聲明的時候已經設置了這些信息)
RegExp實例方法中主要的方法是exec(),該方法是專門爲捕獲組而設計的。exec()接收一個參數,即要應用模式的字符串,而後返回包含第一個匹配項信息的數組;或者在沒有匹配性的時候返回null。
返回的雖然是Array實例,但包含兩個額外的屬性:index和input。其中index表示匹配項在字符串中的位置,而input表示應用正則表達式的字符串。
在數組中,第一項是與整個模式匹配的字符串,其餘項是與模式中的捕獲組匹配的字符串(若是模式中沒有捕獲組,則該數組中只包含一項)。
var text = "grandpa and mom and dad and baby"; var pattern = /mom( and dad( and baby)?)?/gi; var matches = pattern.exec(text); console.log(matches.index); //12 console.log(matches.input); //grandpa and mom and dad and baby console.log(matches); /* [ 'mom and dad and baby', ' and dad and baby', ' and baby', index: 12, input: 'grandpa and mom and dad and baby' ] */
RegExp中第二個方法是test(),它接收一個字符串參數,在模式與該參數匹配的狀況下返回true,不然返回false。通常用於if語句。
var text = "010-6812-0917"; var pattern = /\d{3}-\d{4}/ if(pattern.test(text)){ console.log("The pattern was matched."); //The pattern was matched. }
ECMAScript中的函數其實是對象類型的實例,所以函數名實際上一個指向函數對象的指針,不會與某個函數綁定。所以下面兩個函數聲明的方式很相似。
function sum(num1, num2){ //函數聲明 return num1 + num2; } var sum = function(num1, num2){ //函數表達式 return num1 + num2; }
區別在於解析器會率先讀取函數聲明,並使其在任何代碼以前可用(能夠訪問);至於函數表達式,則必須等到解析器執行到它所在的代碼行,纔會真正被執行。
console.log(sum(5, 6)); //11 function sum(num1, num2){ return num1 + num2; }
console.log(sum(5, 6)); //11 var sum = function(num1, num2){ return num1 + num2; } /* TypeError: undefined is not a function at Object.<anonymous> (/home/zzl/Study/nodejs/studyjs/functionjs.js:1:75) at Module._compile (module.js:456:26) at Object.Module._extensions..js (module.js:474:10) at Module.load (module.js:356:32) at Function.Module._load (module.js:312:12) at Function.Module.runMain (module.js:497:10) at startup (node.js:119:16) at node.js:902:3 */
另外,定義函數還有另外一種方法: var sum = new Function("num1", "num2", "return num1 + num2"); 。這種語法對於理解「函數是對象,函數名是指針」的概念卻是很是直觀,可是不推薦使用這種方式,由於解析器須要解析傳入構造函數中的字符串,最後一個字符串被認爲是函數體,前面的字符串都被認爲是參數。
理解函數名是變量對與js相當重要,由於是變量,因此能夠做爲其餘函數的參數或者返回值返回。
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; } } } var array = [{name:"zhou", age:18},{name:"liu", age:28}]; array.sort(createComparisonFunction("name")); console.log(array[0].name); //liu array.sort(createComparisonFunction("age")); console.log(array[0].name); //zhou
函數做爲一個Function的類型,包含兩個特殊的對象:arguments 和 this。
arguments是一個類數組的對象,包含着全部傳入函數的參數。arguments 還有一個callee屬性,該屬性是一個指針,指向擁有這個arguments對象的函數。該指針對於遞歸調用尤爲重要。
function factorial(num){ if(num <= 1){ return 1; }else{ //return num * factorial(num-1); return num * arguments.callee(num-1); } } temp = factorial; factorial = null; console.log(temp(4)); //24
函數內部另外一個特殊對象是this,其行爲和Java大體相同。也就是說,this引用的是函數據以執行的環境對象。
ECMAScript 5也規範化了另外一個函數對象的屬性:caller。該屬性保存者調用當前函數的函數引用,若是是在全局做用域中調用當前函數,它的值返回null。在caller後加括號就至關於調用了outer函數,馬上會引發棧溢出。
function outer(){ inner(); } function inner(){ console.log(inner.caller; //[Function: outer] console.log(arguments.callee.caller); //[Function: outer] } outer();
在嚴格模式下,caller 和 callee 都是不容許的,由於侵犯到了別的函數的空間。
ECMAScript中函數對象還有length 和 prototype 屬性,其中length屬性表示函數但願接收的函數參數的個數。
對於引用類型而言,prototype屬性是保存他們說有實例方法的所在。也就是說,對象的 toString() valueOf()等函數,其實是保存在prototype名下的,只不過是經過各自對象的實例訪問罷了。在建立自定義引用類型以及實現繼承時,prototype屬性的做用是極爲重要的。
每一個函數都包含兩個非繼承而來的方法:apply()和call()。這兩個方法的用途都是在特定的做用域中調用函數,實際上等於設置函數體內this對象的值。
apply()方法接收兩個參數:一個是在其中運行函數的做用域,另外一個是參數數組(能夠是Array類型的實例,也能夠是arguments對象)。才`
function sayHello(name){ console.log("Hello " + name + ". Your age is " + this.age); } var o = {age:28}; global.age = 15; console.log(this.age); //undefined console.log(age); //15 sayHello.call(this, "LiLei"); //Hello LiLei. Your age is undefined sayHello.call(o, "LiLy"); //Hello LiLy. Your age is 28 sayHello.apply(global, ["Polly"]); //Hello Polly. Your age is 15 sayHello.apply(o, ["Tom"]); //Hello Tom. Your age is 28
從上面的代碼裏能夠得出,在nodejs中在全局函數中傳this並非傳遞的global(相似於瀏覽器中的window對象)因此函數中調用this.age爲undefined。
ECMAScript 5中還定義了bind()方法 用於綁定做用域。
function sayHello(name){ console.log("Hello " + name + ". Your age is " + this.age); } var o = {age:28}; global.age = 15; var sayHelloToObject = sayHello.bind(o); sayHelloToObject("HanMeimei"); //Hello HanMeimei. Your age is 28 sayHello.bind(o)("HanMeimei2"); //Hello HanMeimei2. Your age is 28
基本包裝類型包括:Boolean、Number、String
每當讀取一個基本類型值的時候,後臺就會建立一個對應的基本包裝類型對象,從而讓咱們可以調用一些方法來操做這些數據。過程以下:
引用類型與基本包裝類型的主要區別就是對象的生存期。使用new操做符建立的引用類型的實例,在執行流離開當前做用域以前都一直保存在內存中。
而自動建立的基本包裝類型的對象,則之存在與一行代碼的執行瞬間,而後當即被銷燬。
Object構造函數也會像工廠方法同樣,根據傳入值的類型返回相應基本包裝類型的實例。
var obj = new Object("lalala"); console.log(obj instanceof String); //true var str = "hello"; var strObj = new String("lilili"); var tempStrObj = String(str); console.log(typeof tempStrObj); //string console.log(typeof strObj); //object
通常來講,不建議顯示地建立基本包裝類型的對象,在基本數據類型的變量上能夠直接調用包裝類型的方法。
Boolean類型 是與布爾值對應的引用類型。可是做爲Boolean類型的對象,是用Object方式來判斷真假的。
var booleanObje = new Boolean(false); if(booleanObje){ console.log("true"); }else{ console.log("false"); }
上面代碼返回的true,因此建議永遠不要使用Boolean對象。
Number類型 是與數字值對應的引用類型。
toFixed()方法會按照制定的小數位返回數值的字符串表示。按照四捨五入保留到小數點後某位。
var num = 5.12521212; console.log(num.toFixed(2)); //5.13
toExponential()方法返回以指數表示法表示的數值字符串形式。
var num = 123456.78 console.log(num.toExponential(2)); //1.23e+5
toPrecision()方法能夠根據數值的大小判斷返回固定大小的格式仍是科學表示法的形式的字符串。
var num = 99; console.log(num.toPrecision(1)); //1e+2 console.log(num.toPrecision(2)); //99 console.log(num.toPrecision(3)); //99.0
String類型 是字符串的對象包裝類型。
String類型的每個實例都包含一個length屬性,表示字符串中包含了多少個字符。
concat()方法用於將多個字符串拼接起來,返回拼接之後的新字符串,和字符串的(+)操做符同樣。
substr()、substring()、slice()三個函數都是用來返回子字符串的,後兩個方法是同樣的,substr()方法若是有第二個參數,則表示子字符串的長度,其餘兩個的第二個參數表示結束位置後面的位置。
var str = "helloworld!"; console.log(str.substr(3)); //loworld! console.log(str.substring(3)); //loworld! console.log(str.slice(3)); //loworld! console.log(str.substr(3,5)); //lowor console.log(str.substring(3,5)); //lo console.log(str.slice(3,5)); //lo
模式匹配方法,match()方法(同RegExp的exec()方法),match()方法只接收一個參數,要麼是個正則表達式,要麼是個RegExp對象。
var text = "grandpa and mom and dad and baby"; var pattern = /mom( and dad( and baby)?)?/gi; var matches1 = text.match(pattern) var matches = pattern.exec(text); console.log(matches.index); //12 console.log(matches.input); //grandpa and mom and dad and baby console.log(matches); /* [ 'mom and dad and baby', ' and dad and baby', ' and baby', index: 12, input: 'grandpa and mom and dad and baby' ] */ console.log("==============================================="); console.log(matches1.index); //undefined console.log(matches1.input); //undefined console.log(matches1); //[ 'mom and dad and baby' ]
由上面的代碼能夠看出,match 和 exec 方法返回的值並不一致,exec 方法返回的信息更詳盡而且有捕獲組,而match沒有捕獲組的內容。
另外一個查找模式的方法是search()。參數也是正則表達式或RegExp對象,返回字符串中第一個匹配項的索引;若是沒有找到匹配項,則返回-1.
var text = "cat, bat, sat, fat"; var reg = /at/g; var res; res = text.search(reg); console.log(res); //1 res = text.search(reg); console.log(res); //1
可見search 方法始終從字符串開頭向後查找,即便指定了g也是如此。
replace()方法,用於簡化替換子字符的操做,接受兩個參數,第一個參數能夠是一個RegExp 對象或者一個字符串,第二個參數能夠是一個字符串或者函數。若是第一個參數是字符串,那麼只會替換第一個子字符串。要想替換全部子字符串,惟一的辦法就是提供一個正則表達式,並且要制定全局(g)標誌。
var text = "cat, bat, sat, fat"; var result; result = text.replace(/.at/, "word"); console.log(result); //word, bat, sat, fat result = text.replace(/.at/g, "word"); console.log(result); //word, word, word, word
第二個參數是函數時,函數接受三個參數:模式的匹配項、模式匹配項在字符串中的位置和原始字符串。
function htmlEscape(text){ return text.replace(/[<>"&]/g, function(match, pos, originalText){ switch(match){ case "<": return "<"; case ">": return ">"; case "&": return "&"; case "\"": return """; } }); } //<p class="test">Hello World!</p> console.log(htmlEscape("<p class=\"test\">Hello World!</p>"));
另外還有split()、indexOf()、trim()、charAt()等方法同Java,就不一一列舉了。
Global對象,是ECMAScript中是做爲一個終極的「兜底兒對象」,不屬於任何其餘對象的屬性和方法,最終都是他的屬性和方法,全部在全局做用於中定義的屬性和函數,都是Global對象的屬性。好比isNaN()、isFinite()、parseInt()、parseFloat()實際上都是Global 對象的方法。
encodeURI() 和 encodeURIComponent() 方法能夠對URI進行編碼,以便發送給瀏覽器。有效的URI中不能夠包含某些字符,例如空格。這兩個方法能夠就URI進行編碼,他們用特殊的UTF-8編碼替換全部無效的字符,從而讓瀏覽器可以接受和理解。
var uri = "http://www.baidu.com/illegal value.html#start"; console.log(encodeURI(uri)); //http://www.baidu.com/illegal%20value.html#start var temp = encodeURIComponent(uri); console.log(temp); //http%3A%2F%2Fwww.baidu.com%2Fillegal%20value.html%23start console.log(decodeURI(temp)); //http%3A%2F%2Fwww.baidu.com%2Fillegal value.html%23start console.log(decodeURIComponent(temp)); //http://www.baidu.com/illegal value.html#start
對應的解碼的方法是decodeURI()、decodeURIComponent()。
eval()方法接受一個字符串,即要執行的ECMAScript字符串。
eval(console.log("hello")); //hello
ECMAScript沒有指出如何直接訪問Global對象,可是Web瀏覽器都是將這個全局對象做爲window對象的一部分加以實現的。所以在全局做用於中生命的全部變量和函數,都成爲window對象的屬性。
Math對象,min()和max()方法用於肯定一組數值中的最小值和最大值。這兩個方法均可以接受任意多個數值參數。
舍入方法:Math.ceil()向上舍入、Math.floor()向下舍入、Math.round()四捨五入。
random()方法返回大於0小於1的一個隨機數。