JavaScript --- [學習筆記]觀察者模式 理解對象 工廠模式 構造函數模式

說明

  • 本系列(JS基礎梳理)為后面TCP的模擬實現做準備
  • 本篇的主要內容: 觀察者模式、工廠模式、構造函數模式 和 對對象的理解

1. 觀察者模式

  • 參考JavaScript設計模式

1.1 消息注冊方法

“將訂閱者注冊的消息推入到消息隊列中”

[算法思路] :

  1. 在推入到消息隊列時,如果此消息不存在則應該創建一個該消息類型并將該消息放入消息隊列中
  2. 如果此消息存在則應該將消息執行方法推入該消息對應的執行方法隊列中(保證多個模塊注冊一則消息時能順利執行)
regist: function(type, fn) {// 如果消息不存在則應該創建一個該消息類型if(typeof __message[type] === 'undefined') {// 將動作推入到該消息對應的動作執行隊列中__message[type] = [fn];// 如果此消息存在} else {// 將動作方法推入該消息對應的動作執行序列中__message[type].push(fn);}
}

1.2 發布消息方法

“對于發布消息方法,其功能是當觀察者發布一個消息時將所有訂閱者的消息一次執行”

fire: function(type, args) {// 如果該消息沒有被注冊,則返回if(!__message[type])return;// 定義消息信息var events = {type: type,args: args || {}},i = 0,len = __message[type].length;// 遍歷消息動作for(; i < len; i++) {// 依次執行注冊的消息對應的動作序列__messages[type][i].call(this, events);}
}

1.3 消息注銷方法

“將訂閱者注銷的消息從消息隊列中清除”

remove: function(type, fn) {// 如果消息隊列存在if(__messages[type] instanceof Array){// 從最后一個消息動作遍歷var i = __message[type].length - 1;for(; i>= 0; i--) {// 如果存在該動作則在消息動作序列中移除相應動作__messages[type][i] === fn && __messages[type].splice(i, 1);}}
}

2.面向對象對象的程序設計

  • 參考JavaScript高級程序設計(第三版)

面向對象(Object-Oriented, OO)的語言有一個標志,那就是它們都有類的概念,而通過類可以創建任意多個具有相同屬性和方法的對象。ECMAScript中沒有類的概念,因此它的對象也與類的語言的對象有所不同。

ECMA-262把對象定義為:“無序屬性的集合,其屬性可以包含基本值、對象或者函數”。嚴格來講,這就相當于說對象是一組沒有特定順序的值。對象的每個屬性和方法都有一個名字,而每個名字都映射到一個值。正因為這樣,我們可以把ECMAScript的對象想象成散列表:無非就是一組名值對,其中值可以是數據或函數

2.1 理解對象

  • 創建一個對象的最簡單方式
  • 創建一個Object的實例,然后再為它添加屬性和方法
var person = new Object();
person.name = "Nicholas";
person.age = 29;
person.job = "Software Engineer";
person.sayName = function() {alert(this.name);
};

早期的JavaScript開發人員使用上述方法創建對象。幾年后,對象字面量成為創建這種對象的首選模式:

var person = {name: "Nicholas",age: 29,job: "Software Engineer",sayName: function(){alert(this.name);}
};

2.1.1 屬性類型

ECMA-262第5版在定義只有內部才用的特征(attribute)時,描述了屬性(property)的各種特征。ECMA-262定義這些特性是為了給JavaScript引擎用的,因此在JavaScript中我們不能直接訪問它們。為了表示特性是內部值,該規范把它們放在了兩對兒方括號中,例如[ [Enumerable] ]

  1. 數據屬性
    數據屬性包含一個數據值的位置。在這個位置可以讀取和寫入值。數據屬性有4個描述其行為的特性

    • [ [Configurable]]: 表示能否通過delete刪除屬性從而重新定義屬性,能否修改屬性的特性,或者能否把屬性修改為訪問器屬性。像前面例子中那樣直接在對象上定義的屬性,默認為true。
    • [ [Enumberable]]:表示能否通過for-in循環返回屬性,默認為true。
    • [ [Writable]]:表示能否修改屬性的值,默認為true。
    • [ [Value]]:屬性的數據值,默認為undefined

    對于像前面栗子中的那樣直接在對象上定義屬性,它們的[ [Configurable]]、[ [Enumberable]]和[ [Writable]]特性都被設置為true,而[ [Value]]特性被設置為指定的值。

var person = {name: "Nicholas"
}

要修改屬性默認的特性,必須使用ECMAScript5的Object.defineProperty()方法。這個方法接收三個參數:屬性所在的對象、屬性的名字和一個描述符對象。其中,描述符(descriptor)對象的屬性必須是:configurable、enumerable、writable和value。

