JavaScript面向對象與原型

来源:http://www.cnblogs.com/sctnl/archive/2016/11/21/6086121.html
-Advertisement-
Play Games

工廠模式:無法識別對象 function createObject(name, age) { //集中實例化的函數 var obj = new Object(); obj.name = name; obj.age = age; obj.run = function () { return this. ...


工廠模式:無法識別對象

function createObject(name, age) { //集中實例化的函數
  var obj = new Object();
  obj.name = name;
  obj.age = age;
  obj.run = function () {
    return this.name + this.age + '運行中...';
  };
  return obj;
}
var box1 = createObject('Lee', 100); //第一個實例
var box2 = createObject('Jack', 200); //第二個實例
alert(box1.run());
alert(box2.run()); //保持獨立

alert(typeof box1); //Object
alert(box1 instanceof Object); //true

構造函數(構造方法):可以識別對象

function Box(name, age) { //構造函數模式
  this.name = name;
  this.age = age;
  this.run = function () {
    return this.name + this.age + '運行中...';
  };
}
var box1 = new Box('Lee', 100); //new Box()即可
var box2 = new Box('Jack', 200);

alert(box1.run());
alert(box1 instanceof Box); //很清晰的識別他從屬於 Box

構造函數的方法有一些規範:

1.函數名和實例化構造名相同且大寫,(PS:非強制,但這麼寫有助於區分構造函數和普通函數);

2.通過構造函數創建對象,必須使用 new 運算符。

var o = new Object();
Box.call(o, 'Jack', 200) //對象冒充調用
alert(o.run());

原型(共用):創建的每個函數都有一個 prototype(原型)屬性,這個屬性是一個對象,它的用途是包含可以由特定類型的所有實例共用的屬性和方法。邏輯上可以這麼理解:prototype 通過調用構造函數而創建的那個對象的原型對象。使用原型的好處可以讓所有對象實例共用它所包含的屬性和方法。也就是說,不必在構造函數中定義對象信息,而是可以直接將這些信息添加到原型中。

unction Box() {} //聲明一個構造函數
Box.prototype.name = 'Lee'; //在原型里添加屬性
Box.prototype.age = 100;
Box.prototype.run = function () { //在原型里添加方法
  return this.name + this.age + '運行中...';
};

在原型模式聲明中,多了兩個屬性,這兩個屬性都是創建對象時自動生成的。

__proto__屬性:是實例指向原型對象的一個指針,它的作用就是指向構造函數的原型屬性 constructor 。通過這兩個屬性,就可以訪問到原型里的屬性和方法了。

PS:IE 瀏覽器在腳本訪問__proto__會不能識別,火狐和谷歌瀏覽器及其他某些瀏覽器均能識別。雖然可以輸出,但無法獲取內部信息。

判斷一個對象是否指向了該構造函數的原型對象,可以使用 isPrototypeOf()方法來測試。

exp:alert(Box.prototype.isPrototypeOf(box)); //只要實例化對象,即都會指向

原型模式的執行流程:
1.先查找構造函數實例里的屬性或方法,如果有,立刻返回;
2.如果構造函數實例里沒有,則去它的原型對象里找,如果有,就返回;

雖然我們可以通過對象實例訪問保存在原型中的值,但卻不能訪問通過對象實例重寫原型中的值。

var box1 = new Box();
alert(box1.name); //Lee,原型里的值
box1.name = 'Jack';
alert(box.1name); //Jack,就近原則,
var box2 = new Box();
alert(box2.name); //Lee,原型里的值,沒有被 box1 修改
如果想要 box1 也能在後面繼續訪問到原型里的值,可以把構造函數里的屬性刪除即可 ,具體如下:
delete box1.name; //刪除屬性
alert(box1.name);
如何判斷屬性是在構造函數的實例里,還是在原型里?可以使用 hasOwnProperty()函數來驗證:

alert(box.hasOwnProperty('name')); //實例里有返回 true,否則返回 false

 

in 操作符會在通過對象能夠訪問給定屬性時返回 true,無論該屬性存在於實例中還是原型中。
alert('name' in box); //true,存在實例中或原型中
我們可以通過 hasOwnProperty()方法檢測屬性是否存在實例中,也可以通過 in 來判斷實例或原型中是否存在屬性。那麼結合這兩種方法,可以判斷原型中是否存在屬性。

function isProperty(object, property) { //判斷原型中是否存在屬性
  return !object.hasOwnProperty(property) && (property in object);
}

var box = new Box();
alert(isProperty(box, 'name')) //true,如果原型有

為了讓屬性和方法更好的體現封裝的效果,並且減少不必要的輸入,原型的創建可以使用字面量的方式:

function Box() {};
Box.prototype = { //使用字面量的方式
  name : 'Lee',
  age : 100,
  run : function () {
    return this.name + this.age + '運行中...';
  }
};

使用構造函數創建原型對象和使用字面量創建對象在使用上基本相同,但還是有一些區別,字面量創建的方式使用 constructor 屬性不會指向實例,而會指向 Object,構造函數創建的方式則相反。

如果想讓字面量方式的 constructor 指向實例對象,那麼可以這麼做:
Box.prototype = {
  constructor : Box, //直接強制指向即可
};

原型對象不僅僅可以在自定義對象的情況下使用,而 ECMAScript 內置的引用類型都可以使用這種方式,並且內置的引用類型本身也使用了原型。

alert(Array.prototype.sort); //sort 就是 Array 類型的原型方法
alert(String.prototype.substring); //substring 就是 String 類型的原型方法
String.prototype.addstring = function () { //給 String 類型添加一個方法
  return this + ',被添加了!'; //this 代表調用的字元串
};
alert('Lee'.addstring()); //使用這個方法

PS:儘管給原生的內置引用類型添加方法使用起來特別方便,但我們不推薦使用這種方法。因為它可能會導致命名衝突,不利於代碼維護。

動態原型模式

function Box(name ,age) { //將所有信息封裝到函數體內
  this.name = name;
  this.age = age;
  if (typeof this.run != 'function') { //僅在第一次調用的初始化
    Box.prototype.run = function () {
      return this.name + this.age + '運行中...';
    };
  }
}
var box = new Box('Lee', 100);
alert(box.run());

PS:使用動態原型模式,要註意一點,不可以再使用字面量的方式重寫原型,因為會切斷實例和新原型之間的聯繫。

寄生構造函數

function Box(name, age) {
  var obj = new Object();
  obj.name = name;
  obj.age = age;
  obj.run = function () {
    return this.name + this.age + '運行中...';
  };
  return obj;
}

穩妥構造函數

function Box(name , age) {
  var obj = new Object();
  obj.run = function () {
    return name + age + '運行中...'; //直接列印參數即可
  };
  return obj;
}
var box = Box('Lee', 100); //直接調用函數
alert(box.run());

繼承:依靠原型鏈完成

function Box() { //Box 構造
  this.name = 'Lee';
}
function Desk() { //Desk 構造
  this.age = 100;
}
Desk.prototype = new Box(); //Desc 繼承了 Box,通過原型,形成鏈條
var desk = new Desk();
alert(desk.age);
alert(desk.name); //得到被繼承的屬性
function Table() { //Table 構造
  this.level = 'AAAAA';
}
Table.prototype = new Desk(); //繼續原型鏈繼承
var table = new Table();
alert(table.name); //繼承了 Box 和 Desk

在 JavaScript 里,被繼承的函數稱為超類型(父類,基類也行,其他語言叫法),繼承的函數稱為子類型(子類,派生類)。繼承也有之前問題,比如字面量重寫原型會中斷關係,使用引用類型的原型,並且子類型還無法給超類型傳遞參數。

對象冒充(偽造對象、經典繼承、借用構造函數):解決引用共用和超類型無法傳參的問題

function Box(age) {
  this.name = ['Lee', 'Jack', 'Hello']
  this.age = age;
}
function Desk(age) {
  Box.call(this, age); //對象冒充,給超類型傳參

}
var desk = new Desk(200);
alert(desk.age);
alert(desk.name);
desk.name.push('AAA'); //添加的新數據,只給 desk
alert(desk.name);

組合繼承:原型鏈+ 借用構造函數

function Box(age) {
  this.name = ['Lee', 'Jack', 'Hello']
  this.age = age;
}
Box.prototype.run = function () {
  return this.name + this.age;
};
function Desk(age) {
  Box.call(this, age); //對象冒充
}
Desk.prototype = new Box(); //原型鏈繼承
var desk = new Desk(100);
alert(desk.run());

寄生組合繼承

function obj(o) {     //傳遞一個字面量函數
  function F() {}    //臨時新建一個構造函數,用來存儲傳遞進來的對象
  F.prototype = o;    //將o對象實例賦值給F構造的原型對象

  return new F();    //返回實例化後的構造函數
}
function create(box, desk) {
  var f = obj(box.prototype);
  f.constructor = desk;
  desk.prototype = f;
}
function Box(name) {
  this.name = name;
  this.arr = ['哥哥','妹妹','父母'];
}
Box.prototype.run = function () {
  return this.name;
};
function Desk(name, age) {
  Box.call(this, name);
  this.age = age;
}
inPrototype(Box, Desk); //通過這裡實現繼承
var desk = new Desk('Lee',100);
desk.arr.push('姐姐');
alert(desk.arr);
alert(desk.run()); //只共用了方法
var desk2 = new Desk('Jack', 200);
alert(desk2.arr); //引用問題解決

 


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

-Advertisement-
Play Games
更多相關文章
  • 筆記說明 《CSS3實戰手冊第3版(影印版)》可以消除Web設計工作的痛苦,並且帶給你:HTML——重新入門。如果你是HTML新手,你會學到如何以CSS友好的方式進行基本頁面構造。若你是HTML高手,你將學會如何像CSS設計者那樣思考。 全書共18章,五大部分600來頁。 可能是出版方認為本書英文很 ...
  • SASS是什麼 傳統的CSS是一種單純的描述性樣式文件,然而SASS可以對CSS進行預編譯處理。 在SASS源碼中可以使用變數、函數、繼承等動態語言的特性,並且可以編譯成CSS文件。 安裝與使用 安裝 由於sass是ruby寫的,所以想要使用sass就需要安裝ruby環境。然後再使用gem安裝sas ...
  • 好久沒寫博客了,不想廢話,直接欣賞效果! 點擊這裡,查看完美效果! 附完整代碼: <!doctype html> <html> <head> <meta charset="utf-8"> <title>heart nick</title> <style> canvas { position: abs ...
  • 在CSS中,a標簽有4種偽類,分別為: 對其稍有瞭解的前端er都知道,4個偽類是有固定順序的(LVHA),否則很容易出現預期之外的效果。 大部分人,都會用自己的方式,對這個順序死記硬背。 熟記順序,無疑是寫樣式時最快捷的方法,牛人們的記憶方法也是五花八門。 我見過有醬嬸的:lv的包包hao,這倒是實 ...
  • 如何在Node.js中encode一個字元串呢?是否也像在PHP中使用base64_encode()一樣簡單? 在Node.js中有許多encoding字元串的方法,而不用像在JavaScript中那樣定義各種不同的全局函數。下麵是如何在Node.js中將一個普通字元串encode成Base64格式 ...
  • 下載地址http://download.csdn.net/detail/shouce_ren/9689243 百度雲下載地址 ...
  • Angularjs內置的過濾器(filter)為我們的數據信息格式化提供了比較強大的功能,比如:格式化時間,日期、格式化數字精度、語言本地化、格式化貨幣等等。但這些過濾器一般都是在VIEW中使用的,比如格式化時間/日期的VIEW視圖代碼: 那麼問題來了,如果我需要在控制器(controller)的j ...
  • 一、三個對話框 1、alert("提示信息") 彈出只帶有一個確定按鈕的對話框2、confirm("提示信息") 彈出有確定和取消按鈕的對話框3、prompt("提示信息",預設值) 可輸入內容的對話框,返回null 二、數據類型 1、var通用類型2、數據類型轉換(1)將變數轉為整數類型parse ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...