JavaScript設計模式 Item 3 --封裝

在JavaScript 中,并沒有對抽象類和接口的支持。JavaScript 本身也是一門弱類型語言。在封裝類型方面,JavaScript 沒有能力,也沒有必要做得更多。對于JavaScript 的設計模式實現來說,不區分類型是一種失色,也可以說是一種解脫。

從設計模式的角度出發,封裝在更重要的層面體現為封裝變化

通過封裝變化的方式,把系統中穩定不變的部分和容易變化的部分隔離開來,在系統的演變過程中,我們只需要替換那些容易變化的部分,如果這些部分是已經封裝好的,替換起來也相對容易。這可以最大程度地保證程序的穩定性和可擴展性。

javascript封裝的的基本模式有3種。

1、使用約定優先的原則,將所有的私有變量以_開頭

 <script type="text/javascript">/*** 使用約定優先的原則,把所有的私有變量都使用_開頭*/var Person = function (no, name, age){this.setNo(no);this.setName(name);this.setAge(age);}Person.prototype = {constructor: Person,checkNo: function (no){if (!no.constructor == "string" || no.length != 4)throw new Error("學號必須為4位");},setNo: function (no){this.checkNo(no);this._no = no;}, getNo: function (){return this._no;setName: function (name){this._name = name;}, getName: function (){return this._name;},  setAge: function (age){this._age = age;},  getAge: function (){return this._age;},  toString: function (){return "no = " + this._no + " , name = " + this._name + " , age = " + this._age;}};var p1 = new Person("0001", "小平果", "22");console.log(p1.toString());        //no = 0001 , name = 小平果 , age = 22p1.setNo("0003");console.log(p1.toString());      //no = 0003 , name = 小平果 , age = 22p1.no = "0004";p1._no = "0004";console.log(p1.toString());    //no = 0004 , name =小平果 , age = 22</script>

看完代碼,是不是有種被坑的感覺,僅僅把所有的變量以_開頭,其實還是可以直接訪問的,這能叫封裝么,當然了,說了是約定優先嘛.

下劃線的這種用法這一個眾所周知的命名規范,它表明一個屬性僅供對象內部使用,直接訪問它或設置它可能會導致意想不到的后果。這有助于防止程序員對它的無意使用,卻不能防止對它的有意使用。

這種方式還是不錯的,最起碼成員變量的getter,setter方法都是prototype中,并非存在對象中,總體來說還是個不錯的選擇。如果你覺得,這不行,必須嚴格實現封裝,那么看第二種方式。

2、嚴格實現封裝

<script type="text/javascript">/***  使用這種方式雖然可以嚴格實現封裝,但是帶來的問題是get和set方法都不能存儲在prototype中,都是存儲在對象中的* 這樣無形中就增加了開銷*/var Person = function (no, name, age){var _no , _name, _age ;var checkNo = function (no){if (!no.constructor == "string" || no.length != 4)throw new Error("學號必須為4位");};this.setNo = function (no){checkNo(no);_no = no;};this.getNo = function (){return _no;}this.setName = function (name){_name = name;}this.getName = function (){return _name;}this.setAge = function (age){_age = age;}this.getAge = function (){return _age;}this.setNo(no);this.setName(name);this.setAge(age);}Person.prototype = {constructor: Person,toString: function (){return "no = " + this.getNo() + " , name = " + this.getName() + " , age = " + this.getAge();}};var p1 = new Person("0001", "小平果", "22");console.log(p1.toString());        //no = 0001 , name =小平果 , age = 22p1.setNo("0003");console.log(p1.toString());      //no = 0003 , name = 小平果 , age = 22p1.no = "0004";console.log(p1.toString());    //no = 0003 , name = 小平果 , age = 22</script>

那么這與我們先前講過的其他創建對象的模式有什么不同呢,在上面的例子中,我們在創建和引用對象的屬性時總要使用this關鍵字。而在本例中,我們用var聲明這些變量。這意味著它們只存在于Person構造器中。checkno函數也是用同樣的方式聲明的,因此成了一個私用方法。

需要訪問這些變量和函數的方法只需要聲明在Person中即可。這些方法被稱為特權方法,因為它們是公用方法,但卻能夠訪問私用屬性和方法。為了在對象外部能訪問這些特權函數,它們的前面被加上了關鍵字this。因為這些方法定義于Person構造器的作用域,所以它們能訪問到私用屬性。引用這些屬性時并沒有使用this關鍵字,因為它們不是公開的。所有取值器和賦值器方法都被改為不加this地直接引用這些屬性。

任何不需要直接訪問的私用屬性的方法都可以像原來那樣在Person.prototype中聲明。像toString()方法。只有那些需要直接訪問私用成員的方法才應該被設計為特權方法。但特權方法太多又會占用過多的內存,因為每個對象實例都包含所有特權方法的新副本。

看上面的代碼,去掉了this.屬性名,嚴格的實現了封裝,只能通過getter,setter訪問成員變量了,但是存在一個問題,所有的方法都存在對象中,增加了內存的開銷。

3、以閉包的方式封裝

<script type="text/javascript">var Person = (function (){//靜態方法(共享方法)var checkNo = function (no){if (!no.constructor == "string" || no.length != 4)throw new Error("學號必須為4位");};//靜態變量(共享變量)var times = 0;//return the constructor.return function (no, name, age){console.log(times++);    // 0 ,1 , 2var no , name , age;   //私有變量this.setNo = function (no)  //私有方法{checkNo(no);this._no = no;};this.getNo = function (){return this._no;}this.setName = function (name){this._name = name;}this.getName = function (){return this._name;}this.setAge = function (age){this._age = age;}this.getAge = function (){return this._age;}this.setNo(no);this.setName(name);this.setAge(age);}})();Person.prototype = {constructor: Person,toString: function (){return "no = " + this._no + " , name = " + this._name + " , age = " + this._age;}};var p1 = new Person("0001", "小平果", "22");var p2 = new Person("0002", "abc", "23");var p3 = new Person("0003", "aobama", "24");console.log(p1.toString());        //no = 0001 , name = 小平果 , age = 22console.log(p2.toString());      //no = 0002 , name = abc , age = 23console.log(p3.toString());    //no = 0003 , name = aobama , age = 24</script>

上述代碼,js引擎加載完后,會直接執行Person = 立即執行函數,然后此函數返回了一個子函數,這個子函數才是new Person所調用的構造函數,又因為子函數中保持了對立即執行函數中checkNo(no) ,times的引用,(很明顯的閉包)所以對于checkNo和times,是所有Person對象所共有的,創建3個對象后,times分別為0,1,2 。這種方式的好處是,可以使Person中需要復用的方法和屬性做到私有且對象間共享。

這里的私用成員和特權成員仍然被聲明在構造器。但那個構造器卻從原來的普通函數變成了一個內嵌函數,并且被作為包含它的函數的返回值給變量Person。這就創建了一個閉包,你可以把靜態的私用成員聲明在里面。位于外層函數聲明之后的一對空括號很重要,其作用是代碼一載入就立即執行這個函數。這個函數的返回值是另一個函數,它被賦給Person變量,Person因此成了一個構造函數。在實例華Person時,所調用的這個內層函數。外層那個函數只是用于創建一個可以用來存儲靜態成員的閉包。

在本例中,checkno被設計成為靜態方法,原因是為Person的每個實例都生成這個方法的一個新副本毫無道理。此外還有一個靜態屬性times,其作用在于跟蹤Person構造器的總調用次數。

版權聲明:本文為小平果原創文章,轉載請注明:http://blog.csdn.net/i10630226

轉載于:https://www.cnblogs.com/dingxiaoyue/p/4948174.html

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

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

相關文章

【WCF安全】WCF 自定義授權[用戶名+密碼+x509證書]

1.x509證書制作(略) 2.直接貼代碼 ----------------------------------------------------------------------服務端------------------------------------------------------------------------------------------- WCF服務 1 using System;2 using System.Collections.Generi…

openMVS-編譯

opencv4 編譯 會有問題&#xff0c;可以重新下載 opencv3 編譯并指定好路徑。 OpenCV_DIRyour opencv3 build install path cmake -DCMAKE_BUILD_TYPERelease -DVCG_ROOT"$main_path/vcglib" ..

ASP.NET Web API 數據提供系統相關類型及其關系

轉載于:https://www.cnblogs.com/frankyou/p/4932651.html

openMVG跑自定義數據出錯

使用自己拍攝的圖片跑 openMVG 的 turtor_demo.py 時&#xff0c;出現錯誤&#xff0c;沒有生成 sfm_data.bin DSC01988" model "DSC-RX100M6" doesnt exist in the database Please consider add your camera model and sensor width in the database.原因時數…

windows server 2003下安裝iis6+php

參照http://www.myhack58.com/Article/sort099/sort0100/2012/35579.htm 這篇文章&#xff0c;即可&#xff01; 前 面我寫了《windows安裝PHP5.4Apache2.4Mysql5.5》的安裝教程&#xff0c;本地實現是很簡單的&#xff0c;但是有人還是喜歡用IIS來配置 PHP環境&#xff0c;部分…

將 JAR 轉為 EXE – JSMOOTH 的使用教程(第二期)(轉載)

http://www.iteknical.com/convert-jar-to-exe-phase-ii-jsmooth-use-tutorial/轉載于:https://www.cnblogs.com/leinuo2016/p/4932790.html

“”要求左值

錯誤 C2102 “&”要求左值 wrong code typedef struct CodeData {void *ptr_;CodeData(void*ptr) : ptr_(ptr){} } CodeData;typedef struct Data {int data_;data(int data) : data_(data){} } Data;// 這里出錯&#xff0c;因為&后面是臨時變量&#xff0c;不能取地…

winform自定義文件程序-- 不允許所請求的注冊表訪問權(ZSSQL)

常見問題1&#xff1a; 不允許所請求的注冊表訪問權 win7、win8 雙擊程序文件ZSSQL時候會出現 不允許所請求的注冊表訪問權 的彈窗異常 解決方法&#xff1a;ZSSQL.exe 右鍵 屬性--兼容性--以管理員身份運行此程序 轉載于:https://www.cnblogs.com/DemoLee/p/4173324.html

UITabBarController使用總結

剛看了幾天教程就開始跟著開發了&#xff0c;以前也沒學過C&#xff0c;太痛苦了~只能看看大神的博客&#xff0c;自己再總結學習一下了。 1.首先新建一個TabBarViewController繼承于UITabBarController。然后什么都不用寫&#xff0c;相當于裝各個tab頁的容器。 2.給每個視圖都…

Auto-Configuration Error: Cannot find gcc or CC

bazel 編譯的時候出錯 首先 echo $CC 檢查&#xff0c;若輸出無值&#xff0c;則 export CCcc

Effective Modern C++英文版及中文翻譯

https://pan.baidu.com/s/1uqEBGHn3dcVON18oRK5LNQ 提取碼&#xff1a;gqqv 中文版不用看了&#xff0c;譯者估計自己都不怎么用c11\14&#xff0c;翻譯的巨垃圾。

第一個 mac 程序 Create-JSON-Model

第一個 mac 程序 Create-JSON-Model 效果圖 數據 {"ID":null,"name":"Doe","first-name":"John","age":25,"hobbies":["reading","cinema",{"sports":["volley-bal…

php中utf8 與utf-8

php中utf8 與utf-8 原文:php中utf8 與utf-8相信很多程序員剛開始也會有這樣的疑惑&#xff0c;如題&#xff0c;我也是。 其實&#xff0c;他們可以這樣來區分。 一、在php和html中設置編碼&#xff0c;請盡量統一寫成“UTF-8”,這才是標準寫法&#xff0c;而utf-8只是在…

編譯vtk

https://vtk.org/Wiki/VTK/Configure_and_Build#On_Windows

Android--簡單開發和使用ContentProvider數據共享

今天學習的時候學到了ContentProvider數據共享這個東東&#xff0c;所以自己寫了個小例子: 我們要開發ContentProvider的話&#xff0c;需要創建一個類去繼承ContentProvider,里面會讓你重寫四個方法&#xff0c;這四個方法就是數據共享用到的方法 包括SQLite的插入、查詢、刪除…

ECharts數據圖表系統? 5分鐘上手!

目錄&#xff1a; 前言簡介方法一&#xff1a;模塊化單文件引入(推薦)方法二&#xff1a;標簽式單文件引入【前言】 最近在搗鼓各種插件各種框架&#xff0c;發現這個ECharts還是比較不錯的&#xff0c;文檔也挺全的&#xff0c;還是中文的&#xff0c;給大家推薦一下。 這篇文…

vscode 配置 pcl頭文件庫

ctrl shift p 輸入Edit configuretion 在includePath種添加 “${PCL_ROOT}/include/pcl-1.12/”

Python正則表達式中的re.S

Python正則表達式中的re.S title: Python正則表達式中的re.S date: 2014-12-21 09:55:54 categories: [Python] tags: [正則表達式,python] --- 在Python的正則表達式中&#xff0c;有一個參數為re.S。它表示“.”&#xff08;不包含外側雙引號&#xff0c;下同&#xff09;的作…

MySQL數據庫安全配置

文章來源&#xff1a;http://www.xfocus.net MySQL數據庫安全配置1、前言MySQL 是完全網絡化的跨平臺關系型數據庫系統&#xff0c;同時是具有客戶機/服務器體系結構的分布式數據庫管理系統。它具有功能強、使用簡便、管理方便、運行速度快、安全可靠性強等優點&#xff0c;用戶…

slidingmenu屬性

轉載原文 http://www.cnblogs.com/xueqiang911226/p/3564757.html 最近用到slidingmenu&#xff0c;要了解這個庫&#xff0c;首先得了解屬性和方法&#xff0c;特意記錄以備以后方便查詢。 SlidingMenu 常用屬性介紹: menu.setMode(SlidingMenu.LEFT);//設置左滑菜單 slidin…