淺談javascript的面向對象思想

来源:http://www.cnblogs.com/zhuwenqi2016/archive/2017/08/21/7405961.html
-Advertisement-
Play Games

面向對象的三大基本特性 封裝(把相關的信息(無論數據或方法)存儲在對象中的能力) 繼承(由另一個類(或多個類)得來類的屬性和方法的能力) 多態(一個對象在不同情況下的多種形態) 定義類或對象 第一種:基於Object對象 var person = new Object(); person.name ...


面向對象的三大基本特性

封裝(把相關的信息(無論數據或方法)存儲在對象中的能力)

繼承(由另一個類(或多個類)得來類的屬性和方法的能力)

多態(一個對象在不同情況下的多種形態)

定義類或對象

第一種:基於Object對象

var person = new Object();
person.name = "Rose";
person.age = 18;
person.getName = function () {
    return this.name;
};
console.log(person.name);//Rose
console.log(person.getName);//function () {return this.name;}
console.log(person.getName());//Rose

缺點:不能創建多個對象。

第二種:基於字面量方式

var person = {
    name : "Rose",
    age : 18 ,
    getName : function () {
        return this.name;
    }
};
console.log(person.name);//Rose
console.log(person.getName);//function () {return this.name;}
console.log(person.getName());//Rose

優點:比較清楚的查找對象包含的屬性和方法;

缺點:不能創建多個對象。

第三種:工廠模式

方式一:

function createPerson(name,age) {
    var object = new Object();
    object.name = name;
    object.age = age;
    object.getName = function () {
        return this.name;
    };
    return object;
}
var person1 = createPerson("Rose",18);
var person2 = createPerson("Jack",20);
console.log(person1.name);//Rose
console.log(person2.name);//Jack
console.log(person1.getName === person2.getName);//false//重覆生成函數,為每個對象都創建獨立的函數版本

優點:可以創建多個對象;

缺點:重覆生成函數getName(),為每個對象都創建獨立的函數版本。

方式二:

function createPerson(name,age) {
    var object = new Object();
    object.name = name;
    object.age = age;
    object.getName = getName;
    return object;
}
function getName() {
    return this.name;
}
var person1 = createPerson("Rose",18);
var person2 = createPerson("Jack",20);
console.log(person1.name);//Rose
console.log(person2.name);//Jack
console.log(person1.getName === person2.getName);//true//共用同一個函數

優點:可以創建多個對象;

缺點:從語義上講,函數getName()不太像是Person對象的方法,辨識度不高。

第四種:構造函數方式

方式一:

function Person(name,age) {
    this.name = name;
    this.age = age;
    this.getName = function () {
        return this.name;
    }
}
var person1 = new Person("Rose",18);
var person2 = new Person("Jack",20);
console.log(person1.name);//Rose
console.log(person2.name);//Jack
console.log(person1.getName === person2.getName); //false//重覆生成函數,為每個對象都創建獨立的函數版本

優點:可以創建多個對象;

缺點:重覆生成函數getName(),為每個對象都創建獨立的函數版本。

方式二:

function Person(name,age) {
    this.name = name;
    this.age = age;
    this.getName = getName ;
}
function getName() {
    return this.name;
}
var person1 = new Person("Rose",18);
var person2 = new Person("Jack",20);
console.log(person1.name);//Rose
console.log(person2.name);//Jack
console.log(person1.getName === person2.getName); //true//共用同一個函數

優點:可以創建多個對象;

缺點:從語義上講,函數getName()不太像是Person對象的方法,辨識度不高。

第五種:原型方式

function Person() {
}
Person.prototype.name = 'Rose';
Person.prototype.age = 18;
Person.prototype.getName = function () {
    return this.name;
};
var person1 = new Person();
var person2 = new Person();
console.log(person1.name);//Rose
console.log(person2.name);//Rose//共用同一個屬性
console.log(person1.getName === person2.getName);//true//共用同一個函數

缺點:它省略了為構造函數傳遞初始化參數,這在一定程式帶來不便;另外,最主要是當對象的屬性是引用類型時,它的值是不變的,總是引用同一個外部對象,所有實例對該對象的操作都會影響其它實例:

function Person() {
}
Person.prototype.name = 'Rose';
Person.prototype.age = 18;
Person.prototype.lessons = ["語文","數學"];
Person.prototype.getName = function () {
    return this.name;
};
var person1 = new Person();
person1.lessons.push("英語");
var person2 = new Person();
console.log(person1.lessons);//["語文", "數學", "英語"]
console.log(person2.lessons);//["語文", "數學", "英語"]//person1修改影響了person2

 

第六種:構造函數+原型方式(推薦)

