7 語句
?① if
if (i > 25) {
alert(" Greater than 25.");
} else if (i < 0) {
alert(" Less than 0.");
} else {
alert(" Between 0 and 25, inclusive.");
}
?② do-while后測試循環(huán),至少運一次
do {
statement
} while (出口條件);
var i = 0;
do {
i += 2;
} while (i < 10);
alert(i);
?③ while前測試循環(huán),可能一次不運行
var i = 0;
while (i < 10) {
i += 2;
}
?④ for
for (initialization; expression; post - loop - expression) {
statement
}
var count = 10;
for (var i = 1; i < count; i++) {
alert(i);
}
?注意表達式用;號結束,初始化表達式、控制表達式和循環(huán)后表達式都是可選的,將這些表達式全部省略,就會創(chuàng)建一個無限循環(huán):
for (;;) {
// 無限 循環(huán) doSomething();
}
?⑤ for-in
?for-in語句是一種精準的迭代語句,可以用來枚舉對象的屬性,在ECMAScript對象的屬性是沒有順序的。
for (var propName in window) {
document.write(propName);
}
?⑥ label
start: for (var i = 0; i < count; i++) {
alert(i);
}
?主要作用:在嵌套循環(huán)中使用break、continue配合label可以精確地返回想要的位置:
var num = 0;
for (var i = 0; i < 10; i++) {
for (var j = 0; j < 10; j++) {
if (i == 5 && j == 5) {
break;
}
num++;
}
}
alert(num); //循環(huán)在i為5,j為5的時候跳出j循環(huán),但會繼續(xù)執(zhí)行i循環(huán),輸出95
?添加Label之后:
var num = 0;
outPoint:
for (var i = 0; i < 10; i++) {
for (var j = 0; j < 10; j++) {
if (i == 5 && j == 5) {
break outPoint;
}
num++;
}
}
alert(num); //循環(huán)在i為5,j為5的時候跳出雙循環(huán),返回到outPoint層,執(zhí)行下面的語句,輸出55
?⑦ break和continue
var num = 0;
for (var i = 1; i < 10; i++) {
if (i % 5 == 0) {
break;
}
num++;
}
alert(num); //4
?當i等于5,直接跳出循環(huán),num加到了4。
var num = 0;
for (var i = 1; i < 10; i++) {
if (i % 5 == 0) {
continue;
}
num++;
}
alert(num); //8
?當i等于5,會跳出來再從循環(huán)頭部重新以i等于5開始,再到10的時候再跳一次,此時i < 10已經(jīng)不成立了,不進入循環(huán),等到8。
?⑧ with不建議使用
var qs = location.search.substring(1);
var hostName = location.hostname;
var url = location.href;
/* 使用with簡化后 */
with(location) {
var qs = search.substring(1);
var hostName = hostname;
var url = href;
}
?⑨ switch
switch (i) {
case 25:
alert(" 25");
break;
case 35:
alert(" 35");
break;
case 45:
alert(" 45");
break;
default:
alert(" Other");
}
?在語句里break;得加上,防止發(fā)生同時執(zhí)行多個case語句。
?JS的switch語句能帶任意數(shù)據(jù)類型,甚至是對象:
switch ("hello world") {
case "hello" + " world":
alert(" Greeting was found.");
break;
case "goodbye":
alert(" Closing was found.");
break;
default:
alert(" Unexpected message was found.");
}
8 函數(shù)
?① 寫法
function sayHi(name, message) {
alert(" Hello " + name + "," + message);
}
sayHi(" Nicholas", "how are you today?");
?②return,實際上,沒有指定返回值的函數(shù)返回的是一個特殊的undefined值:
function sayHi(name, message) {
return;
alert(" Hello " + name + "," + message); //永遠不會調(diào)用
}
function sum(num1, num2) {
return num1 + num2;
}
var result = sum(5, 10);
function diff(num1, num2) {
if (num1 < num2) {
return num2 - num1;
} else {
return num1 - num2;
}
}
?③ 傳遞參數(shù)有無,數(shù)據(jù)類型任意都可,原因是ECMAScript中的參數(shù)在內(nèi)部是用一個數(shù)組來表示的;還通過arguments可以查看傳進的參數(shù):
function doAdd() {
if (arguments.length == 1) {
alert(arguments[0] + 10);
} else if (arguments.length == 2) {
alert(arguments[0] + arguments[1]);
}
}
doAdd(10); //20
doAdd(30, 20); //50
?還可以同時使用傳參與arguments,arguments[0]對應num1:
function doAdd(num1, num2) {
if (arguments.length == 1) {
alert(num1 + 10);
} else if (arguments.length == 2) {
alert(arguments[0] + num2);
}
}
?給傳參賦值:
function doAdd(num1, num2) {
arguments[1] = 10;
alert(arguments[0] + num2);
}
?還有些要注意的事情,例如,如果只給doAdd()函數(shù)傳遞了一個參數(shù),則num2中就會保存undefined值。這種賦值方法在嚴格模式下不起作用。
?④ 沒有重載:
function addSomeNumber(num) {
return num + 100;
}
function addSomeNumber(num) {
return num + 200;
}
var result = addSomeNumber(100); //300 FunctionExample10.
?不過可以用檢查arguments的方法,模仿重載,讓一個函數(shù)有兩個定義。
9 變量、作用域與內(nèi)存問題
?① 變量 ★
?ECMAScript變量可能包含兩種不同數(shù)據(jù)類型的值:基本類型值和引用類型值;基本類型是按值訪問的,因為可以操作保存在變量中的實際的值;引用類型的值是保存在內(nèi)存中的對象。與其他語言不同,JavaScript不允許直接訪問內(nèi)存中的位置,也就是說不能直接操作對象的內(nèi)存空間。在操作對象時,實際上是在操作對象的引用而不是實際的對象。為此,引用類型的值是按引用訪問的。
?引用類型與基本類型的差異:
?1> 動態(tài)賦值:
var person = new Object();
person.name = "Nicholas";
alert(person.name); //"Nicholas"
var name = "Nicholas";
name.age = 27;
alert(name.age); //undefined
?2> 復制變量值:
var num1 = 5;
var num2 = num1;
num1 = 4;
alert(num2); //5
var obj1 = new Object();
var obj2 = obj1;
obj1.name = "Nicholas";
alert(obj2.name); //"Nicholas"
?3> 作為傳參時,函數(shù)的參數(shù)都是按值傳遞的:
function addTen(num) {
num += 10;
return num;
}
var count = 20;
var result = addTen(count);
alert(count); //20,不影響作為傳參的count
alert(result); //30
function setName(obj) {
obj.name = "Nicholas";
}
var person = new Object();
setName(person);
alert(person.name); //"Nicholas"
function setName(obj) {
obj.name = "Nicholas";
obj = new Object();
obj.name = "Greg";
/* 在函數(shù)里重寫obj時,obj會指向一個新的Object,而且這個變量引用的是一個局部變量,會在函數(shù)執(zhí)行完后被銷毀 */
}
var person = new Object();
setName(person);
alert(person.name); //"Nicholas"
?3> 檢測變量類型:
?typeof操作符是確定一個變量是字符串、數(shù)值、布爾值,還是undefined的最佳工具。
?instanceof操作符用于檢查對象是何類型,返回布爾值:
alert(person instanceof Object); // 變量 person 是 Object 嗎?
alert(colors instanceof Array); // 變量 colors 是 Array 嗎?
alert(pattern instanceof RegExp); // 變量 pattern 是 RegExp 嗎?
?② 執(zhí)行環(huán)境與作用域 ★:
?1> ES6之前只有全局作用域與函數(shù)作用域;
?2> 每個執(zhí)行環(huán)境都有一個與之關聯(lián)的變量對象(variableobject),環(huán)境中定義的所有變量和函數(shù)都保存在這個對象中;
?3> 每個函數(shù)都有自己的執(zhí)行環(huán)境。當執(zhí)行流進入一個函數(shù)時,函數(shù)的環(huán)境就會被推入一個環(huán)境棧中。而在函數(shù)執(zhí)行之后,棧將其環(huán)境彈出,把控制權返回給之前的執(zhí)行環(huán)境。ECMAScript程序中的執(zhí)行流正是由這個方便的機制控制著;
?4> 當代碼在一個環(huán)境中執(zhí)行時,會創(chuàng)建變量對象的一個作用域鏈,作用域鏈的前端始終是當前代碼執(zhí)行的變量對象,鏈子上后一個的變量對象是包含當前變量對象的變量對象,以此類推,自至到全局執(zhí)行環(huán)境;
var color = "blue";
function changeColor() {
var anotherColor = "red";
function swapColors() {
var tempColor = anotherColor;
anotherColor = color;
color = tempColor;
/* 這里可以訪問color、anotherColor和tempColor */
}
/* 這里可以訪問color和anotherColor,但不能訪問tempColor */
swapColors();
}
/* 這里只能訪問color */
changeColor();
?5> 有些語句可以在作用域的前端臨時增加一個變量對象,比如with語句和try-catch語句的catch塊,前者把填入的變量對象增加到作用域的前端,后者把錯誤對象添加到前端。
?6> 在ES6之前,JavaScript沒有塊級作用域;在其他類型的語言中,連由花括號封閉的代碼塊都有自己的作用域。
?7> 使用var聲明的變量會自動被添加到最接近的環(huán)境中。在函數(shù)內(nèi)部,最接近的環(huán)境就是函數(shù)的局部環(huán)境;在with語句中,最接近的環(huán)境是函數(shù)環(huán)境。如果初始化變量時沒有使用var聲明,該變量會自動被添加到全局環(huán)境。
?③ 垃圾收集
?JS具有自動垃圾回收機制,通過以下幾種方法去判斷是否可以回收:
?1> 標記清除(mark-and-sweap),最常用的,當代碼執(zhí)行時,會將已存儲在內(nèi)存中的所有變量加上標記,然后每每進入一個環(huán)境都會去掉環(huán)境中的變量和被環(huán)境中的變量引用的變量的標記,然后其余的變量都被視為準備刪除的變量;
?2> 引用計數(shù)(reference counting),不太常見,當聲明一個變量并將一個引用類型值賦給該變量時,則這個值的引用次數(shù)就是1。如果同一個值又被賦給另一個變量,則該值的引用次數(shù)加1。相反,如果包含對這個值引用的變量又取得了另外一個值,則這個值的引用次數(shù)減1。當這個值的引用次數(shù)變成0時,會在垃圾回收機制觸發(fā)時被銷毀;
?3> 垃圾回收機制觸發(fā)靠的是判斷是否達到動態(tài)修正的一個瀏覽器內(nèi)存分配量的臨界值,也可以手動觸發(fā),比如IE的window.CollectGarbage()。
?④ 手動內(nèi)存管理,太騷氣了...
?1> 把值設置為null來釋放其引用:
function createPerson(name) {
var localPerson = new Object();
localPerson.name = name;
return localPerson;
}
var globalPerson = createPerson(" Nicholas");
globalPerson = null; // 手動解除globalPerson的引用
10 引用類型
?① 對象類型:
?1> 創(chuàng)建Object實例的兩種方法:
var person = new Object();
person.name = "Nicholas";
person.age = 29;
var person = {
name: "Nicholas",
age: 29
};
var person = {}; //與new Object()相同
person.name = "Nicholas";
person.age = 29;
?2> 關于對象字面量語法,我們推薦只在考慮對象屬性名的可讀性時使用。
?3> 使用對象字面量作為參數(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"
});
?4> 訪問對象屬性的兩種方法:
alert(person["name"]); //"Nicholas"
?等價于:
alert(person.name); //"Nicholas"
?等價于:
var propertyName = "name";
alert(person[propertyName]); //"Nicholas"
?如果對象屬性名帶有空格,那只能用方括號表示法:
person.first name = "Nicholas";// 點表示法不能帶空格,會保錯
person["first name"] = "Nicholas";// 方括號表示法可以
?② Array類型 ★
var colors = new Array(3); // 創(chuàng)建一個包含3項的數(shù)組var
names = new Array(" Greg"); // 創(chuàng)建一個包含1項,即字符串"Greg"的數(shù)組
?1> Array類型也有數(shù)組字面量表示法:
var colors = ["red", "blue", "green"]; // 創(chuàng)建一個包含3個字符串的數(shù)組
var names = []; // 創(chuàng)建一個空數(shù)組
var values = [1, 2,]; // 不要這樣!這樣會創(chuàng)建一個包含2或3項的數(shù)組
var options = [,,,,,]; // 不要這樣!這樣會創(chuàng)建一個包含5或6項的數(shù)組
?2> 與對象一樣,在使用數(shù)組字面量表示法時,也不會調(diào)用Array構造函數(shù),會節(jié)約性能;
?3> 讀取和修改數(shù)組
var colors = ["red", "blue", "green"]; // 定義一個符串數(shù)組
alert(colors[0]); // 顯示第一項
colors[2] = "black"; // 修改第三項
colors[3] = "brown"; // 新增第四項
var colors = ["red", "blue", "green"]; // 創(chuàng)建一個包含3個字符串的數(shù)組
var names = []; // 創(chuàng)建一個空數(shù)組
alert(colors.length); // 3
alert(names.length); // 0
?4> 通過length屬性可以去訪問數(shù)組末尾項,可以新增、修改和刪除:
var colors = ["red", "blue", "green"]; // 創(chuàng)建一個包含3個字符串的數(shù)組
colors.length = 2; // 把數(shù)組長度變?yōu)?,變相刪除末尾項
alert(colors[2]); //undefined
var colors = ["red", "blue", "green"]; // 創(chuàng)建一個包含3個字符串的數(shù)組
colors[colors.length] = "black"; //(在位置3)添加一種顏色
colors[colors.length] = "brown"; //(在位置4)再添加一種顏色
?5> 檢測數(shù)組
if (Array.isArray(value)) {
// 判斷是否為數(shù)組
// 對數(shù)組執(zhí)行某些操作
}
?6> 如前所述,所有對象都具有toLocaleString()、toString()和valueOf()方法,對數(shù)組應用這些方法時,toString()和valueOf()得到的值是相同的字符串,實際上,為了創(chuàng)建這個字符串會調(diào)用數(shù)組每一項的toString()方法,用alert輸出數(shù)組也會在后臺調(diào)用toString():
var colors = ["red", "blue", "yellow"];
alert(colors.toString()); // red,blue,yellow
alert(colors.valueOf()); // red,blue,yellow
alert(colors); // red,blue,yellow
?用toLocaleString()有時候會返回和用toString()、valueOf()方法不一樣的值,因為toLocaleString()是對數(shù)組每一項調(diào)用toLocaleString()方法。我們在數(shù)組里重寫toLocaleString()和toString()測試下:
var person1 = {
toLocaleString: function() {
return "Nikolaos";
},
toString: function() {
return "Nicholas";
}
};
var person2 = {
toLocaleString: function() {
return "Grigorios";
},
toString: function() {
return "Greg";
}
};
var people = [person1, person2];
alert(people); //Nicholas, Greg
alert(people.toString()); //Nicholas, Greg
alert(people.toLocaleString()); //Nikolaos, Grigorios
?關于join()方法,用于重現(xiàn)toString(),代入的參數(shù)是什么分隔符,就可以得到什么樣的字符串:
var colors = ["red", "green", "blue"];
alert(colors.join(",")); // red,green,blue
alert(colors.join("||")); // red||green||blue
?7> 數(shù)組還有種棧方法可以讓數(shù)組的行為表現(xiàn)得像棧(后進先出)一樣,方法有兩:push()(接收任意數(shù)量的參數(shù),把它們逐一添加到數(shù)組末尾,再返回修改后的數(shù)組長度)和pop()(移除數(shù)組最后一項,數(shù)組長度減一,)。
var colors = new Array(); // 創(chuàng)建一個數(shù)組
var count = colors.push(" red", "green"); // 推入兩項
alert(count); // 2
count = colors.push(" black"); // 推入另 一項
alert(count); // 3
var item = colors.pop(); // 取得最后一項
alert(item); // "black"
alert(colors.length); // 2
?8> 數(shù)組還還有種隊列方法可以讓數(shù)組的行為表現(xiàn)得像隊列(先進先出)一樣,方法有三:push()(因為隊列和棧都是從列表的末端添加項)、shift()(移除數(shù)組的第一項,返回該項,同時長度減一),unshift()(往數(shù)組的頭部添加任意項,返回數(shù)組長度):
var colors = new Array(); // 創(chuàng)建一個數(shù)組
var count = colors.unshift(" red", "green"); // 推入兩項
alert(count); // 2
count = colors.unshift(" black"); // 推入另一項
alert(count); //3
var item = colors.pop(); // 取得最后一項
alert(item); //"green"
alert(colors.length); // 2
?注意上面輸出green,表明unshift()推入項的順序
?9> reverse()和sort(),reverse()用來反轉數(shù)組項的順序,sort()更加靈活,可以按升序排列數(shù)組,最小的在前面,最大的排在后面,sort()方法會對數(shù)組每個項調(diào)用toString(),再比較它的字符串,即便它是數(shù)值:
var values = [0, 1, 5, 10, 15];
values.sort();
alert(values); // 0, 1, 10, 15, 5
?由于比較的是字符串,所以, 不一定返回我們想當然的結果,就像上面的例子,"5"在"15"和"10"前面,為了得到準確的結果,可以往sort()里加一個比較函數(shù),比較函數(shù)接受兩個參數(shù),返回結果有3種,如果第一個參數(shù)應該在第二個參數(shù)后面,返回正數(shù);如果在前面,返回負數(shù);兩數(shù)相等,返回0。示例如下:
function compare(value1, value2) {
if (value1 < value2) {
return -1;
} else if (value1 > value2) {
return 1;
} else {
return 0;
}
}
代入sort()后:
var values = [0, 1, 5, 10, 15];
values.sort(compare);
alert(values); // 0, 1, 5, 10, 15
?10> concat(),可以往原有數(shù)組里加參數(shù)變成新的數(shù)組,并返回新數(shù)組:
var colors = ["red", "green", "blue"];
var colors2 = colors.concat(" yellow", ["black", "brown"]);
alert(colors); // red, green, blue
alert(colors2); // red, green, blue, yellow, black, brown
?11> slice(),用原有數(shù)組的項組成新的數(shù)組,并返回新數(shù)組,傳入的兩個參數(shù)為起始位置與終止位置:
var colors = ["red", "green", "blue", "yellow", "purple"];
var colors2 = colors.slice(1); //不傳入終止位置,默認為數(shù)組的長度-1
var colors3 = colors.slice(1, 4);
alert(colors2); //green, blue, yellow, purple
alert(colors3); //green, blue, yellow
?12> splice(),超常用,始終返回一個包含被刪除項的數(shù)組 ★
var colors = ["red", "green", "yellow", "blue", "black"];
colors.splice(0, 1);
alert(colors); // green,yellow,blue,black
colors.splice(0, 2);
alert(colors); // blue,black
colors.splice(0, 0, "red", "green");
alert(colors); // red,green,blue,black
colors.splice(2, 0, "yellow");
alert(colors); // red,green,yellow,blue,black
var remove = colors.splice(1, 2, "green1", "yellow1");
alert(colors); // red,green1,yellow1,blue,black
alert(remove); // green,yellow
?13> indexOf()(從前面往后找)和lastIndexOf()(從后面找起)用于查找特定項在數(shù)組中的位置,后臺比較用的是===:
var colors = ["red", "green", "yellow", "red", "blue", "black"];
alert(colors.indexOf("red")); // 0
alert(colors.lastIndexOf("red")); // 3
alert(colors.lastIndexOf("white")); // -1
var ball = {
color: "white"
}
var ball1 = {
color: "black"
}
var balls = [{
color: "white"
}];
alert(balls.indexOf(ball)); // -1
var balls1 = [ball1, ball];
alert(balls1.indexOf(ball)); // 1
?14> 迭代方法:every() filter() forEach() map() some(),每個方法都接受兩個參數(shù),一是對數(shù)組每一項都運行的函數(shù),二是該函數(shù)的作用域(會影響this的值,該參數(shù)可選用),另外作為參數(shù)的函數(shù)要接收這三個參數(shù),數(shù)組項的值、該項在數(shù)組中的位置和數(shù)組對象本身:★
?every() some(),返回布爾值:
var numbers = [1, 2, 3, 4, 5, 6];
alert(numbers.every(function(item, index, array) {
return (item > 3);
}));
alert(numbers.some(function(item, index, array) {
return (item > 3);
}));
?filter(),返回符合條件項組成的數(shù)組;map(),返回被傳入函數(shù)操作過后的每一項組成的數(shù)組:
var numbers = [1, 2, 3, 4, 5, 6];
alert(numbers.filter(function(item, index, array) {
return (item > 3);
}));
alert(numbers.map(function(item, index, array) {
return (item + 3);
}));
?forEach(),沒有返回值,只是對每一項運行傳入?yún)?shù):
var numbers = [1, 2, 3, 4, 5, 6];
var sum = 0;
function foo(item, index, array) {
sum += item;
}
numbers.forEach(foo);
alert(sum); // 21
?15> reduce() reduceRight(),這兩個方法都會迭代數(shù)組的所有項,然后構建一個最終返回的值;方法接受兩個參數(shù):傳入的函數(shù)(接收4個參數(shù),前一個值、當前值、項的索引和數(shù)組對象,而且函數(shù)返回的值會作為下一項的第一個參數(shù))和(可選的)作為縮小基礎的初始值。
?第一次迭代反生在數(shù)組的第二項,因此第一個參數(shù)是數(shù)組的第一項,第二個參數(shù)就是數(shù)組的第二項:
var numbers = [1, 2, 3, 4, 5, 6];
function bar(prev, cur, index, array) {
return prev + cur;
}
alert(numbers.reduce(bar));// 21
?reduceRight()只是換了個方向的reduce()方法,從數(shù)組后面開始迭代:
?③ Date類型
?Date類型使用自UTC(CoordinatedUniversalTime,國際協(xié)調(diào)時間)1970年1月1日午夜(零時)開始經(jīng)過的毫秒數(shù)來保存日期。
var now = new Date(); //不傳入?yún)?shù),默認返回當前時間
?1> Date.parse(),返回轉換后的毫秒數(shù):
var someDate = new Date(Date.parse("july 29, 2019"));
var someDate1 = new Date("july 29, 2019"); // 后臺調(diào)用Date.parse,等同于上一行
?2> Date.UTC():
// GMT 時間 2000 年 1 月 1 日 午夜 零時
var y2k = new Date(Date.UTC(2000, 0));
// GMT 時間 2005 年 5 月 5 日 下午 5: 55: 55
var allFives = new Date(Date.UTC(2005, 4, 5, 17, 55, 55));
// 本地 時間 2000 年 1 月 1 日 午夜 零時
var y2k = new Date(2000, 0); // 如果第一個是年份,后臺調(diào)用Date.UTC
// 本地 時間 2005 年 5 月 5 日 下午 5: 55: 55
var allFives = new Date(2005, 4, 5, 17, 55, 55);
?3> 用于分析代碼運行時間:
//取得開始時間
var start = Date.now();
//調(diào)用函數(shù)
doSomething();
//取得停止時間
var stop = Date.now(),
result = stop– start;
?4> 與其他引用類型一樣,Date類型也重寫了toLocaleString()、toString()和valueOf()方法,還有一些把日期格式格式化成特定字符串方法,如toDateString() toTimeString() toLocalDateString() toLocalTimeString() toUTCString,toDateString()和toString()是一樣的:
var now = new Date();
alert(now.toString()); // Mon Jul 29 2019 21:08:54 GMT+0800 (中國標準時間)
alert(now.toUTCString()); // Mon, 29 Jul 2019 13:08:54 GMT
alert(now.toLocaleDateString()); // 2019/7/29
alert(now.toTimeString()); // 21:08:54 GMT+0800 (中國標準時間)
alert(now.toLocaleTimeString()); // 下午9:08:54
alert(now.toDateString()); // Mon Jul 29 2019
?還有一些別的格式化方法,如下:

