ES6面向物件——class類
面相過程的程式設計思想
面向過程就是分析出解決問題所需要的步驟,然後用函式把這些步驟一步一步實現,使用的時候再一個一個的依次呼叫就可以了。
面向過程,就是按照我們分析好了的步驟,按照步驟解決問題。
面向物件程式設計 OOP (Object Oriented Programming)
面向物件是把事務分解成為一個個物件,然後由物件之間分工與合作。
在面向物件程式開發思想中,每一個物件都是功能中心,具有明確分工。
面向物件程式設計具有靈活、程式碼可複用、容易維護和開發的優點,更適合多人合作的大型軟體專案。
面向物件的特性:
- 封裝性
- 繼承性
- 多型性
面向過程和麵向物件的對比
面相過程
優點:效能比面向物件高,適合跟硬體聯絡很緊密的東西,例如微控制器就採用的面向過程程式設計。
缺點:沒有面向物件易維護、易複用、易擴充套件
面向物件
優點:易維護、易複用、易擴充套件,由於面向物件有封裝、繼承、多型性的特性,可以設計出低耦合的系統,使系統 更加靈活、更加易於維護
缺點:效能比面向過程低
es6中的類和物件
面向物件的思維特點:
抽取(抽象)物件共用的屬性和行為組織(封裝)成一個類(模板)
對類進行例項化, 獲取類的物件
面向物件程式設計我們考慮的是有哪些物件,按照面向物件的思維特點,不斷的建立物件,使用物件,指揮物件做事情.
物件
現實生活中:萬物皆物件,物件是一個具體的事物,看得見摸得著的實物。例如,一本書、一輛汽車、一個人可以是“物件”,一個數據庫、一張網頁、一個與遠端伺服器的連線也可以是“物件”。
在 JavaScript 中,物件是一組無序的相關屬性和方法的集合,所有的事物都是物件,例如字串、數值、陣列、函式等。
物件是由屬性和方法組成的:
- 屬性:事物的特徵,在物件中用屬性來表示(常用名詞)
- 方法:事物的行為,在物件中用方法來表示(常用動詞)
類 class
在 ES6 中新增加了類的概念,可以使用 class 關鍵字宣告一個類,之後以這個類來例項化物件。
類抽象了物件的公共部分,它泛指某一大類(class)
物件特指某一個,通過類例項化一個具體的物件
建立類
class name {
// class body
}
var xx = new name(); // 注意: 類必須使用 new 例項化物件
類 constructor 建構函式
constructor() 方法是類的建構函式(預設方法),用於傳遞引數,返回例項物件,通過 new 命令生成物件例項時,自動呼叫該方法。如果沒有顯示定義, 類內部會自動給我們建立一個constructor()
class Person {
constructor(name,age) { // constructor 構造方法或者建構函式
this.name = name;
this.age = age;
}
say() {
console.log(this.name + '你好');
}
// 注意: 方法之間不能加逗號分隔,同時方法不需要新增 function 關鍵字。
}
var ldh = new Person('劉德華', 18);
console.log(ldh.name)
繼承
現實中的繼承:子承父業,比如我們都繼承了父親的姓。
程式中的繼承:子類可以繼承父類的一些屬性和方法。
class Father{ // 父類
}
class Son extends Father { // 子類繼承父類
}
super關鍵字
super 關鍵字用於訪問和呼叫物件父類上的函式。可以呼叫父類的建構函式,也可以呼叫父類的普通函式
class Person { // 父類
constructor(surname){
this.surname = surname;
}
}
class Student extends Person { // 子類繼承父類
constructor(surname,firstname){
super(surname); // 呼叫父類的constructor(surname)
this.firstname = firstname; // 定義子類獨有的屬性
}
}
** 注意: **子類在建構函式中使用super, 必須放到 this 前面 (必須先呼叫父類的構造方法,在使用子類構造方法)
class Father {
constructor(surname) {
this.surname = surname;
}
saySurname() {
console.log('我的姓是' + this.surname);
}
}
class Son extends Father { // 這樣子類就繼承了父類的屬性和方法
constructor(surname, fristname) {
super(surname); // 呼叫父類的constructor(surname)
this.fristname = fristname;
}
sayFristname() {
console.log("我的名字是:" + this.fristname);
}
}
var damao = new Son('劉', "德華");
damao.saySurname();
damao.sayFristname();
super關鍵字 用於訪問和呼叫物件父類上的函式。可以呼叫父類的建構函式,也可以呼叫父類的普通函式。
class Father {
say() {
return '我是爸爸';
}
}
class Son extends Father { // 這樣子類就繼承了父類的屬性和方法
say() {
// super.say() super 呼叫父類的方法
return super.say() + '的兒子';
}
}
var damao = new Son();
console.log(damao.say());
注意點
- 在 ES6 中類沒有變數提升,所以必須先定義類,才能通過類例項化物件.
- 類裡面的共有屬性和方法一定要加this使用.
- 類裡面的this指向問題.
- constructor 裡面的this指向例項物件, 方法裡面的this 指向這個方法的呼叫者
面向物件案例——面向物件版 tab 欄切換
功能需求:
- 點選 tab欄,可以切換效果.
- 點選 + 號, 可以新增 tab 項和內容項.
- 點選 x 號, 可以刪除當前的tab項和內容項.
- 雙擊tab項文字或者內容項文字,可以修改裡面的文字內容.
抽象物件: Tab 物件
- 該物件具有切換功能
- 該物件具有新增功能
- 該物件具有刪除功能
- 該物件具有修改功能
新增功能
- 點選 + 可以實現新增新的選項卡和內容
- 第一步: 建立新的選項卡li 和 新的 內容 section
- 第二步: 把建立的兩個元素追加到對應的父元素中.
- 以前的做法: 動態建立元素
createElement
, 但是元素裡面內容較多, 需要innerHTML賦值,在appendChild
追加到父元素裡面. - 現在高階做法: 利用
insertAdjacentHTML()
可以直接把字串格式元素新增到父元素中 appendChild
不支援追加字串的子元素,insertAdjacentHTML
支援追加字串的元素insertAdjacentHTML
(追加的位置,‘要追加的字串元素’)- 追加的位置有:
beforeend
插入元素內部的最後一個子節點之後 - 該方法地址: https://developer.mozilla.org/zh-CN/docs/Web/API/Element/insertAdjacentHTML
刪除功能
點選 × 可以刪除當前的li選項卡和當前的section
X是沒有索引號的, 但是它的父親li 有索引號, 這個索引號正是我們想要的索引號
所以核心思路是: 點選 x 號可以刪除這個索引號對應的 li 和 section
但是,當我們動態刪除新的li和索引號時,也需要重新獲取 x 這個元素. 需要呼叫init
方法
編輯功能
- 雙擊選項卡li或者
section
裡面的文字,可以實現修改功能 - 雙擊事件是:
ondblclick
- 如果雙擊文字,會預設選定文字,此時需要雙擊禁止選中文字
*window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();
- 核心思路: 雙擊文字的時候, 在 裡面生成一個文字框, 當失去焦點或者按下回車然後把文字框輸入的值給原先元素即可.
原始碼(js實現邏輯)
var that;
class Tab {
constructor(id) {
// 獲取元素
that = this;
this.main = document.querySelector(id);
this.add = this.main.querySelector('.tabadd');
// li的父元素
this.ul = this.main.querySelector('.fisrstnav ul:first-child');
// section 父元素
this.fsection = this.main.querySelector('.tabscon');
this.init();
}
init() {
this.updateNode();
// init 初始化操作讓相關的元素繫結事件
this.add.onclick = this.addTab;
for (var i = 0; i < this.lis.length; i++) {
this.lis[i].index = i;
this.lis[i].onclick = this.toggleTab;
this.remove[i].onclick = this.removeTab;
this.spans[i].ondblclick = this.editTab;
this.sections[i].ondblclick = this.editTab;
}
}
// 因為我們動態新增元素 需要從新獲取對應的元素
updateNode() {
this.lis = this.main.querySelectorAll('li');
this.sections = this.main.querySelectorAll('section');
this.remove = this.main.querySelectorAll('.icon-guanbi');
this.spans = this.main.querySelectorAll('.fisrstnav li span:first-child');
}
// 1. 切換功能
toggleTab() {
// console.log(this.index);
that.clearClass();
this.className = 'liactive';
that.sections[this.index].className = 'conactive';
}
// 清除所有li 和section 的類
clearClass() {
for (var i = 0; i < this.lis.length; i++) {
this.lis[i].className = '';
this.sections[i].className = '';
}
}
// 2. 新增功能
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. 刪除功能
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();
}
// 4. 修改功能
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();
}
}
}
}
new Tab('#tab');