function Person(name,age) {
    this.name = name;
    this.age = age;
}
Person.prototype.getName = function () {
    return this.name;
};
var person1 = new Person('Rose', 18);
var person2 = new Person('Jack', 20);
console.log(person1.name);//Rose
console.log(person2.name);//Jack
console.log(person1.getName === person2.getName);//true//共用原型中定義的方法

缺點:屬性定義在構造函數內,方法定義在構造函數外,與面向對象的封裝思想不符。

第七種:構造函數+動態原型方式(推薦)

方式一:

function Person(name,age) {
    this.name = name;
    this.age = age;
    if (typeof Person._getName === "undefined"){
        Person.prototype.getName = function () {
            return this.name;
        };
        Person._getName = true;
    }
}
var person1 = new Person('Rose', 18);
var person2 = new Person('Jack', 20);
console.log(person1.name);//Rose
console.log(person2.name);//Jack
console.log(person1.getName === person2.getName);//true//共用原型中定義的方法

 

方式二:

function Person(name,age) {
    this.name = name;
    this.age = age;
    if (typeof this.getName !== "function"){
        Person.prototype.getName = function () {
            return this.name;
        };
    }
}
var person1 = new Person('Rose', 18);
var person2 = new Person('Jack', 20);
console.log(person1.name);//Rose
console.log(person2.name);//Jack
console.log(person1.getName === person2.getName);//true//共用原型中定義的方法

 

對象屬性的擴展及刪除

Javascript的對象可以使用 ’.’ 操作符動態的擴展其屬性,可以使用 ’delete’ 關鍵字或將屬性的值設置為 ’undefined’ 來刪除屬性。

function Person(name,age) {
    this.name = name;
    this.age = age;
    if (typeof Person._getName === "undefined"){
        Person.prototype.getName = function () {
            return this.name;
        };
        Person._getName = true;
    }
}
var person = new Person("Rose",18);
person.job = 'Engineer';//添加屬性
console.log(person.job);//Engineer
delete person.job;//刪除屬性
console.log(person.job);//undefined//刪除屬性後值為undefined
person
.age = undefined;//刪除屬性
console.log(person.age);//undefined//刪除屬性後值為undefined

對象屬性類型

數據屬性

特性:

[configurable]:表示能否使用delete操作符刪除從而重新定義,或能否修改為訪問器屬性。預設為true;

[enumberable]:表示是否可通過for-in迴圈返回屬性。預設true;

[writable]:表示是否可修改屬性的值。預設true;

[value]:包含該屬性的數據值。讀取/寫入都是該值。預設為undefined;如上面實例對象person中定義了name屬性,其值為’My name’,對該值的修改都反正在這個位置

function Person(name,age) {
    this.name = name;
    this.age = age;
    if (typeof Person._getName === "undefined"){
        Person.prototype.getName = function () {
            return this.name;
        };
        Person._getName = true;
    }
}
var person = new Person("Rose",18);
Object.defineProperty(person,"name",{configurable:false,writable:false});
person.name = "Jack";
console.log(person.name);//Rose//重新賦值無效
delete person.name;
console.log(person.name);//Rose//刪除無效

註意:

一旦將configurable設置為false,則無法再使用defineProperty將其修改為true(執行會報錯:cannot redefine property : propertyName)

function Person(name,age) {
    this.name = name;
    this.age = age;
    if (typeof Person._getName === "undefined"){
        Person.prototype.getName = function () {
            return this.name;
        };
        Person._getName = true;
    }
}
var person = new Person("Rose",18);
Object.defineProperty(person,"name",{configurable:false,writable:false});
person.name = "Jack";
console.log(person.name);//Rose//重新賦值無效
delete person.name;
console.log(person.name);//Rose//刪除無效
Object.defineProperty(person,"name",{configurable:true,writable:true});//Cannot redefine property: name

 

訪問器屬性

特性:

[configurable]:是否可通過delete操作符刪除重新定義屬性;

[numberable]:是否可通過for-in迴圈查找該屬性;

[get]:讀取屬性時調用,預設:undefined;

[set]:寫入屬性時調用,預設:undefined;

訪問器屬性不能直接定義,必須使用defineProperty()或defineProperties來定義:如下

function Person(name,age) {
    this.name = name;
    this._age = age;
    if (typeof Person._getName === "undefined"){
        Person.prototype.getName = function () {
            return this.name;
        };
        Person._getName = true;
    }
}
var person = new Person("Rose",18);
Object.defineProperty(person,"age",{
    get:function () {
        return this._age;
    },
    set:function (age) {
        this._age = age;
    }});
person.age = 20;
console.log(person.age);//20//person.age=20是使用set方法將20賦值給_age,person.age是使用get方法將_age的讀取出來
console.log(person._age);//20

獲取所有的屬性和屬性的特性

使用Object.getOwnPropertyNames(object)方法可以獲取所有的屬性;

