JS高級. 04 增刪改查面向對象版歌曲管理、遞歸、
增 數組.push()
刪 數組.splice(開始刪除索引,刪除幾個)
在當前對象中調用當前對象的方法中和屬性,必須用this調用
nodeType判斷節點類型
節點.nodeType == 1:元素節點/2:屬性節點/3:文本節點
concat 返回的是一個新的數組
封裝歌曲列表管理(函數)
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 <script> 7封裝歌曲列表管理(函數)var songList = [ 8 { 9 songName:"情書", 10 singer:"張學友" 11 }, 12 { 13 songName:"演員", 14 singer:"薛小謙" 15 }, 16 { 17 songName:"李白", 18 singer:"李榮浩" 19} 20 21 ]; 22 //增刪該查 23 24 //增 25 // function addSong(song){ 26 // songList.push(song); 27 // } 28 // 29 // addSong({ 30 // songName:"take me to your heart", 31 // singer:"邁克學搖滾" 32 // }); 33 // 34 // console.log(songList);35 36 //刪 37 function removeSong(songName){ 38 var song = selectSong(songName); 39 var index = songList.indexOf(song); 40 songList.splice(index, 1); 41 // for (var i = 0; i < songList.length; i++) { 42 // var song = songList[i]; 43 // if(song.songName == songName){ 44 // //splice(起始索引,刪幾個) 45 // songList.splice(i, 1); 46 // } 47 // } 48 } 49 50 removeSong("李白"); 51 // 52 // console.log(songList); 53 // 54 //改 55 function updateSong(songName, singer) { 56 57 var song = selectSong(songName); 58 song.singer = singer; 59 //遍歷歌曲列表,找到要修改的對象 60 // for (var j = 0; j < songList.length; j++) { 61 // var song = songList[j]; 62 // //判斷每次遍歷的對象的歌名,和要找的歌名是不是一一致,如果一致,就是我們要找的對象 63 // if(song.songName == songName){ 64 // //對找到的對象進行修改 65 // song.singer = singer; 66 // } 67 // } 68 } 69 // 70 // updateSong("演員","薛之謙"); 71 // console.log(songList); 72 // 73 //查 74 function selectSong(songName) { 75 for (var k = 0; k < songList.length; k++) { 76 var song = songList[k]; 77 if(song.songName == songName){ 78 return song; 79 } 80 } 81 return null; 82 } 83 84 var obj = selectSong("情書1"); 85 console.log(obj); 86 // 87 // console.log(songList); 88 </script> 89 </head> 90 <body> 91 92 </body> 93 </html>
面向對象封裝歌曲管理
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script> function SongManager(){ this.songList = null; } //在當前對象的方法中,調用當前對象的其他方法,需要使用this //例如 在 removeSong方法中調用 selectSong this.selectSong SongManager.prototype = { init:function (songList) { this.songList = songList; }, addSong: function (song){ this.songList.push(song); }, removeSong:function (songName){ var song = this.selectSong(songName); if(song == null){ throw "您要刪除的歌曲不存在!請重新嘗試"; } var index = this.songList.indexOf(song); this.songList.splice(index, 1); }, updateSong: function (songName, singer) { var song = this.selectSong(songName); if(song == null){ throw "您要修改的歌曲不存在!請重新嘗試"; } song.singer = singer; }, selectSong: function (songName) { for (var k = 0; k < this.songList.length; k++) { var song = this.songList[k]; if(song.songName == songName){ return song; } } return null; } }; var pwbDEManager = new SongManager(); pwbDEManager.init([ { songName:"青藏高原", singer:"潘文斌" }, { songName:"我的換板鞋,摩擦摩擦最時尚", singer:"約翰遜,龐麥郎" } ]); pwbDEManager.addSong({ songName:"東風破", singer:"Jay Chou" }) var gjbDEManager = new SongManager(); gjbDEManager.init([ { songName:"兩只老虎", singer:"高金彪" }, { songName:"粉刷匠", singer:"高金彪" } ]); // gjbDEManager.removeSong("李白"); gjbDEManager.removeSong("兩只老虎"); console.log(pwbDEManager.songList); console.log(gjbDEManager.songList); //要封裝一個歌曲管理的工具 //特征:歌曲列表 //行為:增 刪 改 查 </script> </head> <body> </body> </html>
遞歸(練習在最底下)
1.在函數內調用函數自己,就是遞歸
2.函數不調用不占用內存
3.沒有遞歸結束條件的遞歸就是死隊規
遞歸的兩個要素
1.自己調用自己
2.要有結束的條件
化歸思想:把問題由難化易,化繁為簡,有復雜變簡單的過程成為化歸
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script> window.onload = function () { //給頁面中所有的元素添加一個邊框 1px solid pink //DOM中,沒有提供直接獲取後代元素的API //但是可以通過childNodes來獲取所有的子節點 //先找body的所有子元素 //再找body的子元素的所有子元素 function getChildNode(node){ //先找子元素 var nodeList = node.childNodes; //在用子元素再找子元素 這裏就可以遞歸了 //for循環中的條件,就充當了結束的條件 for (var i = 0; i < nodeList.length; i++) { //childNode獲取到到的節點包含了各種類型的節點 //但是我們只需要元素節點 通過nodeType去判斷當前的這個節點是不是元素節點 var childNode = nodeList[i]; //判斷是否是元素節點 if(childNode.nodeType == 1){ childNode.style.border = "1px solid pink"; getChildNode(childNode); } } } getChildNode(document.body); } </script> </head> <body> <div>1div <p>1p<span>1span</span><span>2span</span><span>3span</span></p> <p>5p<span>1span</span><span>2span</span><span>3span</span></p> </div> <div>10div <p>1p<span>1span</span><span>2span</span><span>3span</span></p> <p>5p<span>1span</span><span>2span</span><span>3span</span></p> </div> <p>我是第1個p標簽</p> <p>我是第10個p標簽</p> </body> </html>
方式二
<script> window.onload = function () { //給頁面中所有的元素添加一個邊框 1px solid pink //DOM中,沒有提供直接獲取後代元素的API //但是可以通過childNodes來獲取所有的子節點 //先找body的所有子元素 //再找body的子元素的所有子元素 function getChildNode(node){ //先找子元素 var nodeList = node.childNodes; var result = []; //在用子元素再找子元素 這裏就可以遞歸了 //for循環中的條件,就充當了結束的條件 for (var i = 0; i < nodeList.length; i++) { //childNode獲取到到的節點包含了各種類型的節點 //但是我們只需要元素節點 通過nodeType去判斷當前的這個節點是不是元素節點 var childNode = nodeList[i]; //判斷是否是元素節點 if(childNode.nodeType == 1){ result.push(childNode); var temp = getChildNode(childNode); result = result.concat(temp); } } return result; } //1.第一次調用時獲取body的所有子元素,會把所有的子元素全部放到result裏面 //2.每放進去一個 就找這個子元素的所有子元素 有返回值 //3.把這個返回值和我們存當前子元素的數組拼接起來 就變成了 子元素 和 孫子元素的集合 var arr = getChildNode(document.body); for (var i = 0; i < arr.length; i++) { var child = arr[i]; child.style.border= "1px solid pink"; } } </script>
遞歸
例子:
1, 2, 3, 4, 5, ..., 100 求和
-
首先假定遞歸函數已經寫好, 假設是
foo
. 即foo(100)
就是求1
到100
的和 -
尋找遞推關系. 就是
n
與n-1
, 或n-2
之間的關系:foo( n ) == n + foo( n - 1 )
var res = foo(100);
var res = foo(99) + 100;
將遞推結構轉換為遞歸體
function foo(n){
return n + foo( n - 1 );
}
上面就是利用了化歸思想:
-
將 求 100 轉換為 求 99
-
將 求 99 轉換為 求 98
-
...
-
將求 2 轉換為 求 1
-
求 1 結果就是 1
-
即: foo( 1 ) 是 1
將臨界條件加到遞歸體中(求1的結果為1)
function foo( n ) {
if ( n == 1 ) return 1;
return n + foo( n - 1 );
}
練習:
求 1, 3, 5, 7, 9, ... 第
n
項的結果與前n
項和. 序號從0
開始
先看求第n
項
-
首先假定遞歸函數已經寫好, 假設是
fn
. 那麽第n
項就是fn(n)
-
找遞推關系:
fn(n) == f(n-1) + 2
-
遞歸體
function fn(n) {
return fn(n-1) + 2;
}
-
找臨界條件
-
求 n -> n-1
-
求 n-1 -> n-2
-
...
-
求 1 -> 0
-
求 第 0 項, 就是 1
-
-
加入臨界條件
function fn( n ) {
if ( n == 0 ) return 1;
return fn( n-1 ) + 2;
}
再看求前n
項和
-
假設已完成, sum( n ) 就是前 n 項和
-
找遞推關系: 前 n 項和 等於 第 n 項 + 前 n-1 項的和
-
遞歸體
function sum( n ) {
return fn( n ) + sum( n - 1 );
}
-
找臨界條件
n == 1
結果為 1
-
加入臨界條件
function sum( n ) {
if (n == 0) return 1;
return fn(n) + sum(n - 1);
}
練習
2, 4, 6, 8, 10 第 n 項與 前 n 項和
解題方法和上一題一樣。
練習
現有數列: 1, 1, 2, 4, 7, 11, 16, … 求 第 n 項, 求前 n 項和.
求第n
項
-
假設已經得到結果 fn, fn( 10 ) 就是第 10 項
-
找遞推關系
-
0, 1 => fn( 0 ) + 0 = fn( 1 )
-
1, 2 => fn( 1 ) + 1 = fn( 2 )
-
2, 3 => fn( 2 ) + 2 = fn( 3 )
-
...
-
n-1, n => fn( n-1 ) + n - 1 = fn( n )
-
-
遞歸體也就清楚了
-
臨界條件是 n == 0 => 1
function fn( n ) {
if ( n == 0 ) return 1;
return fn( n-1 ) + n - 1;
}
前n
項和
function sum( n ) {
if ( n == 0 ) return 1;
return sum( n - 1 ) + fn( n );
}
練習
Fibonacci 數列: 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, … 求其第 n 項.
遞推關系:fn(n) == fn(n-1) + fn(n - 2)
function fib( n ) {
if ( n == 0 || n == 1 ) return 1;
return fib( n - 1 ) + fib( n - 2 );
}
練習
階乘:一個數字的階乘表示的是從 1 開始 累乘到這個數字. 例如 3! 表示 1 2 3. 5! 就是 1 2 3 4 5. 規定 0 沒有階乘, 階乘從1開始。
求n的階乘
function foo ( n ) {
if ( n == 1 ) return 1;
return foo( n - 1 ) * n;
}
練習
求冪
-
求冪就是求 某一個數 幾次方
-
2*2 2 的 平方, 2 的 2 次方
-
求 n 的 m 次方
-
最終要得到一個函數 power( n, m )
-
n 的 m 次方就是 m 個 n 相乘 即 n 乘以 (m-1) 個 n 相乘
function power ( n, m ) {
if ( m == 1 ) return n;
return power( n, m - 1 ) * n;
}
JS高級. 04 增刪改查面向對象版歌曲管理、遞歸、