亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

基于JavaScript如何實現私有成員的語法特征及私有成員的實現方式

2019-11-20 11:23:34
字體:
來源:轉載
供稿:網友

前言

在面向對象的編程范式中,封裝都是必不可少的一個概念,而在諸如 Java,C++等傳統的面向對象的語言中, 私有成員是實現封裝的一個重要途徑。但在 JavaScript 中,確沒有在語法特性上對私有成員提供支持, 這也使得開發人員使出了各種奇技淫巧去實現 JS 中的私有成員,以下將介紹下目前實現 JS 私有成員特性的幾個方案以及它們之間的優缺點對比。

現有的一些實現方案

約定命名方案

約定以下劃線'_'開頭的成員名作為私有成員,僅允許類成員方法訪問調用,外部不得訪問私有成員。簡單的代碼如下:

JavaScript

var MyClass = function () {  this._privateProp = ‘privateProp';};MyClass.prototype.getPrivateProp = function () {  return this._privateProp;};var my = new MyClass();alert(my.getPrivateProp()); // ‘privateProp';alert(my._privateProp); // 并未真正隱藏,依然彈出 ‘privateProp'

優點

毫無疑問,約定命名是最簡單的私有成員實現方案,沒有代碼層面上的工作。
調試方便,能夠在控制臺上直接看到對象上的私有成員,方便排查問題。
兼容性好,ie6+都支持

不足

無法阻止外部對私有成員的訪問和變更,如果真有不知道或者不遵守約定的開發人員變更私有屬性,也是無能為力。
必須強制或說服大家遵守這個約定,當然這個在有代碼規范的團隊中不是什么太大的問題。

es6 symbol 方案

在 es6中,引入了一個 Symbol 的特性,該特性正是為了實現私有成員而引入的。
主要的思路是,為每一個私有成員的名稱產生一個隨機且唯一的字符串key,這個 key 對外不可見,對內的可見性則是通過 js 的閉包變量實現,示例代碼如下:

JavaScript

(function() {   var privateProp = Symbol(); // 每次調用會產生一個唯一的key   function MyClass() {     this[privateProp] = ‘privateProp'; // 閉包內引用到這個 key   }   MyClass.prototype.getPrivateProp = function () {     return this[privateProp];   };})();var my = new MyClass();alert(my.getPrivateProp()); // ‘privateProp';alert(my.privateProp); // 彈出 undefined,因為成員的key其實是隨機字符串

優點

彌補了命名約定方案的缺陷,外部無法通過正常途徑獲得私有成員的訪問權。
調試便捷程度上可以接受,一般是通過給 symbol 的構造函數傳入一個字符串參數,則控制臺上對應的私有屬性名稱會展示為:Symbol(key)

兼容性不錯,不支持 Symbol的瀏覽器可以很容易的 shim 出來。

不足

寫法上稍顯別扭,必須為每一個私有成員都創建一個閉包變量讓內部方法可以訪問。
外部還是可以通過 Object.getOwnPropertySymbols的方式獲取實例的 symbol 屬性名稱,通過該名稱獲得私有成員的訪問權。這種場景出現得比較少,且知道這種途徑的開發人員水平相信都是有足夠的能力知道自己的行為會有什么影響,因此這個不足點也算不上真正意義的不足。

es6 WeakMap 方案

在 es6 中引入了 Map, WeakMap 容器,最大的特點是容器的鍵名可以是任意的數據類型,雖說初衷不是為了實現私有成員引入,但意外的可以被用來實現私有成員特性。

主要的思路是,在類的級別上創建一個 WeakMap 容器,用于存儲各個實例的私有成員,這個容器對外不可見,對內通過閉包方式可見;內部方法通過將實例作為鍵名獲取容器上對應實例的私有成員,示例代碼如下:

JavaScript

(function() {   var privateStore = new WeakMap(); // 私有成員存儲容器   function MyClass() {     privateStore.set(this, {privateProp: ‘privateProp'}); // 閉包內引用到privateStore, 用當前實例做 key,設置私有成員   }   MyClass.prototype.getPrivateProp = function () {     return privateStore.get(this).privateProp;    };})();var my = new MyClass();alert(my.getPrivateProp()); // ‘privateProp';alert(my.privateProp); // 彈出 undefined,實例上并沒有 privateProp 屬性

優點

彌補了命名約定方案的缺陷,外部無法通過正常途徑獲得私有成員的訪問權。
對 WeakMap 做一些封裝,抽出一個私有特性的實現模塊,可以在寫法上相對 Symbol 方案更加簡潔干凈,其中一種封裝的實現可以查看參考文章3。
最后一個是個人認為最大的優勢:基于 WeakMap 方案,可以方便的實現保護成員特性(這個話題會在其他文章說到:))

不足

不好調試,因為是私有成員都在閉包容器內,無法在控制臺打印實例查看對應的私有成員
待確認的性能問題,根據 es6的相關郵件列表,weakmap 內部似乎是通過順序一一對比的方式去定位 key 的,時間復雜度為 O(n),和 hash 算法的 O(1)相比會慢不少

最大的缺陷則是兼容性帶來的內存膨脹問題,在不支持 WeakMap 的瀏覽器中是無法實現 WeakMap 的弱引用特性,因此實例無法被垃圾回收。 比如示例代碼中 privateProp 是一個很大的數據項,無弱引用的情況下,實例無法回收,從而造成內存泄露。

現有實現方案小結

從上面的對比來看,Symbol方案最大優勢在于很容易模擬實現;而WeakMap的優勢則是能夠實現保護成員, 現階段無法忍受的不足是無法模擬實現弱引用特性而導致的內存問題。于是我的思路又轉向了將兩者優勢結合起來的方向。

Symbol + 類WeakMap 的整合方案

在 WeakMap 的方案中最大的問題是無法 shim 弱引用,較次要的問題是不大方便調試。

shim 出來的 WeakMap 主要是無法追溯實例的生命周期,而實例上的私有成員的生命周期又是依賴實例, 因此將實例級別的私有成員部分放在實例上不就好了? 實例沒了,自然其屬性也隨之摧毀。而私有存儲區域的隱藏則可以使用 Symol 來做。

該方案的提供一個 createPrivate 函數,該函數會返回一個私有的 token 函數,對外不可見,對內通過閉包函數獲得, 傳入當前實例會返回當前實例的私有存儲區域。使用方式如下:

JavaScript

(function() {   var $private = createPrivate(); // 私有成員 token 函數,可以傳入對象參數,會作為原型鏈上的私有成員   function MyClass() {     $private(this).privateProp = ‘privateProp' ; // 閉包內引用到privateStore, 用當前實例做 key,設置私有成員   }   MyClass.prototype.getPrivateProp = function () {     return $private(this).privateProp;    };})();var my = new MyClass();alert(my.getPrivateProp()); // ‘privateProp';alert(my.privateProp); // 彈出 undefined,實例上并沒有 privateProp 屬性

代碼中主要就是實現 createPrivate 函數,大概的實現如下:

JavaScript

// createPrivate.jsfunction createPrivate(prototype) {  var privateStore = Symbol('privateStore');  var classToken = Symbol(‘classToken');  return function getPrivate(instance) {     if (!instance.hasOwnProperty(privateStore)) {       instance[privateStore] = {};     }    var store = instance[classToken];     store[token] = store[token] || Object.create(prototype || {});     return store[token];   };}

上述實現做了兩層存儲,privateStore 這層是實例上統一的私有成員存儲區域,而 classToken 對應的則是繼承層次之間不同類的私有成員定義,基類有基類的私有成員區域,子類和基類的私有成員區域是不同的。

當然,只做一層的存儲也可以實現,兩層存儲僅僅是為了調試方便,可以直接在控制臺通過Symbol(‘privateStore')這個屬性來查看實例各個層次的私有部分。

奇葩的 es5 property getter 攔截方案

該方案純粹是閑得無聊玩了玩,主要是利用了 es5 提供的 getter,根據 argument.callee.caller 去判斷調用場景,如果是外部的則拋異?;蚍祷?undefined, 如果是內部調用則返回真正的私有成員,實現起來比較復雜,且不支持 strict 模式,不推薦使用。 有興趣的同學可以看看實現。

總結

以上幾個方案對比下來,我個人是傾向 Symbol+WeakMap 的整合方案,結合了兩者的優點,又彌補了 WeakMap 的不足和 Symbol 書寫的冗余。 當然了,我相信隨著 JS 的發展,私有成員和保護成員也遲早會在語法層面上進行支持,正如 es6 對 class 關鍵字和 super 語法糖的支持一樣, 只是現階段需要開發者使用一些技巧去填補語言特性上的空白。

Javascript私有成員的實現方式

總體來講這本書還是可以的,但看完這本書還留了幾個問題一直困擾著我,如js中私有變量的實現,prototype等,經過自己一系列測試,現在終于弄明白了。

很多書上都是說,Javascript是不能真正實現Javascript私有成員的,因此在開發的時候,統一約定 __ 兩個下劃線開頭為私有變量。

后來,發現Javascript中閉包的特性,從而徹底解決了Javascript私有成員的問題。

 function testFn(){     var _Name;//定義Javascript私有成員     this.setName = function(name){      _Name = name; //從當前執行環境中獲取_Name     }     this.getName = function(){      return _Name;     } }// End testFn var test = testFn(); alert(typeof test._Name === "undefined")//true test.setName("KenChen"); 

test._Name 根本訪問不到,但是用對象方法能訪問到,因為閉包能從當前的執行環境中獲取信息。

接下來我們看看,共有成員是怎樣實現的

function testFn(name){   this.Name = name;   this.getName = function(){    return this.Name;   } } var test = new testFn("KenChen"); test.getName(); //KenChen test.Name = "CC"; est.getName();//CC 

接下來在看看類靜態變量是怎樣實現的

function testFn(){ } testFn.Name = "KenChen"; alert(testFn.Name);//KenChen testFn.Name = "CC"; alert(testFn.Name);//CC 

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美孕妇与黑人孕交| 伊人久久久久久久久久久久久| 91av免费观看91av精品在线| 欧美激情在线有限公司| 57pao国产成人免费| 国产精品久久久久久久久久久新郎| 亚洲成人精品av| 亚洲美女av在线播放| 欧美激情一二区| 精品一区二区三区四区| 日韩av片永久免费网站| 91久久国产综合久久91精品网站| 亚洲国产精久久久久久久| 2020欧美日韩在线视频| 精品视频久久久久久久| 久操成人在线视频| 51视频国产精品一区二区| 久久久久久噜噜噜久久久精品| 国产成人av网| 亚洲精品白浆高清久久久久久| 久久中文字幕在线视频| 久久理论片午夜琪琪电影网| 欧美亚洲成人网| 亚洲欧美综合精品久久成人| 色综合久久天天综线观看| 超碰精品一区二区三区乱码| 国产成人在线亚洲欧美| 久久视频在线观看免费| 亚洲国产精品久久久| 日韩欧美精品网站| 日韩欧美国产骚| 亚洲精品美女在线观看| 91高清视频在线免费观看| 91国语精品自产拍在线观看性色| 国产日韩在线视频| 欧美疯狂xxxx大交乱88av| 国产精品中文字幕久久久| 91精品国产91久久久久福利| 丁香五六月婷婷久久激情| 亚洲九九九在线观看| 日韩国产在线播放| 欧美激情亚洲国产| 日韩国产激情在线| 久久亚洲一区二区三区四区五区高| 中文字幕精品—区二区| 国产999精品视频| 亚洲综合中文字幕在线观看| 亚洲乱码国产乱码精品精天堂| 久久久久久久亚洲精品| 91免费精品国偷自产在线| 欧美日韩在线第一页| 日韩中文字幕亚洲| 亚洲欧美日韩中文在线制服| 91中文字幕一区| 7777kkkk成人观看| 国产日韩欧美视频| 日本久久久久久久久久久| 国产精品自拍偷拍| 久久精品国产亚洲7777| 欧美亚洲成人网| 久久久这里只有精品视频| 亚洲成人黄色在线观看| 欧美裸体xxxx| 日本精品视频在线| 欧美激情va永久在线播放| 日韩色av导航| 日本久久久久久久久久久| 国产成人精品久久久| 91高清在线免费观看| 亚洲美女精品久久| 亚洲成色999久久网站| 国产亚洲精品一区二555| 主播福利视频一区| 欧美一区二区三区精品电影| 亚洲国产精品yw在线观看| 亚洲欧美一区二区精品久久久| 久久国产视频网站| 97在线视频国产| 日韩美女av在线免费观看| 日韩欧美国产成人| 成人有码在线播放| 久色乳综合思思在线视频| 亚洲国产精品成人va在线观看| 26uuu另类亚洲欧美日本一| 亚洲国产精品久久久久秋霞不卡| 日韩av片电影专区| 亚洲人精品午夜在线观看| 1769国内精品视频在线播放| 精品国产区一区二区三区在线观看| 97超碰色婷婷| www.欧美三级电影.com| 亚洲少妇中文在线| 伊人青青综合网站| 麻豆精品精华液| 精品久久久久久中文字幕| 日韩日本欧美亚洲| 欧美成人免费全部观看天天性色| 91国产在线精品| 精品成人在线视频| 538国产精品一区二区免费视频| 亚洲国产美女精品久久久久∴| 正在播放欧美视频| 成人黄色av网| 欧美中文字幕视频在线观看| 日本久久91av| 欧美大尺度在线观看| 国产一区欧美二区三区| 中文字幕欧美视频在线| 国产精品视频网址| 大胆人体色综合| 日韩成人免费视频| 国产999视频| 国产+成+人+亚洲欧洲| 最近2019好看的中文字幕免费| 日韩av理论片| 中文字幕一区二区精品| 亚洲国产精品热久久| 午夜精品在线视频| 4p变态网欧美系列| 久久精品国产久精国产一老狼| 亚洲欧美第一页| 日韩欧美一区二区三区久久| 亚洲性生活视频在线观看| 97av在线视频| 日韩免费不卡av| 成人免费视频网址| 欧美综合在线第二页| 日韩电影大片中文字幕| 亚洲黄色有码视频| 精品国产31久久久久久| 91免费精品国偷自产在线| 国产精品爽爽爽爽爽爽在线观看| 国产精品久久久久久久app| 久久国产精品久久国产精品| 亚洲精品一区二三区不卡| 欧美午夜xxx| 亚洲国产精品女人久久久| 日韩精品在线观看网站| 国产手机视频精品| 久久香蕉国产线看观看av| 51视频国产精品一区二区| 欧美成人精品在线播放| 91亚洲精华国产精华| 国产精品免费久久久| 久久国产精品偷| 北条麻妃一区二区在线观看| 日韩在线视频导航| 国产亚洲精品一区二555| 亚洲人成网站999久久久综合| 久久噜噜噜精品国产亚洲综合| 久久精品欧美视频| 中文字幕av一区| 精品视频久久久久久久| 久久精品国亚洲| 色多多国产成人永久免费网站| 91精品国产精品| 欧美日韩激情视频8区| 国产精品视频专区| 韩曰欧美视频免费观看| 色综合久久88| 超薄丝袜一区二区| 欧美丰满老妇厨房牲生活| 最近2019中文字幕mv免费看| 欧亚精品在线观看|