第三章 基本概念
3.1 語法
- ECMAScript標識符一般采用駝峰大小寫格式炕矮,也就是第一個字母小寫禁偎,剩下的每個單詞首字母大寫
3.3 變量
- 在嚴格模式下,不能定義名為eval或arguments的變量,否則會導致語法錯誤爽柒。
3.4 數(shù)據(jù)結構
ECMAScript中有5種簡單數(shù)據(jù)類型(也稱為基本數(shù)據(jù)類型):Undefined、Null者填、Boolean浩村、Number、String占哟。還有一個種復雜數(shù)據(jù)類型--Object
-
typeof 操作符的返回值
- "function" —— 如果這個值是函數(shù)心墅。
從技術角度講,函數(shù)在 ECMAScript中是對象榨乎,不是一種數(shù)據(jù)類型怎燥。然而,函數(shù)也確實有一些特殊的屬性蜜暑,因此通過 typeof 操作符來區(qū)分函數(shù)和其他對象是有必要的铐姚。
- "object" ——如果這個值是對象或 null,
因為null被認為是一個空對象的引用
- Chrome 7 及之前版本對正則表達式應用 typeof 會返回 "function" 肛捍。在IE 和 Firefox中隐绵,對正則表達式應用 typeof 會返回 "object"
typeof 是一個操作符而不是函數(shù)之众,所以后面不必加括號如typeof(),
3.4.2 Undefine類型
- 對未初始化和未聲明的變量執(zhí)行 typeof 操作符都返回了 undefined 值
3.4.3 Null類型
如果定義的變量準備在將來用于保存對象依许,那么最好將該變量初始化為 null 而不是其他值酝枢。這樣一來,只要直接檢查 null 值就可以知道相應的變量是否已經(jīng)保存了一個對象的引用
alert(null == undefined) //true
3.4.5 Number類型
要將一個值轉換為其對應的 Boolean 值悍手,可以調(diào)用轉型函數(shù) Boolean()
永遠不要測試某個特定的浮點數(shù)值帘睦。
任何數(shù)值除以非數(shù)值會返回NaN,因此不會影響其他代碼的執(zhí)行坦康。
-
數(shù)值轉換
-
Number()
- 如果是 undefined 竣付,返回 NaN
- 如果是 null 值,返回 0
- 如果字符串中包含有效的十六進制格式滞欠,例如 "0xf" 古胆,則將其轉換為相同大小的十進制整數(shù)值
- 如果字符串是空的(不包含任何字符),則將其轉換為 0筛璧,而parseInt()則返回NaN
var num1 = Number("Hello world!"); //NaN var num2 = Number(""); //0 var num3 = Number("000011"); //11 var num4 = Number(true); //1
- ParseInt()
parseInt() 函數(shù)在轉換字符串時逸绎,更多的是看其是否符合數(shù)值模式。它會忽略字符串前面的空格夭谤,直至找到第一個非空格字符棺牧。如果第一個字符不是數(shù)字字符或者負號, parseInt()就會返回 NaN 朗儒;也就是說颊乘,用 parseInt() 轉換空字符串會返回 NaN ( Number() 對空字符返回 0)。如果第一個字符是數(shù)字字符醉锄, parseInt() 會繼續(xù)解析第二個字符乏悄,直到解析完所有后續(xù)字符或者遇到了一個非數(shù)字字符
var num1 = parseInt("1234blue"); // 1234 var num2 = parseInt(""); // NaN var num3 = parseInt("0xA"); // 10(十六進制數(shù)) var num4 = parseInt(22.5); // 22 var num5 = parseInt("070"); // 56(八進制數(shù)) var num6 = parseInt("70"); // 70(十進制數(shù)) var num7 = parseInt("0xf"); // 15(十六進制數(shù))
為了消除在使用 parseInt() 函數(shù)時可能導致的上述困惑,可以為這個函數(shù)提供第二個參數(shù):轉換時使用的基數(shù)(即多少進制)
var num = parseInt("0xAF", 16); //175
實際上恳不,如果指定了 16 作為第二個參數(shù)檩小,字符串可以不帶前面的 "0x" 。
- parseFloat()
var num1 = parseFloat("1234blue"); //1234 (整數(shù)) var num2 = parseFloat("0xA"); /*0,與parseInt不同烟勋,parseFlort會始終忽略前導零规求, 而parseInt會將前導零解析為八進制*/ var num3 = parseFloat("22.5"); //22.5 var num4 = parseFloat("22.34.5"); //22.34 var num5 = parseFloat("0908.5"); //908.5 var num6 = parseFloat("3.125e7"); //31250000
-
Number()
3.4.6 String類型
-
toString()和String()方法的不同
null和undefined沒有toString()方法,在不知道要轉換的值是不是 null 或 undefined 的情況下神妹,可以使用轉型函數(shù) String()颓哮。
在調(diào)用數(shù)值的 toString() 方法時,可以傳遞一個參數(shù):輸出數(shù)值的基數(shù)鸵荠。默認情況下, toString() 方法以十進制格式返回數(shù)值的字符串表示伤极。而通過傳遞基數(shù)蛹找, toString() 可以輸出以二進制姨伤、八進制、十六進制庸疾,乃至其他任意有效進制格式表示的字符串值var num = 10; alert(num.toString()); // "10" alert(num.toString(2)); // "1010" alert(num.toString(8)); // "12" alert(num.toString(10)); // "10" alert(num.toString(16)); // "a"
var value1 = 10; var value2 = true; var value3 = null; var value4; alert(String(value1)); // "10" alert(String(value2)); // "true" alert(String(value3)); // "null" alert(String(value4)); // "undefined"
3.4.7 Object類型
Object 的每個實例都具有下列屬性和方法
- constructor :保存著用于創(chuàng)建當前對象的函數(shù)乍楚。對于前面的例子而言,構造函數(shù)(constructor)就是 Object() 届慈。
- hasOwnProperty(propertyName) :用于檢查給定的屬性在當前對象實例中(而不是在實例的原型中)是否存在徒溪。其中,作為參數(shù)的屬性名( propertyName )必須以字符串形式指定(例如: o.hasOwnProperty("name") )金顿。
- isPrototypeOf(object) :用于檢查傳入的對象是否是傳入對象的原型
- propertyIsEnumerable(propertyName) :用于檢查給定的屬性是否能夠使用 for-in 語句臊泌,與 hasOwnProperty() 方法一樣,作為參數(shù)的屬性名必須以字符串形式指定揍拆。
- toString() :返回對象的字符串表示
- valueOf() :返回對象的字符串渠概、數(shù)值或布爾值表示。通常與 toString() 方法的返回值相同
3.5 操作符
-
一元加減操作符
一元加操作符以一個加號(+)表示嫂拴,放在數(shù)值前面播揪,對數(shù)值不會產(chǎn)生任何影響,不過,在對非數(shù)值應用一元加操作符時筒狠,該操作符會像 Number() 轉型函數(shù)一樣對這個值執(zhí)行轉換猪狈。
按位異或 ^
左移 <<
有符號右移 >>
無符號右移 >>>
-
邏輯非!
邏輯非操作符首先會將它的操作數(shù)轉換為一個布爾值,然后再
對其求反 -
邏輯與&&(短路操作)
- 如果第一個操作數(shù)是對象辩恼,則返回第二個操作數(shù)
- 如果第二個操作數(shù)是對象罪裹,則只有在第一個操作數(shù)的求值結果為 true 的情況下才會返回該對象
- 如果有一個操作數(shù)是 null ,則返回 null
- 如果有一個操作數(shù)是 NaN 运挫,則返回 NaN
- 如果有一個操作數(shù)是 undefined 状共,則返回 undefined
- 即如果第一個操作數(shù)能夠決定結果,那么就不會再對第二個操作數(shù)求值谁帕。對于邏輯與操作而言峡继,如果第一個操作數(shù)是 false ,則無論第二個操作數(shù)是什么值匈挖,結果都不再可能是true
-
邏輯或||
- 邏輯或操作符也是短路操作符碾牌。也就是說,如果第一個操作數(shù)的求值結果為true 儡循,就不會對第二個操作數(shù)求值了
- 我們可以利用邏輯或的這一行為來避免為變量賦 null 或 undefined 值
var myObject = preferredObject || backupObject;
-
減法
如果有一個操作數(shù)是字符串舶吗、布爾值、 null 或 undefined 择膝,則先在后臺調(diào)用 Number() 函數(shù)將其轉換為數(shù)值誓琼,然后再根據(jù)前面的規(guī)則執(zhí)行減法計算。如果轉換的結果是 NaN ,則減法的結果就是 NaN
var result1 = 5 - true; // 4腹侣,因為 true 被轉換成了 1 var result2 = NaN - 1; // NaN var result3 = 5 - 3; // 2 var result4 = 5 - ""; // 5叔收,因為"" 被轉換成了 0 var result5 = 5 - "2"; // 3,因為"2"被轉換成了 2 var result6 = 5 - null; // 5傲隶,因為 null 被轉換成了 0
第四章 變量饺律、作用域和內(nèi)存問題
4.1 基本類型和引用類型的值
- ECMAScript 變量可能包含兩種不同數(shù)據(jù)類型的值:基本類型值和引用類型值《逯辏基本類型值指的是簡單的數(shù)據(jù)段复濒,而引用類型值指那些可能由多個值構成的對象
- 當從一個變量向另一個變量復制引用類型的值時,同樣也會將存儲在變量對象中的值復制一份放到為新變量分配的空間中乒省。不同的是巧颈,這個值的副本實際上是一個指針,而這個指針指向存儲在堆中的一個對象作儿。復制操作結束后洛二,兩個變量實際上將引用同一個對象。因此攻锰,改變其中一個變量晾嘶,就會影響另一個變量
var obj1 = new Object();
var obj2 = obj1;
obj1.name = "Nicholas";
alert(obj2.name); //"Nicholas"
- 參數(shù)只能按值傳遞,不管是基本類型的值還是引用類型的值
function setName(obj) {
obj.name = "Nicholas";
obj = new Object();
obj.name = "Greg";
}
var person = new Object();
setName(person);
alert(person.name); //"Nicholas"
實際上娶吞,當在函數(shù)內(nèi)部重寫 obj 時垒迂,這個變量引用的就是一個局部對象了。而這個局部對象會在函數(shù)執(zhí)行完畢后立即被銷毀妒蛇。
- 檢測類型 instanceof
雖然在檢測基本數(shù)據(jù)類型時 typeof 是非常得力的助手机断,但在檢測引用類型的值時,這個操作符的用處不大绣夺。通常吏奸,我們并不是想知道某個值是對象,而是想知道它是什么類型的對象陶耍。為ECMAScript
提供了 instanceof 操作符
alert(person instanceof Object); // 變量 person 是 Object 嗎奋蔚?
alert(colors instanceof Array); // 變量 colors 是 Array 嗎?
alert(pattern instanceof RegExp); // 變量 pattern 是 RegExp 嗎烈钞?
第5章 引用類型
5.1 Object類型
-
創(chuàng)建Object類型的兩種方法
- 使用new操作符后跟Object構造函數(shù)
- 對象字面量
對象字面量也是向函數(shù)傳遞大量可選參數(shù)的首選方式
function displayInfo(args) { var output = ""; if (typeof args.name == "string"){ output += "Name: " + args.name + "\n"; } if (typeof args.age == "number") { output += "Age: " + args.age + "\n"; } alert(output); } displayInfo({ name: "Nicholas", age: 29 }); displayInfo({ name: "Greg" });
-
訪問對象屬性的兩種方法
- 點表示法泊碑,最通用
- 方括號表示法
屬性名中包含會導致語法錯誤的字符,或者屬性名使用的是關鍵字或保留字毯欣,也可以使用方括號表示法
person["first name"] = "Nicholas"
5.2 Array類型
-
數(shù)組的length屬性可讀可寫的馒过。
var colors = ["red", "blue", "green"]; // 創(chuàng)建一個包含 3 個字符串的數(shù)組 colors[colors.length] = "black"; // (在位置 3 )添加一種顏色 colors[colors.length] = "brown"; // (在位置 4 )再添加一種顏色
-
檢測數(shù)組
- instanceof
- Array.isArray()
Array.isArray([1, 2, 3]); // true Array.isArray({foo: 123}); // false Array.isArray('foobar'); // false Array.isArray(undefined); // false
-
轉換方法
- toString()
var colors = ["red", "blue", "green"]; // 創(chuàng)建一個包含 3 個字符串的數(shù)組 alert(colors.toString()); // red,blue,green alert(colors.valueOf()); // red,blue,green alert(colors); // red,blue,green
由于alert() 要接收字符串參數(shù),所以它會在后臺調(diào)用 toString() 方法酗钞,由此會得到與直接調(diào)用 toString() 方法相同的結果
- join()var colors = ["red", "green", "blue"]; alert(colors.join(",")); //red,green,blue alert(colors.join("||")); //red||green||blue
-
棧方法:后進先出
- push()
返回的是數(shù)組的新長度
var colors = new Array(); // 創(chuàng)建一個數(shù)組 var count = colors.push("red", "green"); // 推入兩項 alert(count); //2
- pop()
返回的是移除的項
var colors = ["red", "blue"]; colors.push("brown"); // 添加另一項 colors[3] = "black"; // 添加一項 alert(colors.length); // 4 var item = colors.pop(); // 取得最后一項 alert(item); //"black"
- push()
-
隊列方法:先進先出
- shift()
移除數(shù)組中的第一個項并返回該項 - unshift()
在數(shù)組前端添加任意個項并返回新數(shù)組的長度
- shift()
-
重排序方法
- reverse()
var values = [1, 2, 3, 4, 5]; values.reverse(); alert(values); //5,4,3,2,1
- sort()
//正確的排序方法 function compare(value1, value2) { if (value1 < value2) { return -1; } else if (value1 > value2) { return 1; } else { return 0; } } var values = [0, 1, 5, 10, 15]; values.sort(compare); alert(values); //0,1,5,10,15
-
操作方法
- concat()
拼接數(shù)組 - slice()
slice() 方法可以接受一或兩個參數(shù)腹忽,即要返回項的起始和結束位置来累。在只有一個參數(shù)的情況下, slice() 方法返回從該參數(shù)指定位置開始到當前數(shù)組末尾的所有項留凭。如果有兩個參數(shù)佃扼,該方法返回起始和結束位置之間的項——但不包括結束位置的項偎巢。
var colors = ["red", "green", "blue", "yellow", "purple"]; var colors2 = colors.slice(1); //["green", "blue", "yellow", "purple"] var colors3 = colors.slice(1,4); //["green", "blue", "yellow"]
-
splice()
最強大的數(shù)組方法蔼夜,可刪除,插入压昼,替換- 刪除
可以刪除任意數(shù)量的項求冷,只需指定 2 個參數(shù):要刪除的第一項的位置和要刪除的項數(shù)。例如窍霞, splice(0,2) 會刪除數(shù)組中的前兩項
- 插入
可以向指定位置插入任意數(shù)量的項匠题,只需提供 3 個參數(shù):起始位置、0(要刪除的項數(shù))和要插入的項但金。如果要插入多個項韭山,可以再傳入第四、第五冷溃,以至任意多個項钱磅。例如,splice(2,0,"red","green") 會從當前數(shù)組的位置 2 開始插入字符串 "red" 和 "green"
- 替換
可以向指定位置插入任意數(shù)量的項似枕,且同時刪除任意數(shù)量的項盖淡,只需指定 3 個參數(shù):起始位置、要刪除的項數(shù)和要插入的任意數(shù)量的項凿歼。插入的項數(shù)不必與刪除的項數(shù)相等褪迟。例如,splice (2,1,"red","green") 會刪除當前數(shù)組位置 2 的項答憔,然后再從位置 2 開始插入字符串"red" 和 "green"
var colors = ["red", "green", "blue"]; var removed = colors.splice(0,1); // 刪除第一項 alert(colors); // green,blue alert(removed); // red味赃,返回的數(shù)組中只包含一項 removed = colors.splice(1, 0, "yellow", "orange"); // 從位置 1 開始插入兩項 alert(colors); // green,yellow,orange,blue alert(removed); // 返回的是一個空數(shù)組 removed = colors.splice(1, 1, "red", "purple"); // 插入兩項,刪除一項 alert(colors); // green,red,purple,orange,blue alert(removed); // yellow虐拓,返回的數(shù)組中只包含一項
- concat()
-
位置方法
- indexOf()和lastIndexOf()
這兩個方法都接收兩個參數(shù):要查找的項和(可選的)表示查找起點位置的索引心俗。其中, indexOf() 方法從數(shù)組的開頭(位置 0)開始向后查找侯嘀, lastIndexOf() 方法則從數(shù)組的末尾開始向前查找,這兩個方法都返回要查找的項在數(shù)組中的位置另凌,或者在沒找到的情況下返回-1。
var numbers = [1,2,3,4,5,6,5,2,7]; alert(numbers.indexOf(4)); //3 alert(numbers.lastIndexOf(5)); //6 alert(numbers.lastIndexOf(7)); //8 alert(numbers.indexOf(4, 4)); //-1 alert(numbers.indexOf(4, 3)); //3 alert(numbers.lastIndexOf(2, 8)); //-1 alert(numbers.lastIndexOf(2, 5)); //8 var person = { name: "Nicholas" }; var people = [{ name: "Nicholas" }]; var morePeople = [person]; alert(people.indexOf(person)); //-1 alert(morePeople.indexOf(person)); //0
-
reduce()和reduceRight()
reduce() 和 reduceRight() 的函數(shù)接收 4 個參數(shù):前一個值戒幔、當前值吠谢、項的索引和數(shù)組對象
var values = [1,2,3,4,5]; var sum = values.reduce(function(prev, cur, index, array){ return prev + cur; }); alert(sum); //15
5.4 Date類型
5.5 RegExp類型
- 可以使用RegExp()構造函數(shù)來創(chuàng)建RegExp對象,但更多時候正則表達式直接量定義為包含在一隊斜杠(/)之間的字符诗茎,例如
var pattern=/s$/
var pattern=new RegExp('s$')
- RegExp實例方法
-
test()
- 基本語法:RegExpObject.test(str)
- param(參數(shù)) str是需要檢測的字符串
- return (返回值) 如果字符串str中含有與RegExpObject匹配的文本的話工坊,返回true献汗,否則返回false
var str = "longen and yunxi"; console.log(/longen/.test(str)); // true console.log(/longlong/.test(str)); //false // 或者創(chuàng)建RegExp對象模式 var regexp = new RegExp("longen"); console.log(regexp.test(str)); // true
-
exec()
- 基本語法:RegExpObject.exec(string)
- param(參數(shù)):string【必填項】要檢索的字符串
- return(返回值):返回一個數(shù)組,存放匹配的結果王污,如果未找到匹配罢吃,則返回值為null
- 該返回的數(shù)組的第一個元素是與正則表達式相匹配的文本,該方法還返回2個屬性昭齐,index屬性聲明的是匹配文本的第一個字符的位置尿招;input屬性則存放的是被檢索的字符串string;該方法如果不是全局的話阱驾,返回的數(shù)組與match()方法返回的數(shù)組是相同的
var str = "longen and yunxi"; console.log(/longen/.exec(str)); // 打印 ["longen", index: 0, input: "longen and yunxi"] // 假如沒有找到的話就谜,則返回null console.log(/wo/.exec(str)); // null
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 and baby" alert(matches[0]); // "mom and dad and baby" alert(matches[1]); // " and dad and baby" alert(matches[2]); // " and baby"
- 上面一段代碼,為什么matches[1]會是"and dad and baby"里覆,后來參考了使用js中的exec()方法構造正則表達式驗證這一篇博客丧荐,才知道,“在返回的數(shù)組中喧枷,第一項是與整個模式匹配的字符串虹统,其他項是與模式中的捕獲組匹配的字符串(如果模式中沒有捕獲組,則該數(shù)組只包含一項)”這句話中的“捕獲組匹配的字符串”是指模式匯總每一個()所定義的分組所匹配的字符隧甚,這也就不難解釋為什么matches[1]是"and dad and baby"车荔,matches[2]是“and baby”了。
- 關于index和lastINdex,可參考這篇segmentfault上的問答:js中呻逆,exec()方法夸赫,為何這里的index是5?,摘抄如下:
var pattern2 = /.at/g; var matches = pattern2.exec(text); alert(matches.index); //0 alert(matches[0]); //cat alert(pattern2.lastIndex); //3 matches = pattern2.exec(text); alert(matches.index); //5 alert(matches[0]); //bat alert(pattern2.lastIndex); //8
咱們按逗號之后不加空格來說:你看咖城,第一次檢索出來的是cat茬腿,第一個字符的索引是0,所以result.index是0宜雀,而此時一個檢查字符串中每個字符的指針ptr已經(jīng)走到t后面了切平,所以lastIndex是3,就是相當于告訴正則表達式辐董,我們已經(jīng)檢查到索引為3的地方了悴品,下一次直接從這里開始就好了。
第二次檢索從lastIndex也就是3開始,找到后面的bat之后,匹配成功致板,bat里第一個字符b是4昭躺,所以result.index是4棘钞,而我們匹配完整個bat的時候,指針ptr已經(jīng)走到bat后面了,也就是索引為7的位置,所以結果是4和7退子。這樣你再開始下一次檢索的時候岖妄,就會從text[7]開始,也就是第二個逗號的位置開始往后找寂祥,所以下一次匹配是8, sat, 11荐虐,再下次12, fat, 15。現(xiàn)在到頭了丸凭,再匹配一次的話就是null了福扬,這時候你看看pattern1.lastIndex,已經(jīng)回到0了贮乳。
-
5.5 Function類型
- 函數(shù)是對象忧换,每個函數(shù)都是Function類型的實例恬惯,函數(shù)名是一個指向函數(shù)對象的指針向拆。
- 使用不帶圓括號的函數(shù)名是訪問函數(shù)指針,而非調(diào)用函數(shù)
- 函數(shù)聲明與函數(shù)表達式的區(qū)別
//函數(shù)聲明提升酪耳,函數(shù)正常運行浓恳,沒有報錯
alert(sum(10,10));
function sum(num1, num2){
return num1 + num2;
}
//報錯
alert(sum(10,10));
var sum = function(num1, num2){
return num1 + num2;
};
-
apply()方法和call()
- call()和apply()的第一個實參是要調(diào)用函數(shù)的母對象,它是調(diào)用上下文碗暗,在函數(shù)體內(nèi)通過this來獲得對它的引用颈将。
- 要想以對象o的方法來調(diào)用函數(shù)f(),可以這樣使用call()和apply()。
f.call(o); f.apply(o); //每行代碼和下面代碼的功能類似 o.m=f; //將f存儲為o的臨時方法 o.m(); //調(diào)用它言疗,不傳入?yún)?shù) delete o.m; //將臨時方法刪除
- apply() 方法接收兩個參數(shù):一個是在其中運行函數(shù)的作用域晴圾,另一個是參數(shù)數(shù)組。其中噪奄,第二個參數(shù)可以是 Array 的實例死姚,也可以是arguments 對象,call() 方法與 apply() 方法的作用相同勤篮,它們的區(qū)別僅在于接收參數(shù)的方式不同都毒。對于 call()方法而言,第一個參數(shù)是 this 值沒有變化碰缔,變化的是其余參數(shù)都直接傳遞給函數(shù)账劲。換句話說,在使用call() 方法時金抡,傳遞給函數(shù)的參數(shù)必須逐個列舉出來
- 一般用來擴充函數(shù)賴以運行的作用域
window.color = "red"; var o = { color: "blue" }; function sayColor(){ alert(this.color); } sayColor(); //red sayColor.call(this); //red sayColor.call(window); //red sayColor.call(o); //blue
-
bind()方法
- 這個方法會創(chuàng)建一個函數(shù)的實例瀑焦,其 this 值會被綁定到傳給 bind() 函數(shù)的值
window.color = "red"; var o = { color: "blue" }; function sayColor(){ alert(this.color); } var objectSayColor = sayColor.bind(o); objectSayColor(); //blue
5.6 基本包裝類型
為了便于操作基本類型值,ECMAScript 還提供了 3 個特殊的引用類型: Boolean 梗肝、 Number 和String
-
每當讀取一個基本類型值的時候榛瓮,后臺就會創(chuàng)建一個對應的基本包裝類型的對象,從而讓我們能夠調(diào)用一些方法來操作這些數(shù)據(jù)
var s1 = "some text"; var s2 = s1.substring(2);
處理過程如下:
- 創(chuàng)建 String 類型的一個實例
- 在實例上調(diào)用指定的方法
- 銷毀這個實例
可以將以上三個步驟想象成是執(zhí)行了下列 ECMAScript 代碼
var s1 = new String("some text"); var s2 = s1.substring(2); s1 = null;
引用類型與基本包裝類型的主要區(qū)別就是對象的生存期统捶。使用 new 操作符創(chuàng)建的引用類型的實例榆芦,在執(zhí)行流離開當前作用域之前都一直保存在內(nèi)存中柄粹。而自動創(chuàng)建的基本包裝類型的對象,則只存在于一行代碼的執(zhí)行瞬間匆绣,然后立即被銷毀驻右。這意味著我們不能在運行時為基本類型值添加屬性和方法。來看下面的例子:
var s1 = "some text"; s1.color = "red"; //第二行創(chuàng)建的 String 對象在執(zhí)行第三行代碼時已經(jīng)被銷毀了 alert(s1.color); //undefined
5.6.1 Boolean類型
- 由于 Boolean 對象是 Boolean 類型的實例崎淳,所以使用 instanceof操作符測試 Boolean 對象會返回 true 堪夭,而測試基本類型的布爾值則返回 false
- 理解基本類型的布爾值與 Boolean 對象之間的區(qū)別非常重要——當然,我們的建議是永遠不要使用 Boolean 對象
5.6.2 Number類型
var num = 10;
alert(num.toString()); //"10"
alert(num.toString(2)); //"1010"
alert(num.toString(8)); //"12"
alert(num.toString(10)); //"10"
alert(num.toString(16)); //"a"
-
Number 類型還提供了一些用于將數(shù)值格式化為字符串的方法
- toFixed()
會按照指定的小數(shù)位返回數(shù)值的字符串表示
var num = 10; alert(num.toFixed(2)); //"10.00"
- toExponential()
方法返回以指數(shù)表示法(也稱 e 表示法)表示的數(shù)值的字符串形式
var num = 10; alert(num.toExponential(1)); //"1.0e+1"
- toPrecision()
對于一個數(shù)值來說拣凹, toPrecision() 方法可能會返回固定大猩(fixed)格式,也可能返回指數(shù)(exponential)格式嚣镜;具體規(guī)則是看哪種格式最合適爬迟。這個方法接收一個參數(shù),即表示數(shù)值的所有數(shù)字的位數(shù)(不包括指數(shù)部分)
var num = 99; alert(num.toPrecision(1)); //"1e+2" alert(num.toPrecision(2)); //"99" alert(num.toPrecision(3)); //"99.0"
- toFixed()
5.6.3 String類型
String 類型的每個實例都有一個 length 屬性菊匿,表示字符串中包含多個字符
var stringValue = "hello world";
alert(stringValue.length); //"11"
-
字符方法
- charAt()
charAt() 方法以單字符字符串的形式返回給定位置的那個字符
var stringValue = "hello world"; alert(stringValue.charAt(1)); //"e"
- charCodeAt()
想得到的不是字符而是字符編碼
var stringValue = "hello world"; alert(stringValue.charCodeAt(1)) //"101"
- charAt()
-
字符串操作方法
這些方法都不會修改字符串本身的值付呕,它們只是返回一個基本類型的字符串值- concat()
用于將一或多個字符串拼接起來,返回拼接得到的新字符串,在實踐中一般使用加號操作符來代替 - slice(),substring(),substr()的區(qū)別
- 首先跌捆,他們都接收兩個參數(shù)徽职,slice和substring接收的是起始位置和結束位置(不包括結束位置),而substr接收的則是起始位置和所要返回的字符串長度
var test='hello world' alert(test.slice(4,7)) //"o w" alert(test.substring(4,7)) //"o w" alert(test.substr(4,7)) //"o world"
- substring是以兩個參數(shù)中較小一個作為起始位置佩厚,較大的參數(shù)作為結束位置
alert(test.substring(7,4)); //o w
- 接著姆钉,當接收的參數(shù)是負數(shù)時,slice會將它字符串的長度與對應的負數(shù)相加抄瓦,結果作為參數(shù)潮瓶;substr則僅僅是將負的第一個參數(shù)與字符串長度相加后的結果作為第一個參數(shù),而將負的第二個參數(shù)轉換為0闺鲸;substring則干脆將負參數(shù)都直接轉換為0
var test="hello world" alert(test.slice(-3)) //rld alert(test.substring(-3)) //Hello world alert(test.substr(-3)) //rld alert(test.slice(3,-4)) //lo w alert(test.substring(3,-4)) /*hel 第二點說到筋讨,substring會將較小的數(shù)作為開始位置, 將較大的數(shù)作為結束位置摸恍。*/ alert(test.substr(3,-4)) /*由于第一個參數(shù)不是負數(shù)悉罕,不轉換,依然是3立镶,但第二個參數(shù)是負數(shù)壁袄, 所以轉換為0,所以結果是一個空字符串*/
- concat()
-
字符串位置方法
- indexOf()和lastIndexOf()
參考數(shù)組的indexOf()和lastIndexOf()
var stringValue = "hello world"; alert(stringValue.indexOf("o", 6)); //7 alert(stringValue.lastIndexOf("o", 6)); //4
- indexOf()和lastIndexOf()
-
trim()方法
這個方法會創(chuàng)建一個字符串的副本媚媒,刪除前置及后綴的所有空格嗜逻,然后返回結果var stringValue = " hello world "; var trimmedStringValue = stringValue.trim(); alert(stringValue); //" hello world " alert(trimmedStringValue); //"hello world"
-
字符串大小寫的轉換寫法
var stringValue = "hello world"; alert(stringValue.toLocaleUpperCase()); //"HELLO WORLD" alert(stringValue.toUpperCase()); //"HELLO WORLD" alert(stringValue.toLocaleLowerCase()); //"hello world" alert(stringValue.toLowerCase()); //"hello world"
-
字符串的匹配模式
- match()
在字符串上調(diào)用match()方法,本質(zhì)上與調(diào)用RegExp的exec()方法相同,match()只接受一個參數(shù)缭召,要么是一個正則表達式栈顷,要么是一個RegExp對象逆日。
var text='cat,bat,sat,fat'; var pattern=/.at/; //與pattern.exec(text)相同 var matches=text.match(pattern); altert(matches.index); //0 altert(matches[0]); //"cat" altert(matches.lastIndex); //0
- search()
這個方法的唯一參數(shù)與 match() 方法的參數(shù)相同:由字符串或 RegExp 對象指定的一個正則表達式。 search() 方法返回字符串中第一個匹配項的索引萄凤;如果沒有找到匹配項室抽,則返回 -1 。而且靡努, search() 方法始終是從字符串開頭向后查找模式坪圾。
var text = "cat, bat, sat, fat"; var pos = text.search(/at/); alert(pos); //1
- replace()
這個方法接受兩個參數(shù):第一個參數(shù)可以是一個 RegExp 對象或者一個字符串(這個字符串不會被轉換成正則表達式),第二個參數(shù)可以是一個字符串或者一個函數(shù)惑朦。如果第一個參數(shù)是字符串兽泄,那么只會替換第一個子字符串。要想替換所有子字符串漾月,唯一的辦法就是提供一個正則表達式病梢,而且要指定全局( g )標志
var text = "cat, bat, sat, fat"; var result = text.replace("at", "ond"); alert(result); //"cond, bat, sat, fat" result = text.replace(/at/g, "ond"); alert(result); //"cond, bond, sond, fond"
- split()
這個方法可以基于指定的分隔符將一個字符串分割成多個子字符串,并將結果放在一個數(shù)組中栅屏。分隔符可以是字符串飘千,也可以是一個 RegExp 對象(這個方法不會將字符串看成正則表達式)。 split() 方法可以接受可選的第二個參數(shù)栈雳,用于指定數(shù)組的大小,以便確保返回的數(shù)組不會超過既定大小
var colorText = "red,blue,green,yellow"; var colors1 = colorText.split(","); //["red", "blue", "green", "yellow"] var colors2 = colorText.split(",", 2); //["red", "blue"] var colors3 = colorText.split(/[^\,]+/); //["", ",", ",", ",", ""]
5.7 單體內(nèi)置對象
5.7.1 Global對象
本書前面介紹過的那些函數(shù)缔莲,諸如 isNaN() 哥纫、 isFinite() 、parseInt() 以及 parseFloat() 痴奏,實際上全都是 Global對象的方法蛀骇。除此之外, Global 對象還包含其他一些方法
-
URI 編碼方法
encodeURI() 和 encodeURIComponent() 方法,可以對 URI(Uniform ResourceIdentifiers读拆,通用資源標識符)進行編碼擅憔,以便發(fā)送給瀏覽器。有效的 URI 中不能包含某些字符檐晕,例如空格暑诸。而這兩個 URI 編碼方法就可以對 URI 進行編碼,它們用特殊的 UTF-8 編碼替換所有無效的字符辟灰,從而讓瀏覽器能夠接受和理解个榕。
var uri = "http://www.wrox.com/illegalvalue.htm#start"; //"http://www.wrox.com/illegal%20value.htm#start" alert(encodeURI(uri)); //"http%3A%2F%2Fwww.wrox.com%2Fillegal%20value.htm%23start" alert(encodeURIComponent(uri));
使用 encodeURI() 編碼后的結果是除了空格之外的其他字符都原封不動,只有空格被替換成了%20 芥喇。而 encodeURIComponent() 方法則會使用對應的編碼替換所有非字母數(shù)字字符西采。這也正是可以對整個 URI使用 encodeURI() ,而只能對附加在現(xiàn)有 URI后面的字符串使用 encodeURIComponent()的原因所在继控。
一 般 來 說 械馆, 我 們 使 用 encodeURIComponent() 方 法 的 時 候 要 比 使 用encodeURI() 更多胖眷,因為在實踐中更常見的是對查詢字符串參數(shù)而不是對基礎 URI進行編碼。與 encodeURI() 和 encodeURIComponent() 方法對應的兩個方法分別是 decodeURI() 和decodeURIComponent() 霹崎。其中瘦材, decodeURI() 只能對使用 encodeURI() 替換的字符進行解碼。
var uri = "http%3A%2F%2Fwww.wrox.com%2Fillegal%20value.htm%23start"; //http%3A%2F%2Fwww.wrox.com%2Fillegal value.htm%23start alert(decodeURI(uri)); //http://www.wrox.com/illegal value.htm#start alert(decodeURIComponent(uri));
在第一次調(diào)用 decodeURI()輸出的結果中仿畸,只有 %20 被替換成了空格食棕。而在第二次調(diào)用 decodeURIComponent() 輸出的結果中,所有特殊字符的編碼都被替換成了原來的字符错沽,得到了一個未經(jīng)轉義的字符串簿晓。
eval()
沒什么好說的
5.7.2 Math對象
var max = Math.max(3, 54, 32, 16);
alert(max); //54
var min = Math.min(3, 54, 32, 16);
alert(min);
Math.ceil() 執(zhí)行向上舍入,即它總是將數(shù)值向上舍入為最接近的整數(shù)千埃;
Math.floor() 執(zhí)行向下舍入憔儿,即它總是將數(shù)值向下舍入為最接近的整數(shù);
Math.round() 執(zhí)行標準舍入放可,即它總是將數(shù)值四舍五入為最接近的整數(shù)(這也是我們在數(shù)學課上學到的舍入規(guī)則)谒臼。
-
random() 方法
Math.random() 方法返回大于等于 0 小于 1 的一個隨機數(shù)。如果你想選擇一個 1到 10 之間的數(shù)值耀里,可以像下面這樣編寫代碼var num = Math.floor(Math.random() * 10 + 1);
面向?qū)ο蟮某绦蛟O計
- ECMAScript中有兩種屬性:數(shù)據(jù)屬性和訪問屬性
-
數(shù)據(jù)屬性有4個特性
- [[Configurable]]
- [[Enumerable]]
- [[Writable]]
- [[Value]]
-
訪問器屬性
- [[Configurable]]
- [[Enumerable]]
- [[Get]]
- [[Set]]
定義多個屬性和讀取屬性
var book={}; //通過Object.defineProperties()方法定義屬性 Object.defineProperties(book,{ _year: { //定義數(shù)據(jù)屬性 value: 2004 } edition: { value: 1 } year: { //定義訪問器屬性 get: function(){ return this._year } set: function(){ if(newValue>2004){ this._year = newValue; this.edition += newValue - 2004; } } } }); var descriptor = Object.getOwnPropertyDescriptor(book,_year); alert(descriptor.value); //2004 alert(descriptor.configurable) /*false,因為通過Object.defineProperties() 方法創(chuàng)建一個新的屬性時蜈缤,如果不指定,configurable冯挎,enumerable和 writabale特性的默認值都是false.*/ alert(typeof desciptor.get); //undefined var descriptor = Object.getOwnPropertyDescriptor(book, "year"); alert(descriptor.value); //undefined alert(descriptor.enumerable); //false alert(typeof descriptor.get); //"function"
-
6.2 創(chuàng)建對象
6.2.1 工廠模式
用函數(shù)來封裝以特定接口創(chuàng)建對象的細節(jié)
function createPerson(name, age, job){
var o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayName = function(){
alert(this.name);
};
return o;
}
var person1 = createPerson("Nicholas", 29, "Software Engineer");
var person2 = createPerson("Greg", 27, "Doctor");
- 優(yōu)點
解決了創(chuàng)建多個相似對象的問題 - 缺點
沒有解決對象識別的問題,
alert(person1 instanceof createPerson) //false
6.2.2 構造函數(shù)模式
function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.sayName = function(){
alert(this.name);
};
}
var person1 = new Person("Nicholas", 29, "Software Engineer");
var person2 = new Person("Greg", 27, "Doctor");
- 構造函數(shù)名以大寫開頭
- 要創(chuàng)建Person實例底哥,必須使用new 操作符,person1和person2分別保存著Person的一個不同的實例房官,
- 這兩個對象都有一個 constructor (構造函數(shù))屬性趾徽,該屬性指向 Person
alert(person1.constructor == Person); //true alert(person2.constructor == Person); //true
alert(person1 instanceof Object); //true alert(person1 instanceof Person); //true alert(person2 instanceof Object); //true alert(person2 instanceof Person); //true
- 將構造函數(shù)當作函數(shù)調(diào)用
// 當作構造函數(shù)使用 var person = new Person("Nicholas", 29, "Software Engineer"); person.sayName(); //"Nicholas" // 作為普通函數(shù)調(diào)用 Person("Greg", 27, "Doctor"); // 添加到 window window.sayName(); //"Greg" // 在另一個對象的作用域中調(diào)用 var o = new Object(); Person.call(o, "Kristen", 25, "Nurse"); o.sayName(); //"Kristen"
- 存在的問題
不同實例上的同名函數(shù)是不相等的
可將sayName()函數(shù)轉移到構造函數(shù)的外部alert(person1.sayName == person2.sayName); //false
但這又使得全局作用域有點名不其實,只能被某個對象調(diào)用翰守,而且如果對象需要定義很多方法孵奶,那么就要定義很多個全局函數(shù)。function Person(name, age, job){ this.name = name; this.age = age; this.job = job; this.sayName = sayName; } function sayName(){ alert(this.name); } var person1 = new Person("Nicholas", 29, "Software Engineer"); var person2 = new Person("Greg", 27, "Doctor");
6.2.3 原型模式
- isPrototypeOf()
如果 [[Prototype]] 指向調(diào)用 isPrototypeOf() 方法的對象
( Person.prototype )蜡峰,那么這個方法就返回 truealert(Object.getPrototypeOf(person1) == Person.prototype); //true alert(Object.getPrototypeOf(person1).name); //"Nicholas"
- Object.getPrototypeOf()
返回[[Prototype]] 的值alert(Object.getPrototypeOf(person1) == Person.prototype); //true alert(Object.getPrototypeOf(person1).name); //"Nicholas"
- hasOwnProperty()
可以檢測一個屬性是存在于實例中了袁,還是存在于原型中 - Object.keys()
可取得對象上所有課枚舉的實例屬性,這個方法接受一個對象作為參數(shù)
6.2.4 組合使用構造函數(shù)模式和原型模式
創(chuàng)建自定義類型的最常見方式事示,就是組合使用構造函數(shù)模式與原型模式早像。
function Person(name,age,job){
this.name = name;
this.age = age;
this.job = job;
this.friends= ["Shely","Court"];
}
Person.prototype = {
constructor :Person,
sayName : function(){
alert(this.name);
}
}
var person1 = new Person("Nicholas",20,"Software Engineer");
var person2 = new Person("Greg", 27, "Doctor");
person1.friends.push("Van");
alert(person1.friends); //"Shelby,Count,Van"
alert(person2.friends); //"Shelby,Count"
alert(person1.friends === person2.friends); //false
alert(person1.sayName === person2.sayName); //true
6.2.5 動態(tài)原型模式
function Person(name, age, job){
//屬性
this.name = name;
this.age = age;
this.job = job;
// 方法
if (typeof this.sayName != "function"){
Person.prototype.sayName = function(){
alert(this.name);
};
}
}
var friend = new Person("Nicholas", 29, "Software Engineer");
friend.sayName();
6.2.6 寄生構造函數(shù)模式
形式上可看作是工廠模式+構造函數(shù)模式
//工廠模式
function Person(name,age,job){
var o =new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayName = function(){
alert(this.name);
}
return o;
}
//構造函數(shù)模式
var friend = new Person("Nicholas", 29, "Software Engineer");
friend.sayName() //"Nicholas"
關于寄生構造函數(shù)模式,有一點需要說明:首先肖爵,返回的對象與構造函數(shù)或者與構造函數(shù)的原型屬性之間沒有關系卢鹦;也就是說,構造函數(shù)返回的對象與在構造函數(shù)外部創(chuàng)建的對象沒有什么不同。為此冀自,不能依賴 instanceof 操作符來確定對象類型揉稚。由于存在上述問題,我們建議在可以使用其他模式的情況下熬粗,不要使用這種模式
6.2.7 穩(wěn)妥構造函數(shù)模式
穩(wěn)妥構造函數(shù)遵循與寄生構造函數(shù)類似的模式搀玖,但有兩點不同:一是新創(chuàng)建對象的實例方法不引用 this ;二是不使用 new 操作符調(diào)用構造函數(shù)
function Person(name, age, job){
//創(chuàng)建要返回的對象
var o = new Object();
//可以在這里定義私有變量和函數(shù)
//添加方法
/*除了使用sayName()方法之外驻呐,沒有其他辦法可以訪問name的值*/
o.sayName = function(){
alert(name);
};
//返回對象
return o;
}
var friend = Person("Nicholas", 29, "Software Engineer");
friend.sayName(); //"Nicholas"
6.3 繼承
- 構造函數(shù)灌诅,原型和實例的關系
每個構造函數(shù)都有一個原型對象prototype,原型對象都包含一個指向構造函數(shù)的指針constructor含末,而實例都包含一個指向原型對象的內(nèi)容指針proto猜拾。
所有函數(shù)的默認原型都是Object的實例,因此默認原型都會包含一個內(nèi)部指針佣盒,指向Object.prototype挎袜。這也正是所有自定義類型都會繼承toString(),valueOf()等默認方法的根本原因肥惭。
- 確定原型與實例的關系
- instanceof操作符
只要用這個操作符來測試實例與原型鏈中出現(xiàn)過的構造函數(shù)盯仪,結果都會返回true。
altert(instance instanceof Object); //true
- isPrototypeOf方法
只要是原型鏈中出現(xiàn)過的原型蜜葱,都可以說是該原型鏈所派的實例的原型全景,因此isPrototypeOf()方法也會返回true
altert(Object.isPrototypeOf(instance)); //true
- instanceof操作符
--- 未完待續(xù)---