學習《JavaScript經典例項》之第1~3章
阿新 • • 發佈:2019-02-10
《JavaScript經典例項》各節中的完整程式碼解決了常見的程式設計問題,並且給出了在任何瀏覽器中構建Web應用程式的技術。只需要將這些程式碼示例複製並貼上到你自己的專案中就行了,可以快速完成工作,並且在此過程中學習JavaScript的很多知識。
第1章 JavaScript不只是簡單的構件塊
1.1 JavaScript物件、基本型別和字面值之間的區別
5種基本型別:字串、數值、布林值、null、undefined,有3個有對應的構造方法物件:string、Number、Boolean
基本型別變數嚴格等於字面值,而物件例項則不會,因為基本型別是按值來比較的,而值是字面值
var num1 = 123;
var num2 = new Number(123);
console.log(typeof num1); //number
console.log(typeof num2); //object
1.2 從字串提取一個列表
- 提取之前:
This is a list of items: cherries, limes, oranges, apples.
- 提取之後:
['cherries','limes','oranges','apples']
- 方法可返回某個指定的字串值在字串中首次出現的位置。
- 方法用於提取字串中介於兩個指定下標之間的字元。
- 方法用於把一個字串分割成字串陣列。
var sentence = 'This is one sentence. This is a sentence with a list of items: cherries, oranges, apples, bananas. That was the list of items.';
var start = sentence.indexOf(':');
var end = sentence.indexOf('.', start+1);
var listStr = sentence.substring(start+1, end);
var fruits = listStr.split(',' );
console.log(fruits); //[" cherries", " oranges", " apples", " bananas"]
//取出空格等
fruits.forEach(function(elmnt,indx,arry) {
arry[indx] = elmnt.trim();
});
console.log(fruits); //["cherries", "oranges", "apples", "bananas"]
1.3 檢查一個存在的、非空的字串
- 想要驗證一個變數已經定義了,是一個字串,並且它不為空
if(typeof unknowVariable === 'string' && unknowVariable.length > 0) {...}
1.4 插入特殊字元
- 想要向字串中插入一個特殊字元,例如一個換行
- 轉義序列都以一個反斜槓 開始(\)
1.5 使用新字串替換模式
- 使用String物件的replace方法和一個 正則表示式
- 方法用於在字串中用一些字元替換另一些字元,或替換一個與正則表示式匹配的子串。
正則表示式特殊字元
字元 | 匹配 | 例子 |
---|---|---|
^ | 匹配輸入的開頭 | /^This/ 匹配This is… |
/ 匹配This is the end | ||
* | 匹配0次或多次 | /se*/ 匹配s seeee或se |
? | 匹配0次或1次 | /ap?/ 匹配apple and and |
+ | 匹配1次或多次 | /ap+/ 匹配apple 但是不匹配and |
{n} | 嚴格匹配n次 | /ap{2}/ 嚴格匹配apple 但是不匹配apie |
{n,} | 匹配n次或多次 | /ap{2,}/ 匹配apple中的p,但是不匹配apie中的p |
{n,m} | 至少匹配n次,之多匹配m 除換行以外的任何字元 |
/ap{2,4}/ 匹配apppppple中的4個p /a.e/ 匹配ape和axe |
[…] | 方括號中的任何字元 | /a[px]e/ 匹配ape axe 但是不匹配apxe |
[^…] | 除了方括號以外的任何字元 | /a[^px]/ 匹配ale 但是不匹配ape axe |
\b | 匹配單詞邊界 | /\bno/ 匹配nono中的第一個no |
\B | 匹配非單詞邊界 | /\Bno/ 匹配nono中的第二個no |
\d | 數字0到9 | /\d{3}/ 匹配Now in 123 中的123 |
\D | 匹配任何非數字字元 | /\D{2,4}/ 匹配Now in 123 中的Now in |
\w | 匹配任何單詞字元(字母、陣列和下劃線 | /\w/ 匹配javaScript中的j |
\W | 匹配任何非單詞字元(非字母、陣列和下劃線) | /\W/ 匹配100%中的% |
\n | 匹配一個換行 | |
\s | 一個單個的空白字元 | |
\S | 一個單個的非空白字元 | |
\t | 一個製表符 | |
(x) | 捕獲括號 | 記住匹配的字元 |
var searchString = "Now is the time, this is the tame";
var re = /t\w{2}e/g;
var replacement = searchString.replace(re, 'place');
console.log(replacement); //Now is the place, this is the place
1.6 找到並突出顯示一個模式的所有例項
- RegExp 方法用於檢索字串中的正則表示式的匹配
- RegExpObject.exec(string)
- 返回一個數組,其中存放匹配的結果。如果未找到匹配,則返回值為 null
var searchString2 = "Now is the time and this is the time and that is the time";
var parttern = /t\w*e/g; //\w 匹配任何單詞字元
var matchArray;
var str = "";
//用regexp exec檢查模式,如果不為空,處理它
while((matchArray = parttern.exec(searchString2)) != null) {
str += "at " + matchArray.index + " we found " + matchArray[0] + "\n";
}
console.log(str);
// at 7 we found the
// at 11 we found time
// at 28 we found the
// at 32 we found time
// at 49 we found the
// at 53 we found time
//例項1-1
document.getElementById("searchSubmit").onclick = function() {
//獲取模式
var pattern = document.getElementById("pattern").value;
var re = new RegExp(pattern, "g");
//獲取字串
var searchString = document.getElementById("inComing").value;
var matchArray;
var resultString = "<pre>";
var first = 0;
var last = 0;
//找到每一個匹配
while((matchArray = re.exec(searchString)) != null) {
last = matchArray.index;
//獲取所有匹配的字串,將其連線起來
resultString += searchString.substring(first, last);
//使用class,新增匹配的字串
resultString += '<span class="found">' + matchArray[0] + '</span>';
first = re.lastIndex;
}
//完成字串
resultString += searchString.substring(first, searchString.length);
resultString += "</pre>";
//插入頁面
document.getElementById("searchResult").innerHTML = resultString;
}
1.7 使用捕獲圓括號交換一個字串中的單詞
- 交換名稱,讓姓氏先出現
- 解決:使用捕獲圓括號和一個正則表示式在字串中找到並記住他們的名字,然後互換他們
- 方法用於在字串中用一些字元替換另一些字元,或替換一個與正則表示式匹配的子串。
字元 | 替換文字 |
---|---|
2、…、$99 | 與 regexp 中的第 1 到第 99 個子表示式相匹配的文字。 |
$& | 與 regexp 相匹配的子串。 |
$` | 位於匹配子串左側的文字。 |
$’ | 位於匹配子串右側的文字。 |
$$ | 允許替換中有一個字面值美元符號($) |
$n | 插入使用RegExp的第n次捕獲圓括號的值 |
var myName = "Tao Yang";
var nameRe = /^(\w+)\s(\w+)$/;
var myNewName = myName.replace(nameRe, "$2 $1");
console.log(myNewName); //Yang Tao
1.8 使用命名實體來替代HTML標籤
- 使用正則表示式把尖括號(<>)轉換為命名的實體:<和>
var pieceOfHtml = "<p>This is a <span>paragraph</span></p>";
pieceOfHtml = pieceOfHtml.replace(/</g, "<");
pieceOfHtml = pieceOfHtml.replace(/>/g, ">");
console.log(pieceOfHtml); //<p>This is a <span>paragraph</span></p>
1.9 ISO 8610格式的日期轉換為Date物件可接受的一種形式
var dtstr = "2014-3-04T19:35:32Z";
dtstr = dtstr.replace(/\D/g, " ");
console.log(dtstr); //2014 3 04 19 35 32
var dtcomps = dtstr.split(" ");
//在基於1的ISO 8610月份和基於0的日期格式之間轉換
dtcomps[1]--;
var convdt = new Date(Date.UTC.apply(null, dtcomps));
console.log(convdt.toString()); //Wed Mar 05 2014 03:35:32 GMT+0800 (中國標準時間)
1.10 使用帶有定時器的函式閉包
- 使用一個匿名函式作為setInterval()或setTimeout()方法呼叫的第一個引數
var intervalId = null;
document.getElementById("redbox").addEventListener('click', startBox, false);
function startBox() {
if(intervalId == null) {
var x = 100;
intervalId = setInterval(function() {
x += 5;
var left = x + "px";
document.getElementById("redbox").style.left = left;
}, 500);
} else {
clearInterval(intervalId);
intervalId = null;
}
}
1.11 記錄兩個事件之間消耗的時間
- 在第一個事件發生的時候,建立一個Date物件,當第二個時間發生的時候,建立一個新的Date物件,並且從第二個物件中減去第一個物件。兩者之間的差以毫秒錶示的,要轉換為秒,就除以1000
- 兩個日期可以相減,但是相加就成了拼接字串
var firstDate = new Date();
setTimeout(function() {
doEvent(firstDate);
}, 25000);
function doEvent() {
var secondDate = new Date();
var diff = secondDate - firstDate;
console.log(diff); //25001
}
1.12 十進位制數轉化為十六進位制值
var num = 255;
console.log(num.toString(16)); //ff
1.13 想要將表中一列的所有數字加和
- 遍歷表中包含了數字值的列,將其轉換為數字,並加和
- 如果你需要返回所有的元素,請使用 querySelectorAll() 方法替代
var sum = 0;
//使用querySelectorAll找到第二列的所有單元格
var cells = document.querySelectorAll("td:nth-of-type(2)");
for(var i=0, l=cells.length; i<l; i++) {
sum += parseFloat(cells[i].firstChild.data);
}
1.14 在角度和弧度之間轉換
- 將角度轉換為弧度
var radians = degrees * (Math.PI / 180);
- 將弧度轉化為角度
var degrees = radians * (180 / Math.PI);
1.15 找到頁面元素可容納的一個圓的半徑和圓心
- Math.min(x,y)方法可返回指定的數字中帶有最低值的數字。
- 求出寬度和高度中較小的一個,用其除以2得到半徑
var circleRadius = Math.min(elemengWidth, elemengHeight) / 2;
- 給指定頁面元素的寬度、高度,通過將二者都除以2來找到其中心點
var x = elemengWidth / 2;
var y = elemengHeight / 2;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>將一個SVG圓放入到一個div元素中</title>
<style type="text/css">
#elem {
width: 100%;
height: 500px;
border: 1px solid #ddd;
background-color: #ddd;
}
</style>
</head>
<body>
<div id="elem">
<svg width="100%" height="100%">
<circle id="circ" width="10" height="10" r="10" fill="#f90">
</svg>
</div>
<script type="text/javascript">
window.onload = window.onresize = function() {
var box = document.getElementById("elem");
var style = window.getComputedStyle(box, null);
var width = parseInt(style.getPropertyValue("width"));
var height = parseInt(style.getPropertyValue("height"));
console.log('w', width, 'h', height);
var x = width / 2;
var y = height / 2;
var circleRadius = Math.min(width, height) / 2;
var circ = document.getElementById("circ");
circ.setAttribute("r", circleRadius);
circ.setAttribute("cx", x);
circ.setAttribute("cy", y);
console.log('r', circleRadius, ' cx', x, ' cy', y);
}
</script>
</body>
</html>
1.16 計算圓弧的長度
- 給定了一個圓的半徑及圓弧角的角度值,求該圓弧的長度
- 使用
Math.PI
把角度轉換為弧度,並在公式中使用該結果來求得圓弧的長度
var radians = degrees * (Math.PI / 180);
var arclength = radians * radians;
第2章 JavaScript陣列
2.1 在陣列中搜索
indexOf()、lastIndexOf()
var animals = new Array('dog', 'cat', 'seal', 'elephant', 'walrus', 'lion');
var index = animals.indexOf('cat');
var index2 = animals.lastIndexOf('lion');
console.log('i',index); //1
console.log('i2',index2); //5
- findIndex() 方法返回傳入一個測試條件(函式)符合條件的陣列第一個元素位置。
var nums = [2, 4, 199, 80, 400, 30, 90];
var over = nums.findIndex(function(ele) {
return (ele >= 100);
});
console.log('nums',nums[over]); //199
2.2 用concat()和apply()將一個二維陣列扁平化
- concat() 方法用於連線兩個或多個數組。該方法不會改變現有的陣列,而僅僅會返回被連線陣列的一個副本。
arrayObject.concat(arrayX,arrayX,......,arrayX)
var fruitarray = [];
fruitarray[0] = ['stranwberry', 'orange'];
fruitarray[1] = ['lime', 'peach', 'banana'];
fruitarray[2] = ['tangerine', 'apricot'];
console.log('array',fruitarray.concat());
var newArray = fruitarray.concat.apply([], fruitarray);
console.log(newArray);
- 如何理解和熟練運用js中的call及apply?
obj.call(thisObj, arg1, arg2, ...);
obj.apply(thisObj, [arg1, arg2, ...]);
- call() & apply(),動態改變this
function add(a, b) {
console.log('add', this);
}
function sum(a, b) {
console.log('sum', this);
}
add(1, 2); //Window
sum(1, 2); //Window
add.call(sum, 1, 2); //sum(a, b)
sum.call(add, 1, 2); //add(a ,b)
- arguments裝換為陣列, 返回的是陣列,但是arguments本身保持不變
var arg = [].slice.call(arguments);
// [].slice.call(document.getElementsByTagName('li'));
- 借用別人的方法
var foo = {
name: 'jack',
showName: function() {
console.log('this name:',this.name);
}
}
var bar = {
name: 'rose'
}
foo.showName(); //jack
foo.showName.call(bar); //rose
- 實現繼承
var Student = function(name, age, high) {
Person.call(this, name, age);
this.high = high;
}
- 封裝物件保證this的指向
var _this = this;
_this.$box.on('mousedown', function()) {
return _this.fndown.apply(_this);
}
2.3 刪除或替換陣列元素
var animals = new Array('dog', 'cat', 'rabbit', 'pig', 'apple');
// 從陣列刪除元素
animals.splice(animals.indexOf('apple'), 1);
console.log(animals); // ["dog", "cat", "rabbit", "pig"]
// 替換
animals.splice(animals.indexOf('pig'), 1, 'monkey');
console.log(animals); //["dog", "cat", "rabbit", "monkey"]
// 使用迴圈和分割來替換和刪除元素
var charSets = ["ab", "bb", "cd", "ab", "cc", "ab", "dd", "ab"];
while(charSets.indexOf('ab') != -1) {
charSets.splice(charSets.indexOf('ab'), 1, '**');
}
console.log(charSets); //["**", "bb", "cd", "**", "cc", "**", "dd", "**"]
while(charSets.indexOf('**') != -1) {
charSets.splice(charSets.indexOf('**'), 1);
}
console.log(charSets); //["bb", "cd", "cc", "dd"]
2.4 提取一個數組中的一部分
var animals = new Array('dog', 'cat', 'rabbit', 'pig', 'apple');
var newAnimals = animals.slice(1, 2);
console.log(animals); //["dog", "cat", "rabbit", "pig", "apple"]
console.log(newAnimals); //["cat"]
2.5 對每一個數組元素應用一個函式
var charSets = ["ab", "bb", "cd", "ab", "cc", "ab", "dd", "ab"];
charSets.forEach(function(element, index, array) {
if(element == 'ab') array[index] = '**';
});
console.log(charSets); //["**", "bb", "cd", "**", "cc", "**", "dd", "**"]
2.6 使用forEach()和call()遍歷querySelectorAll()的結果
- 可以將forEach()強制和一個NodeList一起使用
var cells = document.querySelectorAll('td + td');
[].forEach.call(cells, function(cell) {
sum += parseFloat(cell.firstChild.data);
});
2.7 對陣列中的每個元素執行一個函式並返回一個新陣列
- 將一個十進位制的陣列轉化為新的等價的十六進位制陣列
- map()方法建立一個新陣列,其結果是該陣列中的每個元素都呼叫一個提供的函式後返回的結果。
- 與forEach()不同,不會修改原陣列,但是必須返回一個值
var decArray = [23, 3, 24, 45, 500, 9, 70];
var hexArray = decArray.map(function(ele) {
return ele.toString(16);
});
console.log(decArray); //[23, 3, 24, 45, 500, 9, 70]
console.log(hexArray); //["17", "3", "18", "2d", "1f4", "9", "46"]
2.8 建立一個過濾後的陣列
- filter() 方法建立一個新陣列, 其包含通過所提供函式實現的測試的所有元素。
var charSet = ['**', 'bb', 'cc', '**', 'cd'];
var newArray = charSet.filter(function(element, index, array) {
return element != "**";
});
console.log(newArray); //["bb", "cc", "cd"]
2.9 驗證陣列內容
- 使用Array every()方法來檢查每個元素是否符合給定的條件
- some() 方法確保至少某些元素符合該條件
- 區別:every()方法只要函式返回一個false值,處理就會結束,而some()方法會繼續測試每個元素,直至返回true,此時,不再驗證其他元素,即可返回ture
function testValue(element, index, array) {
var testExp = /^[a-zA-Z]+$/;
return testExp.test(element);
}
var elemSet = ['**', 123, 'adv', '-', 45, 'AAA'];
var result = elemSet.every(testValue);
var result2 = elemSet.some(testValue);
console.log(result); //false
console.log(result2); //true
var elemSet2 = ['aaa', 'animals', 'vvv'];
result = elemSet2.every(testValue);
result2 = elemSet2.some(testValue);
console.log(result); //true
console.log(result2); //true
2.10 使用一個關聯陣列來儲存表單元素名和值
- keys() 方法返回一個新的Array迭代器,它包含陣列中每個索引的鍵。
var elemArray = {};
var elem = document.forms[0].elements[0];
elemArray[elem.id] = elem.value;
var elemArray = {name: 'yt', age:25};
Object.keys(elemArray).forEach(function(key) {
var value = elemArray[key];
console.log(value);
});
第3章 JavaScript的構建塊
3種基本的建立函式方式:
- 宣告式函式
- 匿名函式或函式建構函式
- 函式字面值或函式表示式
3.1 放置函式並提升
- 宣告式函式,可以放置在程式碼中的任何位置;函式表示式,必須將其放置在使用函式的位置之前
// 在宣告一個變數之前列印a
console.log('a', a); //undefined
var a;
// 在宣告一個變數並賦值
console.log('aa', aa); //undefined
var aa = 1;
// 宣告變數發生了提升,但是賦值並沒有,賦值是在相應的位置發生的
// 宣告式函式,在訪問該函式之前,提升將確保把函式宣告移動到當前作用域的頂部
console.log(mytest()); //success
function mytest() {
return 'success';
}
// 使用函式表示式就會報錯,變數可能聲明瞭,但沒有例項化,但是你的程式碼試圖將這個變數當做一個函式對待
console.log(mytest2()); //TypeError: mytest2 is not a function
var mytest2 = function() {
return 'success2';
}
3.2 把一個函式當做引數傳遞給另一個函式
function otherFunction(x, y, z) {
x(y, z);
}
// 可以像傳遞一個命名的變數一樣,將一個函式作為引數傳遞給另一個函式
var param = function func(a1, a2) { alert(a1 + " " + a2); };
otherFunction(param, "Hello", "World");
- 函數語言程式設計和JavaScript
- 高階函式: 一個函式接受另一個函式作為引數,或者返回一個函式,或者兩者都具備
- 函數語言程式設計: 對應用程式複雜性進行抽象的一種方式,使用整齊、乾淨的函式呼叫替代了複雜的迴圈和條件語句(程式碼可讀性高)
- 比如:將陣列中的所有數字相加
// for迴圈相加
var nums = [1, 34, 3, 15, 4, 18];
var sum = 0;
for(var i = 0; i < nums.length; i++) {
sum += nums[i];
}
console.log('sum', sum); //75
var nums2 = [1, 34, 3, 15, 4, 18];
var sum2 = nums2.reduce(function(n1, n2) {
return n1 + n2;
});
console.log('sum2', sum2); //75
3.3 實現遞迴演算法
- 想要實現一個函式,它遞迴地遍歷一個數組並返回一個反向的陣列字串
- 缺點:遞迴很消耗記憶體
// 階乘
function factorial(n) {
return n == 1 ? n : n * factorial(n - 1);
}
console.log('階乘', factorial(4)); // 24
// 斐波那契
var fibonacci = function(n) {
return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2);
}
console.log('斐波那契', fibonacci(10)); //55
// 使用一個遞迴函式字面值來反轉陣列元素,從最大長度開始,每次迭代都將這個值自減
// 當為 0 時,返回字串
var reverseArrary = function(x, index, str) {
return index == 0 ? str : reverseArrary(x, --index, (str += " " + x[index]));
}
var arr = ['apple', 'orange', 'peach', 'lime'];
var str = reverseArrary(arr, arr.length, "");
console.log('str', str); //lime peach orange apple
// 如果要反過來,按照順序把陣列連線為一個字串
var orderArray = function(x, i, str) {
return i == x.length - 1 ? str : orderArray(x, ++i, (str += x[i] + " "));
}
var numArr = [1, 2, 3, 4];
var numStr = orderArray(numArr, -1, "");
console.log('numStr', numStr); //1 2 3 4
3.4 使用一個定時器和回撥防止程式碼阻塞
- 在程式的輸出中,3個外圍的
console.log()
立即被處理了 - 佇列中下一個事件是第一個
noBlock()
函式呼叫,其中又呼叫了factorial()
,記錄了其執行時候的活動,最後跟著回撥函式的呼叫 - 第二次同樣地呼叫了
callBack()
- 第三次呼叫
callBack()
的時候,回撥函式中的呼叫針對第一次callBack()
,並使用了第一次函式呼叫的最終結果:6
<script type="text/javascript">
function factorial(n) {
console.log('n', n);
return n == 1 ? 1 : n * factorial(n - 1);
}
function noBlock(n, callback) {
setTimeout(function() {
var val = factorial(n);
if(callback && typeof callback == 'function') {
callback(val);
}
}, 0);
}
console.log('Top of the morning to you');
noBlock(3, function(n) {
console.log('first call ends width ' + n);
noBlock(n, function(m) {
console.log('final result is ' + m);
});
});
var tst = 0;
for(var i = 0; i < 10; i++) {
tst += i;
}
console.log('value of tst is ' + tst);
noBlock(4, function(n) {
console.log('end result is ' + n);
});
console.log('not doing too much');
</script>