使用Object.getOwnPropertyDescriptor(object,property)方法可以取得給定屬性的特性;

function Person(name,age) {
    this.name = name;
    this._age = age;
    if (typeof Person._getName === "undefined"){
        Person.prototype.getName = function () {
            return this.name;
        };
        Person._getName = true;
    }
}
var person = new Person("Rose",18);
Object.defineProperty(person,"age",{
    get:function () {
        return this._age;
    },
    set:function (age) {
        this._age = age;
    }});
console.log(Object.getOwnPropertyNames(person));//["name", "_age", "age"]
console.log(Object.getOwnPropertyDescriptor(person,"age"));//{enumerable: false, configurable: false, get: function, set: function}

對於數據屬性,可以取得:configurable,enumberable,writable和value;

對於訪問器屬性,可以取得:configurable,enumberable,get和set;

繼承機制實現

對象冒充

function Father(name) {
    this.name = name ;
    this.getName = function () {
        return this.name;
    }
}
function Son(name,age) {
    this._newMethod = Father;
    this._newMethod(name);
    delete  this._newMethod;

    this.age = age;
    this.getAge = function () {
        return this.age;
    }
}
var father = new Father("Tom");
var son = new Son("Jack",18);
console.log(father.getName());//Tom
console.log(son.getName());//Jack//繼承父類getName()方法
console.log(son.getAge());//18

多繼承(利用對象冒充可以實現多繼承)

function FatherA(name) {
    this.name = name ;
    this.getName = function () {
        return this.name;
    }
}
function FatherB(job) {
    this.job = job;
    this.getJob = function () {
        return this.job;
    }
}
function Son(name,job,age) {
    this._newMethod = FatherA;
    this._newMethod(name);
    delete  this._newMethod;
    this._newMethod = FatherB;
    this._newMethod(job);
    delete  this._newMethod;

    this.age = age;
    this.getAge = function () {
        return this.age;
    }
}
var fatherA = new FatherA("Tom");
var fatherB = new FatherB("Engineer");
var son = new Son("Jack","Programmer",18);
console.log(fatherA.getName());//Tom
console.log(fatherB.getJob());//Engineer
console.log(son.getName());//Jack//繼承父類FatherA的getName()方法
console.log(son.getJob());//Programmer//繼承父類FatherB的getJob()方法
console.log(son.getAge());//18

 

call()方法

function Father(name) {
    this.name = name ;
    this.getName = function () {
        return this.name;
    }
}
function Son(name,job,age) {
    Father.call(this,name);

    this.age = age;
    this.getAge = function () {
        return this.age;
    }
}
var father = new Father("Tom");
var son = new Son("Jack","Programmer",18);
console.log(father.getName());//Tom
console.log(son.getName());//Jack//繼承父類getName()方法
console.log(son.getAge());//18

 

多繼承(利用call()方法實現多繼承)

function FatherA(name) {
    this.name = name ;
    this.getName = function () {
        return this.name;
    }
}
function FatherB(job) {
    this.job = job;
    this.getJob = function () {
        return this.job;
    }
}
function Son(name,job,age) {
    FatherA.call(this,name);
    FatherB.call(this,job);

    this.age = age;
    this.getAge = function () {
        return this.age;
    }
}
var fatherA = new FatherA("Tom");
var fatherB = new FatherB("Engineer");
var son = new Son("Jack","Programmer",18);
console.log(fatherA.getName());//Tom
console.log(fatherB.getJob());//Engineer
console.log(son.getName());//Jack//繼承父類FatherA的getName()方法
console.log(son.getJob());//Programmer//繼承父類FatherB的getJob()方法
console.log(son.getAge());//18

 

apply()方法

function Father(name) {
    this.name = name ;
    this.getName = function () {
        return this.name;
    }
}
function Son(name,job,age) {
    Father.apply(this,new Array(name));

    this.age = age;
    this.getAge = function () {
        return this.age;
    }
}
var father = new Father("Tom");
var son = new Son("Jack","Programmer",18);
console.log(father.getName());//Tom
console.log(son.getName());//Jack//繼承父類getName()方法
console.log(son.getAge());//18

多繼承(利用apply()方法實現多繼承)

function FatherA(name) {
    this.name = name ;
    this.getName = function () {
        return this.name;
    }
}
function FatherB(job) {
    this.job = job;
    this.getJob = function () {
        return this.job;
    }
}
function Son(name,job,age) {
    FatherA.apply(this,new Array(name));
    FatherB.apply(this,new Array(job));

    this.age = age;
    this.getAge = function () {
        return this.age;
    }
}
var fatherA = new FatherA("Tom");
var fatherB = new FatherB("Engineer");
var son = new Son("Jack","Programmer",18);
console.log(fatherA.getName());//Tom
console.log(fatherB.getJob());//Engineer
console.log(son.getName());//Jack//繼承父類FatherA的getName()方法
console.log(son.getJob());//Programmer//繼承父類FatherB的getJob()方法
console.log(son.getAge());//18

