一、面向對象的概念
1.1 什麼是面向過程
? 就是分析出解決問題所需要的步驟,然後用函數把這些步驟一步一步實現,使用的時候一個一個依次調用就可以瞭。
? 生活中的的例子舉例。
1.2 什麼是面向對象
? 面向對象是把構成問題事務分解成各個對象,建立對象的目的不是為瞭完成一個步驟,而是為瞭描敘某個事物在整個解決問題的步驟中的行為。
面向對象是一種思維方法 面向對象是一種編程方法 面向對象並不隻針對某一種編程語言
1.3 面向對象和面向過程的區別和聯系
面向過程過程側重整個問題的解決步驟,著眼局部或者具體 面向對象側重具體的功能,讓某個對象具有這樣的功能。更加側重於整體。
各自的優缺點 面向過程的優點: 流程化使得編程任務明確,在開發之前基本考慮瞭實現方式和最終結果; 效率高,面向過程強調代碼的短小精悍,善於結合數據結構來開發高效率的程序。。 流程明確,具體步驟清楚,便於節點分析。 缺點是:需要深入的思考,耗費精力,代碼重用性低,擴展能力差,維護起來難度比較高, 對復雜業務來說,面向過程的模塊難度較高,耦合度也比較高。 面向對象的優點:結構清晰,程序便於模塊化,結構化,抽象化,更加符合人類的思維方式; 封裝性,將事務高度抽象,從而便於流程中的行為分析,也便於操作和自省; 容易擴展,代碼重用率高,可繼承,可覆蓋; 實現簡單,可有效地減少程序的維護工作量,軟件開發效率高。 缺點是:效率低,面向對象在面向過程的基礎上高度抽象,從而和代碼底層的直接交互非常少機會, 從而不適合底層開發和遊戲甚至多媒體開發; 復雜性,對於事務開發而言,事務本身是面向過程的,過度的封裝導致事務本身的復雜性提高。
二、編程語言中面向對象的實現方式
編程語言對對面向對象的實現主流的有兩種方式:基於類的面向對象和基於原型的面向對象。
不管以什麼方式實現,都具有面向對象的三大特征:
封裝
也就是把客觀事物封裝成抽象的類或具體的對象,並且類或對象可以把自己的數據和方法隻讓可信的類或者對象操作,對不可信的進行信息隱藏。
繼承
可以讓某個類型的對象獲得另一個類型的對象的屬性的方
多態
不同實例的相同方法在不同情形有不同表現形式。多態機制使具有不同內部結構的對象可以共享相同的外部接口。
2.1基於類的面向對象
典型的語言:Java、C#
對象(object)依靠 類(class)來產生
2.2 基於原型的面向對象
典型的語言:JavaScript
對象(object)則是依靠 構造器(constructor)利用 原型(prototype)構造出來的
三、對JavaScript對象的進一步認識
? ECMA-262 把對象定義為:“無序屬性的集合,其屬性可以包含基本值、對象或者函數。”嚴格來講,這就相當於說對象是一組沒有特定順序的值。對象的每個屬性或方法都有一個名字,而每個名字都映射到一個值。正因為這樣(以及其他將要討論的原因),我們可以把 ECMAScript 的對象想象成散列表:無非就是一組名值對,其中值可以是數據或函數。
<script type="text/javascript"> //用大括號括起來的一系列的鍵值對,就構成瞭JavaScript對象。這種對象稱之為字面量對象。 var person = { name : "張三", // 一個鍵值對 age : 20, sex : "男", eat : function () { //屬性的值是函數,這個時候我們更喜歡把這樣的屬性稱之為方法。 alert("吃東西"); } } </script>
說明:
name : “張三” 一個鍵值對表示JavaScript對象的一個屬性。 name是屬性名, “張三” 屬性值。 屬性可以是任意類型的。可以包括我們以前學的簡單數據類型,也可以是函數,也可以是其他的對象。 當一個屬性的值是函數的時候,我們更喜歡說這個屬性為方法。(如果函數不和對象關聯起來的時候,應該叫函數不應該叫方法。隻是一種稱呼,你完全可以不用理會)。 我們一般說person對象具有瞭一個方法eat. 將來訪問eat的時候,也和調用一個函數一樣一樣的。
3.1 訪問對象的屬性
訪問一個對象的屬性,我們可以直接通過 對象.屬性名 和 對象[屬性名] 來訪問。
alert(person.name); // 訪問person對象的 name屬性值 person.age = 30; //修改person對象的 age 屬性 person.eat(); //既然是調用方法(函數) 則一定還要添加 ()來表示方法的調用 alert(person["name"]); //
兩種使用方式有一些不同的地方:
對象.屬性名的方式,隻適合知道瞭屬性的名字,可以直接寫。比如: person.age 。如果屬性名是個變量,則這種方法無效, 對象.變量名 會出現語法錯誤。 對象[屬性名],這種方式使用無限制。如果是字符串常量,則應該用”“引起來,如果是變量,可以直接使用。
person.age = 100; // ok var n = "age"; person.a = 101; // no ok 語法錯誤 person["age"] = 102; // ok person[n] = 103; //ok
3.2 給對象添加屬性
JavaScript是一種動態語言,可以在代碼執行過程中,動態去添加和修改對象的屬性。這是與其他面向對象語言一個很大的不同點。
備註:對那些基於類的語言,屬性一旦在類中定義完成,對象是不能去動態添加和刪除屬性的。
//給person對象的屬性 girlFriend 賦值。在賦值的過程中,首先會判斷這個屬性在JavaScript中是否存在,如果存在就對這個 //屬性重寫賦值。如果不存在,就給這個對象添加這個屬性,並賦值。 person.girlFrient = "小麗"; //給對象添加方法 person.play = funcion(){ alert("打擊high起來"); }
3.3 刪除對象屬性
對JavaScript來說,我們不僅可以動態的添加屬性,也可以動態的刪除屬性。
使用操作符:delete
註意:delete是個操作符,不是方法,所以後面沒有必要添加括號啊
// 使用delete操作關鍵字,刪除person對象的屬性age delete person.age; alert(person.age); //彈出undefined。表示這個屬性沒有定義
3.4 修改對象屬性
// 把person對象的sex屬性的值修改為 女 person.sex = "女"; person.eat = funcion(){ alert("吃貨"); } person.eat(); //吃貨
3.5 使用for…in遍歷對象的屬性
for…in可以用來遍歷對象的所有屬性。
// 在用for...in遍歷的時候, in前面的變量pn指的是屬性的名稱。 for (pn in person) { alert(pn + " " + person[pn]); }
四、多種創建對象的方式
除瞭上面的使用對象直接量,JavaScript還支持多種方式創建對象
4.1 使用new Object()創建
<script type="text/javascript"> //使用object創建一個對象 完全等同於 var person = {}; var person = new Object(); //給對象添加屬性 person.name = "李四"; //給對象添加方法 person.eat = function () { alert("好好吃") } </script>
4.2 工廠模式創建
雖然 Object 構造函數或對象字面量都可以用來創建單個對象,但這些方式有個明顯的缺點:使用同一個接口創建很多對象,會產生大量的重復代碼。為解決這個問題,人們開始使用工廠模式的一種變體。
工廠模式是軟件工程領域一種廣為人知的設計模式,這種模式抽象瞭創建具體對象的過程,考慮到在 ECMAScript 中無法創建類,開發人員就發明瞭一種函數,用函數來封裝以特定接口創建對象的細節。
<script type="text/javascript"> function createPerson(name, age, job) { var o = new Object(); o.name = name; o.age = age; o.job = job; o.sayName = function() { alert(this.name); }; return o; } var person1 = createPerson("張三", 29, "js開發者"); var person2 = createPerson("李四", 27, "java開發者"); </script>
createPerson()函數可以多次調用,每調用一次這個函數就會返回一個對象,而且對象的類型仍然是Object類型的。雖然解決瞭多個相似對象的問題,但卻沒有解決對象類型識別的問題。
4.3 構造函數模式創建
為瞭解決對象類型識別問題,又提出瞭構造函數模式。這種模式,其實在我們創建一些原生對象的時候,比如Array、Object都是調用的他們的構造函數。
看下面的代碼
<script type="text/javascript"> function Person (name, age, sex) { this.name = name; this.age = age; this.sex = sex; this.eat = function () { alert(this.name + "在吃東西"); } } var p1 = new Person("張三", 20, "男"); p1.eat(); //張三在在吃東西 var p1 = new Person("李四", 30, "男"); p1.eat(); //李四在在吃東西 alert(p1 instanceof Person); // </script>
說明:
使用構造函數創建對象,必須使用關鍵字new ,後面跟著構造函數的名,根據需要傳入相應的參數。 其實使用 new 構造函數() 的方式創建對象,經歷瞭下面幾個步驟。
創建出來一個新的對象 將構造函數的作用域賦給新對象。意味著這個時候 this就代表瞭這個新對象。 執行構造函數中的代碼。 在本例中就是給新對象添加屬性,並給屬性初始化值。 構造函數執行完畢之後,默認返回新對象。 所以外面就可以拿到這個剛剛創建的新對象瞭。
五、構造函數與普通函數的關系
他們都是函數。構造函數也是函數,也可以像普通的函數一樣進行調用。 做普通函數調用的時候,因為沒有創建新的對象,所以this其實指向瞭window對象。
function Person(){ this.name = "張三"; // 把name屬性添加到瞭window對象上面 alert(this === window); //如果不作為構造方法調用,則 是true } Person(); // 把構造函數當做普通方法調用。這個時候內部的this指向瞭weindow alert(window.name); //張三 function Human(){ this.name = "王五"; alert(this instanceof window); // false alert(this instanceof Human); //true } var h = new Human(); //當做構造函數來調用,創建一個對象 alert(h.name);
構造函數和普通函數僅僅也僅僅是調用方式的不同。也就是說,隨便一個函數你如果用new 的方式去使用,那麼他就是一個構造函數。 為瞭區別,如果一個函數想作為構造函數,作為國際慣例,最好把這個構造函數的首字母大寫。