JavaScript基礎系列14—面向對象入門

一、面向對象的概念

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 的方式去使用,那麼他就是一個構造函數。 為瞭區別,如果一個函數想作為構造函數,作為國際慣例,最好把這個構造函數的首字母大寫。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *