在JS中用typeof操作符獲取對象的類型,它總是返回一個字符串:
typeof 123; // 'number'
typeof NaN; // 'number'
typeof 'str'; // 'string'
typeof true; // 'boolean'
typeof undefined; // 'undefined'
typeof Math.abs; // 'function'
typeof null; // 'object'
typeof []; // 'object'
typeof {}; // 'object'
其中number、string、boolean、function和undefined是基本數(shù)據(jù)類型,我們注意到null的類型是object,Array的類型也是object,如果我們用typeof將無法區(qū)分出null、Array和通常意義上的object。除此以外,JS還提供了包裝對象,number、boolean和string都有包裝對象,包裝對象用new創(chuàng)建:
var n = new Number(123); // 123,生成了新的包裝類型
var b = new Boolean(true); // true,生成了新的包裝類型
var s = new String('str'); // 'str',生成了新的包裝類型
雖然包裝對象看上去和原來一模一樣,但他們的類型已經(jīng)變?yōu)閛bject了!所以包裝對象和原始值用===比較會返回false,一般情況下不要使用包裝對象,尤其是string類型:
typeof new Number(123); // 'object'
new Number(123) === 123; // false
typeof new Boolean(true); // 'object'
new Boolean(true) === true; // false
typeof new String('str'); // 'object'
new String('str') === 'str'; // false
此外,Number()、Boolean和String()作為普通函數(shù),把任何類型的數(shù)據(jù)轉(zhuǎn)換為其相應(yīng)類型(注意不是包裝類型):
var n = Number('123'); // 123,相當(dāng)于parseInt()或parseFloat()
typeof n; // 'number'
var b = Boolean('true'); // true
typeof b; // 'boolean'
var b2 = Boolean('false'); // true! 'false'字符串轉(zhuǎn)換結(jié)果為true!因為它是非空字符串!
var b3 = Boolean(''); // false
var s = String(123.45); // '123.45'
typeof s; // 'string'
對JS中數(shù)據(jù)類型稍作總結(jié)如下:
- 不要使用new Number()、new Boolean()、new String()創(chuàng)建包裝對象;
- 用parseInt()或parseFloat()來轉(zhuǎn)換任意類型到number;
- 用String()來轉(zhuǎn)換任意類型到string,或者直接調(diào)用某個對象的toString()方法;
- 通常不必把任意類型轉(zhuǎn)換為boolean再判斷,因為可以直接寫if (myVar) {...};
- typeof操作符可以判斷區(qū)分number、boolean、string、function和undefined;
- 判斷Array要使用Array.isArray(arr);
- 判斷null請使用myVar === null;
- 判斷全局變量是否存在用typeof window.myVar === 'undefined';
- 函數(shù)內(nèi)部判斷變量是否存在用typeof myVar === 'undefined'。
最后需要指出null和undefined沒有toString(),number對象調(diào)用toString()要特殊處理一下:
123.toString(); // SyntaxError
123..toString(); // '123', 注意是兩個點!
(123).toString(); // '123'
Date
在JS中Date對象用來表示日期和時間:
var now = new Date();
now; // Wed Jun 24 2015 19:49:22 GMT+0800 (CST)
now.getFullYear(); // 2015, 年份
now.getMonth(); // 5, 月份,注意月份范圍是0~11,5表示六月
now.getDate(); // 24, 表示24號
now.getDay(); // 3, 表示星期三
now.getHours(); // 19, 24小時制
now.getMinutes(); // 49, 分鐘
now.getSeconds(); // 22, 秒
now.getMilliseconds(); // 875, 毫秒數(shù)
now.getTime(); // 1435146562875, 以number形式表示的時間戳
注意,當(dāng)前時間是瀏覽器從本機操作系統(tǒng)獲取的時間,所以不一定準確,如果要創(chuàng)建一個指定日期和時間的Date對象,可以用:
var d = new Date(2015, 5, 19, 20, 15, 30, 123);
d; // Fri Jun 19 2015 20:15:30 GMT+0800 (CST)
var timestamp = Date.parse('2015-06-24T19:49:22.875+08:00');
// 這里返回一個時間戳,再轉(zhuǎn)換為Date:
timestamp; // 1435146562875
var date = new Date(timestamp);
date; // Wed Jun 24 2015 19:49:22 GMT+0800 (CST)
date.toLocaleString(); // '2015/6/24 下午7:49:22',本地時間(北京時區(qū)+8:00),顯示的字符串與操作系統(tǒng)設(shè)定的格式有關(guān)
date.toUTCString(); // 'Wed, 24 Jun 2015 11:49:22 GMT',UTC時間,與本地時間相差8小時
需要強調(diào)的是JS中月份范圍用整數(shù)表示是0~11,從0開始。我們只需要從數(shù)據(jù)庫讀取時間戳,再轉(zhuǎn)換為當(dāng)?shù)貢r間:
if (Date.now) {
alert(Date.now()); // 老版本IE沒有now()方法
} else {
alert(new Date().getTime());
}
RegExp
JS中創(chuàng)建正則表達式有兩種方式,第一種方式是直接通過/正則表達式/寫出來,第二種方式是通過new RegExp('正則表達式')創(chuàng)建一個RegExp對象:
var re1 = /ABC\-001/;
var re2 = new RegExp('ABC\\-001');
re1; // /ABC\-001/
re2; // /ABC\-001/
RegExp對象的test()方法用于測試給定的字符串是否符合條件:
var re = /^\d{3}\-\d{3,8}$/;
re.test('010-12345'); // true
re.test('010-1234x'); // false
re.test('010 12345'); // false
用正則表達式切分字符串比用固定的字符更靈活:
'a b c'.split(' '); // ['a', 'b', '', '', 'c']
// 用正則表達式切分
'a b c'.split(/\s+/); // ['a', 'b', 'c']
// 加入,試試
'a,b, c d'.split(/[\s\,]+/); // ['a', 'b', 'c', 'd']
一般用正則表達式把用戶不規(guī)范的輸入轉(zhuǎn)化成正確的格式進行處理。除此之外,正則表達式還有提取子串的強大功能,比如:
var re = /^(\d{3})-(\d{3,8})$/;
re.exec('010-12345'); // ['010-12345', '010', '12345']
re.exec('010 12345'); // null
exec()方法在匹配成功后,會返回一個Array,第一個元素是正則表達式匹配到的整個字符串,后面的字符串表示匹配成功的子串;exec()方法在匹配失敗時返回null。
需要特別指出的是,正則匹配默認是貪婪匹配,也就是匹配盡可能多的字符。舉例如下:
var re = /^(\d+)(0*)$/;
re.exec('102300'); // ['102300', '102300', '']
由于\d+采用貪婪匹配,直接把后面的0全部匹配了,結(jié)果0*只能匹配空字符串了。必須讓\d+采用非貪婪匹配(也就是盡可能少匹配),才能把后面的0匹配出來,加個?就可以讓\d+采用非貪婪匹配:
var re = /^(\d+?)(0*)$/;
re.exec('102300'); // ['102300', '1023', '00']
JS的正則表達式還有幾個特殊的標(biāo)志,最常用的是g表示全局匹配,i表示忽略大小寫,m表示執(zhí)行多行匹配:
var r1 = /test/g;
// 等價于:
var r2 = new RegExp('test', 'g');
全局匹配可以多次執(zhí)行exec()方法來搜索一個匹配的字符串,不能使用/^...$/,那樣只會最多匹配一次。當(dāng)我們指定g標(biāo)志后,每次運行exec(),正則表達式本身會更新lastIndex屬性,表示上次匹配到的最后索引:
var s = 'JavaScript, VBScript, JScript and ECMAScript';
var re=/[a-zA-Z]+Script/g;
// 使用全局匹配:
re.exec(s); // ['JavaScript']
re.lastIndex; // 10
re.exec(s); // ['VBScript']
re.lastIndex; // 20
re.exec(s); // ['JScript']
re.lastIndex; // 29
re.exec(s); // ['ECMAScript']
re.lastIndex; // 44
re.exec(s); // null,直到結(jié)束仍沒有匹配到
JSON
JSON實際上是JavaScript的一個子集,在JS中我們可以直接使用JSON,因為JavaScript內(nèi)置了JSON的解析。把任何JavaScript對象變成JSON,就是把這個對象序列化成一個JSON格式的字符串,這樣才能夠通過網(wǎng)絡(luò)傳遞給其他計算機。如果我們收到一個JSON格式的字符串,只需要把它反序列化成一個JavaScript對象,就可以在JavaScript中直接使用這個對象了。讓我們先把小明這個對象序列化成JSON格式的字符串:
var xiaoming = {
name: '小明',
age: 14,
gender: true,
height: 1.65,
grade: null,
'middle-school': '\"W3C\" Middle School',
skills: ['JavaScript', 'Java', 'Python', 'Lisp']
};
JSON.stringify(xiaoming); // '{"name":"小明","age":14,"gender":true,"height":1.65,"grade":null,"middle-school":"\"W3C\" Middle School","skills":["JavaScript","Java","Python","Lisp"]}'
可以加上參數(shù)按縮進輸出:
JSON.stringify(xiaoming, null, ' ');
結(jié)果:
{
"name": "小明",
"age": 14,
"gender": true,
"height": 1.65,
"grade": null,
"middle-school": "\"W3C\" Middle School",
"skills": [
"JavaScript",
"Java",
"Python",
"Lisp"
]
}
第二個參數(shù)用于控制如何篩選對象的鍵值,如果我們只想輸出指定的屬性,可以傳入Array:
JSON.stringify(xiaoming, ['name', 'skills'], ' ');
結(jié)果:
{
"name": "小明",
"skills": [
"JavaScript",
"Java",
"Python",
"Lisp"
]
}
還可以傳入一個函數(shù),這樣對象的每個鍵值對都會被函數(shù)先處理:
function convert(key, value) {
if (typeof value === 'string') {
return value.toUpperCase();
}
return value;
}
JSON.stringify(xiaoming, convert, ' ');
{
"name": "小明",
"age": 14,
"gender": true,
"height": 1.65,
"grade": null,
"middle-school": "\"W3C\" MIDDLE SCHOOL",
"skills": [
"JAVASCRIPT",
"JAVA",
"PYTHON",
"LISP"
]
}
如果我們還想要精確控制如何序列化小明,可以給xiaoming定義一個toJSON()的方法,直接返回JSON應(yīng)該序列化的數(shù)據(jù):
var xiaoming = {
name: '小明',
age: 14,
gender: true,
height: 1.65,
grade: null,
'middle-school': '\"W3C\" Middle School',
skills: ['JavaScript', 'Java', 'Python', 'Lisp'],
toJSON: function () {
return { // 只輸出name和age,并且改變了key:
'Name': this.name,
'Age': this.age
};
}
};
JSON.stringify(xiaoming); // '{"Name":"小明","Age":14}'
拿到一個JSON格式的字符串,我們直接用JSON.parse()把它變成一個JavaScript對象:
JSON.parse('[1,2,3,true]'); // [1, 2, 3, true]
JSON.parse('{"name":"小明","age":14}'); // Object {name: '小明', age: 14}
JSON.parse('true'); // true
JSON.parse('123.45'); // 123.45
JSON.parse()還可以接收一個函數(shù),用來轉(zhuǎn)換解析出的屬性:
JSON.parse('{"name":"小明","age":14}', function (key, value) {
// 把number * 2:
if (key === 'name') {
return value + '同學(xué)';
}
return value;
}); // Object {name: '小明同學(xué)', age: 14}