原型鏈方法

function Father() {
}
Father.prototype.name = "Tom";
Father.prototype.getName = function () {
  return this.name;
};
function Son() {
}
Son.prototype = new Father();
Son.prototype.age = 18;
Son.prototype.getAge = function () {
    return this.age;
};
var father = new Father();
var son = new Son();
console.log(father.getName());//Tom
console.log(son.getName());//Tom//繼承父類FatherA的getName()方法
console.log(son.getAge());//18

混合方式(call()+原型鏈)

function Father(name) {
    this.name = name;
}
Father.prototype.getName = function () {
  return this.name;
};
function Son(name,age) {
    Father.call(this,name);
    this.age = age;
}
Son.prototype = new Father();
Son.prototype.getAge = function () {
    return this.age;
};
var father = new Father("Tom");
var son = new Son("Jack",18);
console.log(father.getName());//Tom
console.log(son.getName());//Jack//繼承父類Father的getName()方法
console.log(son.getAge());//18

多態機制實現

function Person(name) {
    this.name = name;
    if (typeof this.getName !== "function"){
        Person.prototype.getName = function () {
            return this.name;
        }
    }
    if (typeof this.toEat !== "function"){
        Person.prototype.toEat = function (animal) {
            console.log( this.getName() + "說去吃飯:");
            animal.eat();
        }
    }
}
function Animal(name) {
    this.name = name;
    if (typeof this.getName !== "function"){
        Animal.prototype.getName = function () {
            return this.name;
        }
    }
}
function Cat(name) {
    Animal.call(this,name);
    if (typeof this.eat !== "function"){
        Cat.prototype.eat = function () {
            console.log(this.getName() + "吃魚");
        }
    }
}
Cat.prototype = new Animal();
function Dog(name) {
    Animal.call(this,name);
    if (typeof this.eat !== "function"){
        Dog.prototype.eat = function () {
            console.log(this.getName() + "啃骨頭");
        }
    }
}
Dog.prototype = new Animal();

var person = new Person("Tom");
person.toEat(new Cat("cat"));//Tom說去吃飯:cat吃魚
person
.toEat(new Dog("dog"));//Tom說去吃飯:dog啃骨頭


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1、我們希望在註冊頁面中添加一個欄位(籍貫),當用戶選擇一個具體的省份,在後面的下拉列表中動態載入該省份下所有的城市。顯示的效果如下: 2、步驟分析: 第一步:確定事件(onchange)併為其綁定一個函數 第二步:創建一個二維數組用於存儲省份和城市 第三步:獲取用戶選擇的省份 第四步:遍歷二維數組 ...
  • 寫在前面: 本人從事軟體開發方面三年了,一直是從事著.net開發,但是我個人熱衷於前端開發,由於開發經驗不足即使效勞過三家公司了也沒有真正去從事著前端開發這個職位,雖然如此但是我還是專註著前端開發的(哪怕現在還是半桶水)。為了繼續好好的學習前端開發就藉此博客記錄下學習的心路歷程,把一直以來所學的捋一 ...
  • [1]概述 [2]基本用法 [3]參數設置 [4]配置項 [5]動畫指令 [6]特色動畫 [7]高級用法 [8]UI插件 ...
  • 如果你對jquery比較熟悉的話,應該用過 eq, first, last, get, prev, next, siblings等過濾器和方法。本文,我們就用迭代設計模式來封裝實現,類似的功能 ...
  • 歡迎各位同學加入: React-Native群:397885169 大前端群:544587175 大神超多,熱情無私幫助解決各種問題。 我想我寫的這篇博文可以幫助到很多人,接下來要分享的東西,對app而言很重要,很常見,我先上圖,大家看效果! 為什麼我們要這麼做呢?這體現出對用戶的友好,當用戶第一次 ...
  • 學習資源: Angular官網(建議翻牆):https://angularjs.org Angular中文官網:https://angular.cn 菜鳥教程:http://www.runoob.com/angularjs2 官網Demo: 我的學習步驟是從官網教程的DEMO下手,完全跟隨教程一步一 ...
  • 本文,我們接著之前的框架繼續擴展,這次擴展了一共有5個與字元串位置相關的方法 between( left, right ) 返回兩個字元串之間的內容, 如果第二個參數沒有傳遞,返回的是找到的第一個參數 之後 到 字元串結尾的所有字元串 如果第二個參數傳遞了,但是從left這個位置查找不到,就返回空字 ...
  • html代碼 <!DOCTYPE html><html><head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>實現簡單的tab框</title> <link rel="st ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...