?④ RegExp類型
var expression = / pattern / flags;
?1> pattern部分是正則表達式,flags為標識,用以標明正則表達式的行為;構建方法也有兩種,但其實都會創(chuàng)建一個RegExp實例;實例有著內(nèi)置屬性;元字符需要轉義:
var pattern1 = /\[bc\] at/i;
alert(pattern1.global); //false
alert(pattern1.ignoreCase); //true
alert(pattern1.multiline); //false
alert(pattern1.lastIndex); //0
alert(pattern1.source); //"\[bc\] at"
var pattern2 = new RegExp("\\[ bc\\] at", "i");
alert(pattern2.global); //false
alert(pattern2.ignoreCase); //true
alert(pattern2.multiline); //false
alert(pattern2.lastIndex); //0
alert(pattern2.source); //"\[bc\] at"
?2> exec()是RegExp實例常用的方法:
var text = "I am a rookie";
var pattern = /I( am( a rookie)?)?/gi; // ?表示匹配前面的子表達式零次或一次
var matches = pattern.exec(text);
alert(matches[0]); // I am a rookie
alert(matches[1]); // am a rookie
alert(matches[2]); // a rookie
?捕獲組可以通過從左到右計算其開括號來編號 。例如,在表達式 (A)(B(C)) 中,存在四個這樣的組:
?在
g標識符下每次調(diào)用exec()都會返回字符串中的下一個匹配項,直至搜索到字符串末尾為止,lastIndex的值也會在每次調(diào)用exec()后都會增加:
var text = "cat, bat, sat, fat";
var pattern1 = /.at/;
var matches = pattern1.exec(text);
alert(matches.index); //0
alert(matches[0]); //cat
alert(pattern1.lastIndex); //0
matches = pattern1.exec(text);
alert(matches.index); //0
alert(matches[0]); //cat
alert(pattern1.lastIndex); //0
var pattern2 = /.at/g;
var matches = pattern2.exec(text);
alert(matches.index); //0
alert(matches[0]); //cat
alert(pattern2.lastIndex); //0
matches = pattern2.exec(text);
alert(matches.index); //5
alert(matches[0]); //bat
alert(pattern2.lastIndex); //8
?2> test()
var text = "000-00-0000";
var pattern = /\d{3}-\d{2}-\d{4}/;
if (pattern.test(text)) {
alert(" The pattern was matched.");
}
?2> toString()和 toLocalString()
var pattern = new RegExp("\\[bc\\]at","gi");
alert(pattern.toString()); // /\[bc\]at/gi
alert(pattern.toLocaleString()); // /\[bc\]at/gi
?④ Function類型 ★
?1> 每個函數(shù)都是Function類型的實例,函數(shù)名是指向?qū)嵗瘮?shù)指針,ECMAScript中沒有函數(shù)重載的概念,定義方法如下:
function sum(num1, num2) {
return num1 + num2;
}
var sum = 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
?2> 函數(shù)聲明會被解析器提升到源代碼樹的頂部,至于函數(shù)表達式var foo = new function(){...},則必須等到解析器執(zhí)行到它所在的代碼行,才會真正被解釋執(zhí)行:
alert(sum(10, 10));// 20
function sum(num1, num2) {
return num1 + num2;
}
?3> 函數(shù)作為函數(shù)的參數(shù):
function callSomeFunction(someFunction, someArgument) {
return someFunction(someArgument);
}
function add(item) {
return item + 10;
}
alert(callSomeFunction(add, 10));
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 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
?4> 函數(shù)內(nèi)部屬性 ★
?在函數(shù)內(nèi)部,有兩個特殊的對象:
?arguments(類數(shù)組對象,包含著傳入函數(shù)中的所有參數(shù)),其中arguments.callee屬性指向擁有這個argument的函數(shù):
function factorial(num) {
if (num <= 1) {
return 1;
} else {
return num * factorial(num - 1)
}
}
?為了消除與函數(shù)名factorial的耦合,改寫后:
function factorial(num) {
if (num <= 1) {
return 1;
} else {
return num * arguments.callee(num - 1)
}
}
var trueFactorial = factorial;
factorial = function() {
return 0;
};
alert(trueFactorial(5)); //120
alert(factorial(5)); //0
?arguments.callee.caller提供更好的解耦,它保存著調(diào)用當前函數(shù)的函數(shù)的引用:
function outer() {
inner();
}
function inner() {
alert(arguments.callee.caller);
}
outer();
?this(引用的是函數(shù)據(jù)以執(zhí)行的環(huán)境對象,當在網(wǎng)頁的全局作用域中調(diào)用函數(shù)時,this對象引用的就是window):
window.color = "red";
var o = {
color: "blue"
};
function sayColor() {
alert(this.color);
}
sayColor(); // red
o.sayColor = sayColor; // 添加sayColor方法給o
o.sayColor(); // blue
?length,表示函數(shù)希望接收的參數(shù)個數(shù):
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
?5> 函數(shù)內(nèi)的方法 ★
?apply(),內(nèi)置于函數(shù),用于在特定的作用域調(diào)用函數(shù);接受兩個參數(shù),一個是在其中運行函數(shù)的作用域,另一個是參數(shù)數(shù)組:
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]); // 傳入數(shù)組
}
alert(callSum1(10, 10)); //20
alert(callSum2(10, 10)); //20
?call()與apply()的作用一樣,區(qū)別在于接收的參數(shù)不同,除了this值,其余的參數(shù)都得一個個列出來:
function sum(num1, num2) {
return num1 + num2;
}
function callSum(num1, num2) {
return sum.call(this, num1, num2);
}
alert(callSum(10, 10)); //20
?call()與apply()真正強大的地方是使對象不需要與方法有任何耦合關系,比如修改之前那個例子,不用再把sayColor()方法復制給o:
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ù)的實例,這個函數(shù)的this值會被綁定到所傳入函數(shù):
window.color = "red";
var o = {
color: "blue"
};
function sayColor() {
alert(this.color);
}
var objectSayColor = sayColor.bind(o);
objectSayColor(); //blue
?⑤ 相似的基本包裝類型:Boolean、Number和String ★
?1> 實際上,每當讀取一個基本類型值的時候,后臺就會創(chuàng)建一個對應的基本包裝類型的對象實例,從而讓我們使用一些方法去操縱數(shù)據(jù),而且每次使用完都會銷毀這個實例:
var s1 = "some text";
var s2 = s1.substring(2);
var s1 = "some text";
s1.color = "red";// 運行結束后,實例對象被銷毀
alert(s1.color); //undefined,因為這個是新建的實例,不帶color屬性
?等同于:
var s1 = new String(" some text");
var s2 = s1.substring(2);
s1 = null;,
?2> Object構造函數(shù)也會像工廠方法一樣,根據(jù)傳入值的類型返回相應基本包裝類型的實例:
var obj = new Object(" some text");
alert(obj instanceof String); //true
?2> 使用new調(diào)用基本包裝類型的構造函數(shù),與直接調(diào)用同名的轉型函數(shù)是不一樣的:
var value = "25";
var number = Number(value); //轉型函數(shù),把字符串轉為數(shù)值,number保存的是數(shù)值
alert(typeof number); //"number"
var obj = new Number(value); //構造函數(shù),保存的是實例
alert(typeof obj); //"object"
?3> 這些類型都重寫了valueOf(),toString(),toLocalString()方法。
?4> Boolean類型需要注意的是,Boolean類型實例與bool值的區(qū)別:
var falseObject = new Boolean(false);
var result = falseObject && true;
alert(result); //true,因為所有對象轉化成bool值是true
var falseValue = false;
result = falseValue && true;
alert(result); //false
?5> Number類型
var numberObject = new Number(10);
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"
alert(num.toFixed(2)); //"10.00",toFixed會按照參數(shù)返回指定小數(shù)點位的數(shù)值
var num1 = 10.005;
alert(num1.toFixed(2)); //"10.01",還可以四舍五入
alert(num.toExponential(1)); //"1.0e+1",e表示法
// toPrecision方法返回參數(shù)指定位數(shù)的數(shù)組,還可以自動選擇最合適的表達方式
var num3 = 99;
alert(num3.toPrecision(1)); //"1e+ 2",一位數(shù)表達99的表達法
alert(num3.toPrecision(2)); //"99"
alert(num3.toPrecision(3)); //"99. 0"
var numberObject = new Number(10);
var numberValue = 10;
alert(typeof numberObject); //"object"
alert(typeof numberValue); //"number"
alert(numberObject instanceof Number); //true
alert(numberValue instanceof Number); //false
?6> String類型
var stringValue = "hello world";
alert(stringValue.charAt(1)); //"e"
alert( stringValue. charCodeAt( 1)); //輸出" 101",101是小寫e的字符編碼
alert(stringValue[1]); //"e"
var stringValue = "hello ";
var result = stringValue.concat(" world");
alert(result); //"hello world"
alert(stringValue); //"hello"
?字符操作方法(返回新字符串),slice()、substring()和substr():
var stringValue = "hello world";
alert(stringValue.slice(3)); //"lo world"
alert(stringValue.substring(3)); //"lo world"
alert(stringValue.substr(3)); //"lo world"
alert(stringValue.slice(3,7)); //"lo w" ,第一個參數(shù)都是起始位置
alert(stringValue.substring(3,7)); //"lo w",slice()和substring()的第二個參數(shù)指定的是子字符串最后一個字符的位置
alert(stringValue.substr(3,7)); //"lo worl",第二個參數(shù)指定的是返回的字符個數(shù)
var stringValue = "hello world";
alert(stringValue.slice(-3)); //"rld"
alert(stringValue.substring(-3)); //"hello world"
alert(stringValue.substr(-3)); //"rld"
alert(stringValue.slice(3,-4)); //"lo w"
alert(stringValue.substring(3,-4)); //"hel"
alert(stringValue.substr(3,-4)); //""( 空字符串)
?位置方法,indexOf()和lastIndexOf():
var stringValue = "hello world";
alert(stringValue.indexOf("o")); //4
alert(stringValue.lastIndexOf("o")); //7
alert(stringValue.indexOf("o",6)); //7
alert(stringValue.lastIndexOf("o",6)); //4
var stringValue = "Lorem ipsum dolor sit amet, consectetur adipisicing elit";
var positions = new Array();
var pos = stringValue.indexOf("e");
while (pos > -1) {
positions.push(pos);
pos = stringValue.indexOf("e", pos + 1);
}
alert(positions); //"3, 24, 32, 35, 52"
?trim()去除前面和后面空格:
var stringValue = " hello world ";
var trimmedStringValue = stringValue.trim();
alert(stringValue); //" hello world "
alert(trimmedStringValue); //"hello world"
?toLowerCase()、toLocaleLowerCase()、toUpperCase()和toLocaleUpperCase()用于轉換大小寫。
?match()匹配方法,返回一個數(shù)組:
var text = "cat,bat,sat,fat";
var pattern = /.at/;
//與pattern.exec(text)相同
var matches = text.match(pattern);
alert(matches.index); //0
alert(matches[0]); //"cat"
alert(pattern.lastIndex); //0,lastIndex:是RegExp的屬性,一個可讀/寫的整數(shù),如果匹配模式中帶有g修飾符,這個屬性存儲在整個字符串中下一次檢索的開始位置
?search(),這個方法的唯一參數(shù)與match()方法的參數(shù)相同,返回字符串中第一個匹配項的索引:
var text = "cat, bat, sat, fat";
var pos = text.search(/at/);
alert(pos); //1
?replace(),第二參數(shù)可以是一個函數(shù)或者一串字符串 ★:
var text = "cat, bat, sat, fat";
result = text.replace(/(.at)/g, "word ($1)");
alert(result); //word (cat), word (bat), word (sat), word (fat)
function htmlEscape(text) {
return text.replace(/[<>"&]/g,
function(match, pos, originalText) {
switch (match) {
case "<":
return "<";
case ">":
return ">";
case "&":
return "&";
case "\"":
return """;
}
});
}
alert(htmlEscape("<p class=\" greeting\"> Hello world!</p>")); //< p class=& quot; greeting& quot;& gt; Hello world!& lt;/ p& gt;
?最后一個匹配方法split():
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(/[^\,]+/); //["",",",",",",",""]
?剩下與String類型有關的幾個方法:
?localeCompare(),比較字符串,根據(jù)在字母表的順序返回數(shù)字1(或正數(shù))、-1(或負數(shù))、0(相等)。
?fromCharCode(),接收一到多個字符編碼,轉化成一個字符串。
?⑤ Global對象,所有在全局作用域中定義的屬性和函數(shù),都是Global對象的屬性;window對象在Web瀏覽器中,是對Global對象的一種實現(xiàn),而且Global只是window對象的一部分。
?⑥ Math對象
?1> 屬性:
?2> 方法:
?
max() min():
var max = Math.max(3, 54, 32, 16);
alert(max); //54
var min = Math.min(3, 54, 32, 16);
alert(min); //3
?ceil() floor() round(),舍入方法:
alert(Math.ceil(25.9)); //26
alert(Math.ceil(25.5)); //26
alert(Math.ceil(25.1)); //26
alert(Math.round(25.9)); //26
?random():
值 = Math.floor(Math. random() * 可能值的總數(shù) + 第一個可能的值)
?返回1到10的數(shù)值:
var num = Math.floor(Math.random() * 10 + 1);
?其他方法:
11 面向?qū)ο蟮腏S
?① 一次定義多個屬性,defineProperties:
var book = {};
Object.defineProperties(book, {
_year: {
value: 2004
},
edition: {
value: 1
},
year: {
get: function() {
return this._ year;
},
set: function(newValue) {
if (newValue > 2004) {
this._ year = newValue;
this.edition += newValue - 2004;
}
}
}
});
?下面是幾種創(chuàng)建對象的方法與其的優(yōu)缺點:
?② 構造函數(shù)模式
?構造函數(shù)模式,構造函數(shù)應始終都應該以一個大寫字母開頭,而非構造函數(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ù)可以當普通函數(shù)使用:
// 當構造函數(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ù)的缺點:每次創(chuàng)建實例都會為實例新建一個方法,而且不是同一個方法的實例:
alert(person1.sayName == person2.sayName); //false
?可以這么改寫:
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");
?③ 原型模式
function Person() {}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function() {
alert(this.name);
};
var person1 = new Person();
person1.sayName(); //"
Nicholas " var person2 = new Person(); person2. sayName(); //"
Nicholas "
alert(person1.sayName == person2.sayName); //true
?在上面,我們注意到在為原型對象添加屬性時,需要每個都增加Person.prototype,這個工作很重復,可以改成更簡單的語法:
function Person() {}
Person.prototype = {
name: "Nicholas",
age: 29,
job: "Software Engineer",
sayName: function() {
alert(this.name);
}
};
?原型模式的缺點:假如原型有引用類型,假如是數(shù)組,那么所有的實例里面的數(shù)組都指向同一個數(shù)組。

?④ 混合模式 ★★
?創(chuàng)建自定義類型的最常見方式,就是組合使用構造函數(shù)模式與原型模式。構造函數(shù)模式用于定義實例屬性,而原型模式用于定義方法和共享的屬性,這樣我們就可以傳遞不同的參數(shù)來創(chuàng)建出不同的對象,同時又擁有了共享的方法和屬性:
function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.friends = ["Shelby", "Court"];
}
Person.prototype = {
constructor: Person,
sayName: function() {
alert(this.name);
}
}
var person1 = new Person(" Nicholas", 29, "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
?⑤ 動態(tài)原型模式——將原型方法和構造函數(shù)封裝到一塊★★★
function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.friends = ["Shelby", "Court"];
if (typeof this.sayHi != "function") {
Person.prototype.sayHi = function() {
alert("hi,i am " + this.name);
}
}// 這段判斷語句的作用是限制Person.prototype屬性(原型屬性對象)只生成一次,要不然每次實例化一個Person對象都會去寫一遍原型對象!!!!!
}
var lee = new Person("lee", 17, "student");
var jack = new Person("jack", 28, "doctor");
lee.friends.push("dand");
lee.sayHi(); // hi,i am lee
alert(lee.friends); // Shelby,Court,dand
jack.sayHi(); // hi,i am jack
alert(jack.friends); // Shelby,Court
?⑥ 寄生構造函數(shù)模式——假設我們想創(chuàng)建一個具有額外方法的特殊數(shù)組。由于不能直接修改Array構造函數(shù),所以我們可以使用寄生模式:
function SpecialArray() {
//創(chuàng)建數(shù)組
var array=new Array();
//添加值 arguments獲取的是實參,不是形參,所以SpecialArray()并沒有形參接收傳遞過來的參數(shù)
array.push.apply(array,arguments);
array.toPipedString=function(){
return this.join("|");
}
return array;
}
var colors=new SpecialArray("red","blue","black");
alert(colors.toPipedString()); //輸出:red|blue|black
?⑦ 穩(wěn)妥構造函數(shù)模式,所謂穩(wěn)妥對象,指的是沒有公共屬性,而且其方法也不引用this的對象。:
function Person(name,age) {
//創(chuàng)建要返回的對象
var o=new Object();
//可以在這里定義私有變量和函數(shù)
//添加方法
o.sayName=function(){
alert(name);
}
//返回對象
return o;
}
var person=Person("張三",22);
person.sayName(); //使用穩(wěn)妥構造函數(shù)模式只能通過其構造函數(shù)內(nèi)部的方法來獲取里面的屬性值