var person = {};
Object.defineProperty(person,"name", {writable: false,value: "Nicholas"
});
  1. 訪問器屬性
    訪問器屬性不包含數據值;它們包含一對兒getter和setter函數。在讀取訪問器屬性時,會調用getter函數,這個函數負責返回有效的值;在寫入訪問器屬性時,會調用setter函數并傳入新值,這個函數負責決定如何處理數據。
  • [[Configurable]]: 表示能否通過delete刪除屬性從而重新定義屬性。
  • [[Enumerable]]: 表示能否通過for-in循環返回屬性。
  • [[Get]]:在讀取屬性時調用的函數,默認值為undefined
  • [[Set]]:在寫入屬性時調用的函數,默認值為undefined

訪問器屬性不能直接定義,必須使用Object.defineProperty()來定義。

var book = {_year: 2004,edition: 1
};
Object.defineProperty(book, "year", {get: function() {return this._year;},set: function(newValue) {if(newValue > 2004){this._year = newValue;this.edition += newValue - 2004;}}
});
book.year = 2005;
alert(book.edition);

2.1.2 定義多個屬性

ECAMAScript5 又定義了一個Object.defineProperties()方法。利用這個方法可以通過描述符一次定義多個屬性

var book = {};
Object.defineProperties(book, {_year: {writable: true,value: 2004},edition: {writable: true,value: 1},year: {get: function() {return this._year;},set: function(newValue) {if(newValue > 2004) {this._year = newValue;this.edition += newValue - 2004;}}}
});

2.1.3 讀取屬性的特性

使用ECMAScript5的Object.getOwnPropertyDescriptor()方法,可以取得給定屬性的描述符。這個方法接收兩個參數: 屬性所在的對象和要讀取其描述符的屬性名稱。返回值是一個對象,如果是訪問器屬性,這個對象的屬性又configurable、enumerable、get和set;如果是數據屬性,這個對象的屬性又configurable、enumerable、writable和value。

var book = {};
Object.defineProperties(book, {_year: {value: 2004},edition: {value: 1},year: {get: function(){return this._year;},set: function(newValue){if (newValue > 2004) {this._year = newValue;this.edition += newValue - 2004;}}}
});
var descriptor = Object.getOwnPropertyDescriptor(book, "_year");
alert(descriptor.value);    // 2004
alert(descriptor.configurable);   // false
alert(typeof descriptor.get);   // "undefined"var descriptor = Object.getOwnPropertyDescriptor(book, "year");
alert(descriptor.value);
alert(descriptor.enumerable);
alert(typeof descriptor.get);

2.2 工廠模式

  • 對象字面量的缺點: 使用同一個接口創建很多對象,會產生大量的重復代碼
  • 抽象了創建具體對象的過程
  • 考慮到ECMAScript中無法創建類,開發人員發明了如下函數:
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("Nicholas", 29, "Software Engineer");
var person2 = createPerson("Greg", 27, "Doctor");
  • 工廠模式的缺點: 沒有解決對象識別問題,即怎樣知道一個對象的類型.(如上面應該可以檢測出是一個createPerson類)

2.3 構造函數模式

  • ECMAScript中的構造函數可用來創建特定類型的對象。
function Person(name, age, job) {this.name = name;this.age = age;this.job = job;this.sayName = function(){alert(this.name);};
}
var person1 = new Person("Nicholas", 29, "Softwate Engineer");
var person2 = new Person("Greg", 27, "Doctor");

2.3.1 構造函數和工廠模式的區別

  • 沒有顯示地創建對象
  • 直接將屬性和方法賦給了this對象
  • 沒有return語句

2.3.2 new構造函數

  • 使用new操作符調用構造函數,實際上會經歷以下4個步驟:
    (1) 創建一個新對象;
    (2) 將構造函數的作用域賦給新對象(this就指向了這個新對象);
    (3) 指向構造函數中的代碼(為這個新對象添加屬性);
    (4) 返回新對象

[栗子]:

  1. 檢測person1是不是Person的實例
console.log(person1 instanceof Person);

創建自定義的構造函數意味著將來可以將它的實例標識為一種特定的類型。

2.3.3 不使用new操作符調用構造函數

function Person(name, age, job) {this.name = name;this.age = age;this.job = job;this.sayName = function(){alert(this.name);}
}
Person("Greg", 27, "Doctor");
alert(Window.name);     // "Greg"
  • 將會在全局對象上掛載這些屬性和方法.

