1.JavaScript 面向對象
目标:
能夠說出什麼是面向對象
能夠說出類和對象的關系心
能夠使用class 建立自定義類
能夠說出什麼是繼承
1.1 面向對象程式設計介紹
1.1.1 兩大程式設計思想
- 面向過程
- 面向對象
1.1.2 面向過程程式設計POP(Process-oriented progrmming)
面向過程就是分析出解決問題所需要的步驟,然後用函數把這些步驟一步一步實作,使用的時候再一個一個的依次調用就可以了。
面向過程,就是按照分析好了的步驟,按照步驟解決問題。
1.1.3 面向對象程式設計OOP(Object Oriented Programming)
面向對象是把事務分解成為一個個對象,然後由對象之間分工與合作。
面向對象是以對象功能來劃分問題,而不是步驟。
在面向對象程式開發思想中,每一個對象都是功能中心,具有明确分工。
面向對象程式設計具有靈活、代碼可複用、容易維護和開發的優點,更适合多人合作的大型軟體項目。
面向對象的特性:
- 封裝性
- 繼承性
- 多态性
1.1.4 面向過程和面向對象的對比
1.2 ES6中的類和對象
面向對象
面向對象更貼近我們的實際生活,可以使用面向對象描述現實世界事物.但是事物分為具體的事物和抽象的事物
手機→ 抽象的(泛指的)
滑鼠指向的手機→ 具體的(特指的)
面向對象的思維特點:
1.抽取(抽象)對象共用的屬性和行為組織(封裝)成一個類(模闆)
2.對類進行執行個體化,擷取類的對象
面向對象程式設計我們考慮的是有哪些對象,按照面向對象的思維特點,不斷的建立對象,使用對象,指揮對象做事情.
1.2.1 對象
現實生活中∶萬物皆對象,對象是一個具體的事物,看得見摸得着的實物。例如,一本書、一輛汽車、一個人可以是“對象”,一個資料庫、一張網頁、一個與遠端伺服器的連接配接也可以是“對象”。
在JavaScript 中,對象是一組無序的相關屬性和方法的集合,所有的事物都是對象,例如字元串、數值、數組、函數等。
對象是由屬性和方法組成的:
- 屬性:事物的特征,在對象中用屬性來表示(常用名詞)
- 方法:事物的行為,在對象中用方法來表示(常用動詞)
1.2.2 類class
在ES6中新增加了類的概念,可以使用class關鍵字聲明一個類,之後以這個類來執行個體化對象。
類抽象了對象的公共部分,它泛指某一大類( class )
對象特指某一個,通過類執行個體化一個具體的對象
面向對象的思維特點:
1.抽取(抽象)對象共用的屬性和行為組織(封裝)成一個類(模闆)
2.對類進行執行個體化,擷取類的對象
1.2.3 建立類
文法:
// 類名習慣性定義首字母大寫
class ClassName {
// class body
}
建立執行個體
注意:類必須使用 new 執行個體化對象。
1.2.4 類 constructor 構造函數
constructor()方法是類的構造函數(預設方法),用于傳遞參數,傳回執行個體對象,通過 new 指令生成對象執行個體時,自動調用該方法。如果沒有顯示定義,類内部會自動給我們建立一個constructor()
// 1. 通過 class 關鍵字建立類,類名習慣性定義首字母大寫
class Star {
// 2.類裡面有個constructor函數,可以接受傳遞過來的參數,同時傳回執行個體對象
// 3.constructor函數隻要new生成執行個體時,就會自動調用這個函數,如果我們不寫這個函數,類也會自動生成這個函數
constructor(uname, age) {
this.uname = uname;
this.age = age;
}
}
// 2.生成執行個體 new 不能省略
var ldh = new Star('劉德華', 18);
var zxy = new Star('張學友',20);
console.log(ldh);
console.log(zxy);
注意文法規範,建立類類名後面不要加小括号,生成執行個體類名後面加小括号,構造函數不需要加function
1.2.5 類添加方法
文法∶
class Person {
constructor(name, age){ // constructor構造器或者構造函數
this.name = name;
this.age = age;
}
// 類裡面所有的函數不需要寫 function
// 類裡面,多個函數方法之間不需要逗号分隔
say () {
console.log (this.name + '你好');
}
}
1.3.類的繼承
1.3.1 繼承
繼承:子類可以繼承父類的一些屬性和方法。
文法:
class Father{ // 父類
}
class Son extends Father { //子類繼承父類
}
1.3.2 super
super關鍵字用于通路和調用對象父類上的函數。可以調用父類的構造函數,也可以調用父類的普通函數。
1.調用父類的構造函數
super 關鍵字可以調用父類的構造方法,可以寫在子類的構造方法中,進而給父類的屬性指派。
避免出現通過子類構造方法,指派給的是子類的屬性,導緻父類的方法無法使用的情況。
以下是這種情況的說明:
父類 Father 如下:
class Father {
constructor(×,y) {
this.x =X;
this.y = y;
}
sum() {
console.log(this.x + this.y);
}
}
想要子類 Son 繼承它的 sum 方法。按照如下代碼寫的話,會出現問題。
class Son extends Father {
// 這個地方這樣寫的話,子類執行個體化的時候是指派給了子類的屬性 x和y
constructor(×,y) {
this.x = X;
this.y = y;
}
}
// 這個Son類的執行個體的屬性x和y分别是1和2
var son = new Son(1,2);
// son 類繼承的sun 方法,算的是父類的屬性x和y的和,無法得到結果。
son.sum();
正确的寫法應該是:
class Son {
constructor(x,y) {
super(x,y);//調用了父類的構造函數
}
}
// new 指令生成子類的執行個體時,自動調用構造函數,把 1和2 傳給了子類的構造函數的 x和y
// 執行super(x,y)語句,調用了父類的構造函數
// 父類中的x和y 賦了值,分别是 1和2
var son = new Son(1,2);
// 計算父類的屬性:x和y 的和。結果是3.
son.sum();
2.super關鍵字調用父類的普通函數
class Father {
say() {
return "我是爸爸';
}
}
class Son extends Father {
say() {
console.log('我是兒子');
// super.say()就是調用父類中的普通函數say()
console.log(super.say() + '的兒子');
}
}
var son = new Son();
son.say();
☆ 繼承中的屬性或者方法查找原則(就近原則):
- 如果執行個體化子類輸出一個方法,先看子類有沒有這個方法,如果有就先執行子類的。
- 如果子類裡面沒有,就去查找父類有沒有這個方法,如果有,就執行父類的這個方法(就近原則)
3.子類繼承父類方法,同時擴充自己方法
在子類的構造函數中:
- 使用 super關鍵字,在子類執行個體化時給父類的構造函數傳值
- 使用 this 關鍵字,在子類執行個體化時給子類的屬性指派
注意:子類在構造函數中使用super,必須放到this 前面(必須先調用父類的構造方法,再使用子類構造方法)
class Father {
constructor(×,y){
// 構造函數裡面的 this 指的是 建立的執行個體對象
this.x = X;
this.y = y;
}
sum() {
console.log(this.× + this.y);
}
}
//子類繼承父類加法方法同時擴充減法方法
class Son extends Father {
constructor(x,y) {
// 利用super 調用父類的構造函數
// super 必須在子類this 之前
super(x,y);
this.x = x;
this.y = y;
}
// subtract 中的this,指的是 執行個體對象son,因為son 調用了這個函數
subtract() {
console.log(this.x - this.y);
}
}
var son = new Son(5,3);
son.subtract();
☆ 三個注意點;
- 在ES6中類沒有變量提升,是以必須先定義類,才能通過類執行個體化對象
- 類裡面的共有的屬性和方法,一定要加 this 使用
- 類裡面的this指向問題.
- constructor裡面的this指向執行個體對象,方法裡面的this指向這個方法的調用者
1.4.面向對象案例
案例:面向對象版tab欄切換
功能需求:
1.點選 tab欄,可以切換效果.
2.點選+号,可以添加tab項和内容項.
3.點選x号,可以删除目前的tab項和内容項.
4.輕按兩下tab項文字或者内容項文字可以修改裡面的文字内容.
抽象對象:
Tab 對象
1.該對象具有切換功能
2.該對象具有添加功能
3.該對象具有删除功能
4.該對象具有修改功能
2.構造函數和原型
目标:
- 能夠使用構造函數建立對象
- 能夠說出原型的作用
- 能夠說出通路對象成員的規則
- 能夠使用ES5新增的一些方法
2.1 構造函數和原型
2.1.1 概述
在典型的OOP的語言中( 如Java ),都存在類的概念,類就是對象的模闆,對象就是類的執行個體,但在ES6之前,JS中并沒有引入類的概念。
ES6,全稱ECMAScript 6.0 ,2015.06發版。但是目前浏覽器的JavaScript是 ES5 版本,大多數高版本的浏覽器也支援ES6,不過隻實作了5S6的部分特性和功能。
在ES6之前,對象不是基于類建立的,而是用一種稱為建構函數的特殊函數來定義對象和它們的特征。
建立對象可以通過以下三種方式:
1.對象字面量
2.new Object()
3.自定義構造函數
// 方法一:對象字面量
var obj1 = {};
// 方法二: new Object()
var obj2 = new Object();
// 方法三:自定義構造函數
function Star(uname, age) {
this.uname = uname;
this.age = age;
this.sing = function(){
console.log('會唱歌')
}
}
var ldh = new Star('劉德華',18);
ldh.sing();
2.1.2 構造函數
構造函數是一種特殊的函數,主要用來初始化對象,即為對象成員變量賦初始值,它總與new一起使用。我們可以把對象中一些公共的屬性和方法抽取出來,然後封裝到這個函數裡面。
在JS中,使用構造函數時要注意以下兩點︰
1.構造函數用于建立某一類對象,其首字母要大寫
2.構造函數要和 new 一起使用才有意義
new 在執行時會做四件事情:
- 在記憶體中建立一個新的空對象。
- 讓 this指向這個新的對象。
- 執行構造函數裡面的代碼,給這個新對象添加屬性和方法。
- 傳回這個新對象(是以構造函數裡面不需要return ).
JavaScript的構造函數中可以添加一些成員,可以在構造函數本身上添加,也可以在構造函數内部的this上添加。通過這兩種方式添加的成員,就分别稱為靜态成員和執行個體成員。
靜态成員︰在構造函數本身上添加的成員稱為靜态成員,隻能由構造函數本身來通路。如sex。
執行個體成員∶在構造函數内部通過 this 添加的對象成員稱為執行個體成員,隻能由執行個體化的對象來通路。如uname、age、sing。
function Star(uname, age) {
// 1.在構造函數内部通過 this 添加的對象成員稱為執行個體成員
this.uname = uname;
this.age = age;
this.sing = function(){
console.log('會唱歌')
}
}
var ldh = new Star('劉德華',18);
// 執行個體成員 隻能由執行個體化的對象來通路
ldh.sing();
// 2.在構造函數本身上添加的成員稱為靜态成員
Star.sex = '男';
// 靜态成員 隻能由構造函數本身來通路
console.log(Star.sex)
2.1.3 構造函數的問題
構造函數方法很好用,但是存在浪費記憶體的問題。
我們希望所有的對象使用同一個函數,這樣就比較節省記憶體,那麼我們就要使用到原型。
2.1.4 構造函數原型 prototype
構造函數通過原型配置設定的函數是所有對象所共享的。
JavaScript規定,每一個構造函數都有一個prototype屬性,指向另一個對象。注意這個prototype就是一個對象,這個對象的所有屬性和方法,都會被構造函數所據有。
我們可以把那些不變的方法,直接定義在prototype對象上,這樣所有對象的執行個體就可以共享這些方法。
Star.prototype.sing = function(){
console.log('會唱歌')
}
-
Q:原型是什麼?
A:一個對象,我們也稱prototype 為原型對象
-
Q:原型的作用是什麼?
A:共享方法。
一般情況下,公共屬性定義到構造函數裡面,公共的方法放到原型對象上。
2.1.5 對象原型 __proto__
對象都會有一個屬性__proto__,指向構造函數的prototype原型對象,之是以我們對象可以使用構造函數prototype原型對象的屬性和方法,就是因為對象有__proto__原型的存在。
- proto 對象原型和原型對象 prototype是等價的
- __proto__對象原型的意義就在于,為對象的查找機制提供一個方向,或者說一條路線,但是它是一個非标準屬性,是以實際開發中,不可以使用這個屬性,它隻是内部指向原型對象prototype
方法的查找規則:
首先看ldh對象身上是否有sing方法,如果有就執行這個對象上的sing
如果沒有sing 這個方法,因為有__proto__的存在,就去構造函數原型對象prototype身上去查找sing這個方法
2.1.6 constructor 屬性
對象原型(__proto__)和構造函數( prototype ) 原型對象裡面都有一個屬性constructor屬性,constructor我們稱為構浩函數,因為它指回構造函教本身。
constructor主要用于記錄該對象引用于哪個構造函數,它可以讓原型對象重新指向原來的構造函數。
很多情況下,我們需要手動的利用constructor這個屬性指回原來的構造函數
Star.prototype = {
// 如果我們修改了原來的原型對象,給原型對象指派的是一個對象,則必須手動的利用constructor指回原來的構造函數
constructor: star;
sing: function() f
console.log('我會唱歌');
},
movie: function() {
console.log('我會演電影');
}
}