JavaScript高級-類的使用
- 2021 年 2 月 18 日
- 筆記
1.面向過程與面向對象
1.1面向過程
- 面向過程就是分析出解決問題所需要的步驟,然後用函數把這些步驟一步一步實現,使用的時候再一個一個的依次調用就可以了。
1.2面向對象
- 面向對象是把事務分解成為一個個對象,然後由對象之間分工與合作。
1.3面向過程與面向對象對比
面向過程 | 面向對象 | |
---|---|---|
優點 | 性能比面向對象高,適合跟硬體聯繫很緊密的東西,例如單片機就採用的面向過程編程。 | 易維護、易復用、易擴展,由於面向對象有封裝、繼承、多態性的特性,可以設計出低耦合的系統,使系統 更加靈活、更加易於維護 |
缺點 | 不易維護、不易復用、不易擴展 | 性能比面向過程低 |
2.對象與類
2.1對象
對象是由屬性和方法組成的:是一個無序鍵值對的集合,指的是一個具體的事物
- 屬性:事物的特徵,在對象中用屬性來表示(常用名詞)
- 方法:事物的行為,在對象中用方法來表示(常用動詞)
2.1.1創建對象
//以下程式碼是對對象的複習
//字面量創建對象
var ldh = {
name: '劉德華',
age: 18
}
console.log(ldh);
//構造函數創建對象
function Star(name, age) {
this.name = name;
this.age = age;
}
var ldh = new Star('劉德華', 18)//實例化對象
console.log(ldh);
如上兩行程式碼運行結果為:
2.2類
- 在 ES6 中新增加了類的概念,可以使用 class 關鍵字聲明一個類,之後以這個類來實例化對象。類抽象了對象的公共部分,它泛指某一大類(class)對象特指某一個,通過類實例化一個具體的對象
2.2.1創建類
- 語法:
//步驟1 使用class關鍵字
class name {
// class body
}
//步驟2使用定義的類創建實例 注意new關鍵字
var xx = new name();
- 示例
// 1. 創建類 class 創建一個 明星類
class Star {
// 類的共有屬性放到 constructor 裡面
constructor(name, age) {
this.name = name;
this.age = age;
}
}
// 2. 利用類創建對象 new
var ldh = new Star('劉德華', 18);
console.log(ldh);
以上程式碼運行結果:
通過結果我們可以看出,運行結果和使用構造函數方式一樣
2.2.2類創建添加屬性和方法
// 1. 創建類 class 創建一個類
class Star {
// 類的共有屬性放到 constructor 裡面 constructor是 構造器或者構造函數
constructor(uname, age) {
this.uname = uname;
this.age = age;
}//------------------------------------------->注意,方法與方法之間不需要添加逗號
sing(song) {
console.log(this.uname + '唱' + song);
}
}
// 2. 利用類創建對象 new
var ldh = new Star('劉德華', 18);
console.log(ldh); // Star {uname: "劉德華", age: 18}
ldh.sing('冰雨'); // 劉德華唱冰雨
以上程式碼運行結果:
注意喲:
- 通過class 關鍵字創建類, 類名我們還是習慣性定義首字母大寫
- 類裡面有個constructor 函數,可以接受傳遞過來的參數,同時返回實例對象
- constructor 函數 只要 new 生成實例時,就會自動調用這個函數, 如果我們不寫這個函數,類也會自動生成這個函數
- 多個函數方法之間不需要添加逗號分隔
- 生成實例 new 不能省略
- 語法規範, 創建類 類名後面不要加小括弧,生成實例 類名後面加小括弧, 構造函數不需要加function
2.2.3類的繼承
- 語法
// 父類
class Father{
}
// 子類繼承父類
class Son extends Father {
}
- 示例
class Father {
constructor(surname) {
this.surname= surname;
}
say() {
console.log('你的姓是' + this.surname);
}
}
class Son extends Father{ // 這樣子類就繼承了父類的屬性和方法
}
var damao= new Son('劉');
damao.say(); //結果為 你的姓是劉
以上程式碼運行結果:
-
子類使用super關鍵字訪問父類的方法
//定義了父類 class Father { constructor(x, y) { this.x = x; this.y = y; } sum() { console.log(this.x + this.y); } } //子元素繼承父類 class Son extends Father { constructor(x, y) { super(x, y); //使用super調用了父類中的構造函數 } } var son = new Son(1, 2); son.sum(); //結果為3
注意:
-
繼承中,如果實例化子類輸出一個方法,先看子類有沒有這個方法,如果有就先執行子類的
-
繼承中,如果子類裡面沒有,就去查找父類有沒有這個方法,如果有,就執行父類的這個方法(就近原則)
-
如果子類想要繼承父類的方法,同時在自己內部擴展自己的方法,利用super 調用父類的構造函數,super 必須在子類this之前調用
// 父類有加法方法 class Father { constructor(x, y) { this.x = x; this.y = y; } sum() { console.log(this.x + this.y); } } // 子類繼承父類加法方法 同時 擴展減法方法 class Son extends Father { constructor(x, y) { // 利用super 調用父類的構造函數 super 必須在子類this之前調用,放到this之後會報錯 super(x, y); this.x = x; this.y = y; } subtract() { console.log(this.x - this.y); } } var son = new Son(5, 3); son.subtract(); //2 son.sum();//8
以上程式碼運行結果為:
-
-
時刻注意this的指向問題,類裡面的共有的屬性和方法一定要加this使用.
- constructor中的this指向的是new出來的實例對象
- 自定義的方法,一般也指向的new出來的實例對象
- 綁定事件之後this指向的就是觸發事件的事件源
-
在 ES6 中類沒有變數提升,所以必須先定義類,才能通過類實例化對象
3.面向對象版tab 欄切換
3.1功能需求
- 點擊 tab欄,可以切換效果.
- 點擊 + 號, 可以添加 tab 項和內容項.
- 點擊 x 號, 可以刪除當前的tab項和內容項.
- 雙擊tab項文字或者內容項文字可以修改裡面的文字內容
3.2案例準備
- 獲取到標題元素
- 獲取到內容元素
- 獲取到刪除的小按鈕 x號
- 新建js文件,定義類,添加需要的屬性方法(切換,刪除,增加,修改)
- 時刻注意this的指向問題
3.3切換
-
為獲取到的標題綁定點擊事件,展示對應的內容區域,存儲對應的索引
this.lis[i].index = i; this.lis[i].onclick = this.toggleTab;
-
使用排他,實現只有一個元素的顯示
toggleTab() { //將所有的標題與內容類樣式全部移除 for (var i = 0; i < this.lis.length; i++) { this.lis[i].className = ''; this.sections[i].className = ''; } //為當前的標題添加激活樣式 this.className = 'liactive'; //為當前的內容添加激活樣式 that.sections[this.index].className = 'conactive'; }
3.4添加
-
為添加按鈕+ 綁定點擊事件
this.add.onclick = this.addTab;
-
實現標題與內容的添加,做好排他處理
addTab() { that.clearClass(); // (1) 創建li元素和section元素 var random = Math.random(); var li = '<li class="liactive"><span>新選項卡</span><span class="iconfont icon-guanbi"> </span></li>'; var section = '<section class="conactive">測試 ' + random + '</section>'; // (2) 把這兩個元素追加到對應的父元素裡面 that.ul.insertAdjacentHTML('beforeend', li); that.fsection.insertAdjacentHTML('beforeend', section); that.init(); }
3.5刪除
-
為元素的刪除按鈕x綁定點擊事件
this.remove[i].onclick = this.removeTab;
-
獲取到點擊的刪除按鈕的所在的父元素的所有,刪除對應的標題與內容
removeTab(e) { e.stopPropagation(); // 阻止冒泡 防止觸發li 的切換點擊事件 var index = this.parentNode.index; console.log(index); // 根據索引號刪除對應的li 和section remove()方法可以直接刪除指定的元素 that.lis[index].remove(); that.sections[index].remove(); that.init(); // 當我們刪除的不是選中狀態的li 的時候,原來的選中狀態li保持不變 if (document.querySelector('.liactive')) return; // 當我們刪除了選中狀態的這個li 的時候, 讓它的前一個li 處於選定狀態 index--; // 手動調用我們的點擊事件 不需要滑鼠觸發 that.lis[index] && that.lis[index].click(); }
3.6編輯
-
為元素(標題與內容)綁定雙擊事件
this.spans[i].ondblclick = this.editTab; this.sections[i].ondblclick = this.editTab;
-
在雙擊事件處理文本選中狀態,修改內部DOM節點,實現新舊value值的傳遞
editTab() { var str = this.innerHTML; // 雙擊禁止選定文字 window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty(); // alert(11); this.innerHTML = '<input type="text" />'; var input = this.children[0]; input.value = str; input.select(); // 文本框裡面的文字處於選定狀態 // 當我們離開文本框就把文本框裡面的值給span input.onblur = function() { this.parentNode.innerHTML = this.value; }; // 按下回車也可以把文本框裡面的值給span input.onkeyup = function(e) { if (e.keyCode === 13) { // 手動調用表單失去焦點事件 不需要滑鼠離開操作 this.blur(); } } }