2.3.4 構造函數的問題

  • 構造函數的主要問題是: “每個方法都要在每個實例上重新創建一遍”
// 前面的構造函數等價于
function Person(name, age, job){this.name = name;this.age = age;this.job = job;this.sayName = new Function("alert(this.name)");
}
  • 從以上角度來看,每一個Person實例都包含一個不同的Function實例
  • 更確切的講,以構造函數創建的函數,會導致不同的作用域鏈和標識符解析
  • 以下代碼可以證明函數的方法是不同的.
console.log(person1.sayName === person2.sayName);   //false

3.小結

3.1 工廠模式

  • 抽象了對象的創建過程
  • 缺點是: 使用工廠模式創建的對象是無法識別為某一個類的

3.2 構造函數模式

  • 解決了工廠模式類的識別問題.

  • 缺點是: 不同實例之間相同的方法是不同的.浪費了資源.

  • 解決辦法: 原型模式

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/250390.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/250390.shtml
英文地址,請注明出處:http://en.pswp.cn/news/250390.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

java_day19_MVC和配置文件

簡單的MVC設計 MVC的全名是Model View Controller&#xff0c;是模型(model)&#xff0d;視圖(view)&#xff0d;控制器(controller)的縮寫&#xff0c;是一種軟件設計典范。它是用一種業務邏輯、數據與界面顯示分離的方法來組織代碼&#xff0c;將眾多的業務邏輯聚集到一個部件…

Problem I: 打印金字塔

#include<stdio.h> int main() {int n,i,j,k;scanf("%d",&n);for(i1;i<n;i){for(j1;j<n-i;j)printf(" ");for(k1;k<2*i-1;k)printf("*");printf("\n");}return 0; } HINT 用雙重循環做&#xff0c;外循環代表行數&…

webpack --- 發布環境的配置 代碼壓縮 代碼分類

說明 源代碼本篇主要對發布環境的配置說明前面2點是對webpack的一個復習.第3點開始,逐步配置部署代碼 1. Webpack發布的策略 2.1 在實際開發中,一般會有兩套方案: 開發期間的項目:包含了測試文件、測試數據、開發工具、測試工具等相關配置,有利于項目的開發和測試,但是這些文…

salesforce lightning零基礎學習(三) 表達式的!(綁定表達式)與 #(非綁定表達式)

在salesforce的classic中&#xff0c;我們使用{!expresion}在前臺頁面展示信息&#xff0c;在lightning中&#xff0c;上一篇我們也提及了&#xff0c;如果展示attribute的值&#xff0c;可以使用{!v.expresion}展示信息。 lightning在component中解析動態值的時候&#xff0c;…

sqlserver學習3---sql函數

一、SQL DML 和 DDL 可以把 SQL 分為兩個部分&#xff1a;數據操作語言 (DML) 和 數據定義語言 (DDL)。 SQL (結構化查詢語言)是用于執行查詢的語法。但是 SQL 語言也包含用于更新、插入和刪除記錄的語法。 查詢和更新指令構成了 SQL 的 DML 部分&#xff1a; SELECT - 從數據庫…

JavaScript --- [學習筆記] 原型模式

說明 接JavaScript — > [學習筆記]觀察者模式 & 理解對象 & 工廠模式 & 構造函數模式上一篇構造函數模式創建的實例,不同實例的同一個方法是不相等的,為了解決這個問題.出現了原型模式 1. 原型模式 具體做法是,不在構造函數中定義對象實例的信息,而是將這些…

網絡協議各層概述

網絡協議概述 OSI是一個開放性的通信系統互連參考模型&#xff0c;他是一個定義得非常好的協議規范。OSI模型有7層結構&#xff0c;每層都可以有幾個子層。 OSI的7層從上到下分別是 7 應用層 6 表示層 5 會話層 4 傳輸層 3 網絡層 2 數據鏈路層 1 物理層&#xff1b; 其中高層&…

A start job is running for Raise network interface(5min 13s )問題解決方法

命令&#xff1a;sudo vim /etc/systemd/system/network-online.target.wants/networking.service將里面的TimeoutStartSec5min 修改為TimeoutStartSec2sec 然后重啟系統&#xff0c;就可以生效了&#xff0c;開機速度很快 轉載于:https://www.cnblogs.com/sea-stream/p/98615…

javascript --- 實現對象的深拷貝

淺拷貝和深拷貝 淺拷貝: 只拷貝一層.當對象是復雜數據類型(Object、 Array)時,只拷貝引用深拷貝: 多層拷貝.復雜數據類型,會重新分配內存空間. 實現淺拷貝的2種方法 使用for ... in 實現 var obj {name: marron,age: 18,msg: {sex: "1" } } var o {}; for(let …

Qt與FFmpeg聯合開發指南(二)——解碼(2):封裝和界面設計

與解碼相關的主要代碼在上一篇博客中已經做了介紹&#xff0c;本篇我們會先討論一下如何控制解碼速度再提供一個我個人的封裝思路。最后回歸到界面設計環節重點看一下如何保證播放器界面在縮放和拖動的過程中保證視頻畫面的寬高比例。 一、解碼速度 播放器播放媒體文件的時候播…

Bzoj1051 受歡迎的牛

每一頭牛的愿望就是變成一頭最受歡迎的牛。現在有 N 頭牛&#xff0c;給你 M 對整數 (A,B)&#xff0c;表示牛 A 認為牛 B 受歡迎。這種關系是具有傳遞性的&#xff0c;如果 A 認為 B 受歡迎&#xff0c;B 認為 C 受歡迎&#xff0c;那么牛 A 也認為牛 C 受歡迎。你的任務是求出…

node --- 模塊加載機制

1. Node.js中模塊加載機制 1.1 模塊查找規則-當模塊擁有路徑但沒有后綴時 require(./find.js); require(./find);require方法根據模塊路徑查找模塊,如果是完整路徑,直接進入模塊如果模塊后綴省略,先找同名JS文件再找同名JS文件夾 require(./find); // 以上會先找到命令行目錄…

51Nod 蜥蜴和地下室(搜索)

哈利喜歡玩角色扮演的電腦游戲《蜥蜴和地下室》。此時&#xff0c;他正在扮演一個魔術師。在最后一關&#xff0c;他必須和一排的弓箭手戰斗。他唯一能消滅他們的辦法是一個火球咒語。如果哈利用他的火球咒語攻擊第i個弓箭手&#xff08;他們從左到右標記&#xff09;&#xff…

多線程——實現Runnable接口實現一個多線程

實現Runnable接口實現一個多線程 Runnable接口源碼&#xff1a; package java.lang; //Runnable接口源碼只有一個run方法 public interface Runnable {public abstract void run(); } 實現Runnable的兩個多線程類&#xff1a; public class RunnableThread1 implements Runnabl…

javascript --- 文件上傳即時預覽 閉包實現多圖片即時預覽

使用javascript原生功能實現,點擊上傳文件,然后再網頁上顯示出來 1. 初級顯示 1.1 準備一個input標簽和一個img標簽 <input typefile id"file"> <img id"preview" src"">1.2 js代碼如下 // 將上傳的圖片顯示到頁面上function sho…

第一次作業:深入Linux源碼分析進程模型

一.進程的概念 第一&#xff0c;進程是一個實體。每一個進程都有它自己的地址空間&#xff0c;一般情況下&#xff0c;包括文本區域&#xff08;text region&#xff09;、數據區域&#xff08;data region&#xff09;和堆棧&#xff08;stack region&#xff09;。文本區域存…

關于模型驗證那點事兒

今天應笑笑老師之問&#xff0c;做了一個模型驗證的例子&#xff0c;發現之前對這個東西的理解太片面&#xff0c;重新整理了一下思路 字段驗證優先級高于類驗證 什么是類驗證呢&#xff1f;就是兩個字段組合的驗證&#xff0c;比如你Admin不允許修改密碼&#xff0c;你修改密碼…

mongoose --- createUser

說明 源代碼記錄、遺忘回顧mongoDB默認不需要使用賬號密碼即可訪問數據庫.下面是給mongoDB添加超級管理員和普通用戶的方法 以系統管理員的方式運行powershell連接數據庫 mongo查看數據庫: show dbs切換到admin數據庫: use admin創建超級管理員賬戶: db.createUser({user: roo…

Win10安裝MySQL5.7.22 解壓縮版(手動配置)方法

1.下載地址&#xff1a;https://dev.mysql.com/downloads/mysql/5.7.html#downloads 直接點擊下載項 下載后&#xff1a; 2.可以把解壓的內容隨便放到一個目錄&#xff0c;我的是如下目錄&#xff08;放到C盤的話&#xff0c;可能在修改ini文件時涉及權限問題&#xff0c;之后我…

Elemant-UI日期范圍的表單驗證

Form 組件提供了表單驗證的功能&#xff0c;只需要通過 rules 屬性傳入約定的驗證規則&#xff0c;并將 Form-Item 的 prop 屬性設置為需校驗的字段名即可。但是官網的示例只有普通日期類型的驗證&#xff0c;沒有時間范圍的驗證。 一開始&#xff0c;我認為時間時間范圍的是一…