<span id="mktg5"></span>

<i id="mktg5"><meter id="mktg5"></meter></i>

        <label id="mktg5"><meter id="mktg5"></meter></label>
        最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
        問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
        當前位置: 首頁 - 科技 - 知識百科 - 正文

        面向對象的Javascript之三(封裝和信息隱藏)_js面向對象

        來源:懂視網 責編:小采 時間:2020-11-27 21:02:16
        文檔

        面向對象的Javascript之三(封裝和信息隱藏)_js面向對象

        面向對象的Javascript之三(封裝和信息隱藏)_js面向對象:同時,我們知道在面向對象的高級語言中,創建包含私有成員的對象是最基本的特性之一,提供屬性和方法對私有成員進行訪問來隱藏內部的細節。雖然JS也是面向對象的,但沒有內部機制可以直接表明一個成員是公有還是私有的。還是那句話,依靠JS的語言靈活性,我們
        推薦度:
        導讀面向對象的Javascript之三(封裝和信息隱藏)_js面向對象:同時,我們知道在面向對象的高級語言中,創建包含私有成員的對象是最基本的特性之一,提供屬性和方法對私有成員進行訪問來隱藏內部的細節。雖然JS也是面向對象的,但沒有內部機制可以直接表明一個成員是公有還是私有的。還是那句話,依靠JS的語言靈活性,我們

        同時,我們知道在面向對象的高級語言中,創建包含私有成員的對象是最基本的特性之一,提供屬性和方法對私有成員進行訪問來隱藏內部的細節。雖然JS也是面向對象的,但沒有內部機制可以直接表明一個成員是公有還是私有的。還是那句話,依靠JS的語言靈活性,我們可以創建公共、私有和特權成員,信息隱藏是我們要實現的目標,而封裝是我們實現這個目標的方法。我們還是從一個示例來說明:創建一個類來存儲圖書數據,并實現可以在網頁中顯示這些數據。

        1. 最簡單的是完全暴露對象。使用構造函數創建一個類,其中所有的屬性和方法在外部都是可以訪問的。
        代碼如下:
        var Book = function(isbn, title, author) {
        if(isbn == undefined) {
        throw new Error("Book constructor requires a isbn.");
        }
        this.isbn = isbn;
        this.title = title || "";
        this.author = author || "";
        }
        Book.prototype.display = function() {
        return "Book: ISBN: " + this.isbn + ",Title: " + this.title + ",Author: " + this.author;
        }

        display方法依賴于isbn是否正確,如果不是你將無法獲取圖像以及鏈接。考慮到這點,每本圖書isbn必須存在的,而圖書的標題和作者是可選的。表面上看只要指定一個isbn參數似乎就能正常運行。但卻不能保證isbn的完整性,基于此我們加入isbn的驗證,使圖書的檢查更加健壯。
        代碼如下:
        var Book = function(isbn, title, author) {
        if(!this.checkIsbn(isbn)) {
        throw new Error("Book: invalid ISBN.");
        }
        this.isbn = isbn;
        this.title = title || "";
        this.author = author || "";
        }
        Book.prototype = {
        checkIsbn: function(isbn) {
        if(isbn == undefined || typeof isbn != "string") return false;
        isbn = isbn.replace("-", "");
        if(isbn.length != 10 && isbn.length != 13) return false;
        var sum = 0;
        if(isbn.length == 10) {
        if(!isbn.match(\^\d{9}\)) return false;
        for(var i = 0;i < 9;i++) {
        sum += isbn.charAt(i) * (10 - i);
        }
        var checksum = sum % 11;
        if(checksum == 10) checksum = "X";
        if(isbn.charAt(9) != checksum) return false;
        } else {
        if(!isbn.match(\^\d{12}\)) return false;
        for(var i = 0;i < 12;i++) {
        sum += isbn.charAt(i) * (i % 2 == 0 ? 1 : 3);
        }
        var checksum = sum % 10;
        if(isbn.charAt(12) != checksum) return false;
        }
        return true;
        },
        display: function() {
        return "Book: ISBN: " + this.isbn + ",Title: " + this.title + ",Author: " + this.author;
        }
        };

        我們添加了checkIsbn()來驗證ISBN的有效性,確保display()可以正常運行。但是需求有變化了,每本書可能有多個版本,意味著同一本可能有多個ISBN號存在,需要維護單獨的選擇版本的算法來控制。同時盡管能檢查數據的完整性,但卻無法控制外部對內部成員的訪問(如對isbn,title,author賦值),就談不上保護內部數據了。我們繼續改進這個方案,采用接口實現(提供get訪問器/set存儲器)。
        代碼如下:
        var Publication = new Interface("Publication", ["getIsbn", "setIsbn", "checkIsbn", "getTitle", "setTitle", "getAuthor", "setAuthor", "display"]);
        var Book = function(isbn, title, author) {
        // implements Publication interface
        this.setIsbn(isbn);
        this.setTitle(title);
        this.setAuthor(author);
        }
        Book.prototype = {
        getIsbn: function() {
        return this.isbn;
        },
        setIsbn: function(isbn) {
        if(!this.checkIsbn(isbn)) {
        throw new Error("Book: Invalid ISBN.");
        }
        this.isbn = isbn;
        },
        checkIsbn: function(isbn) {
        if(isbn == undefined || typeof isbn != "string") return false;
        isbn = isbn.replace("-", "");
        if(isbn.length != 10 && isbn.length != 13) return false;
        var sum = 0;
        if(isbn.length == 10) {
        if(!isbn.match(\^\d{9}\)) return false;
        for(var i = 0;i < 9;i++) {
        sum += isbn.charAt(i) * (10 - i);
        }
        var checksum = sum % 11;
        if(checksum == 10) checksum = "X";
        if(isbn.charAt(9) != checksum) return false;
        } else {
        if(!isbn.match(\^\d{12}\)) return false;
        for(var i = 0;i < 12;i++) {
        sum += isbn.charAt(i) * (i % 2 == 0 ? 1 : 3);
        }
        var checksum = sum % 10;
        if(isbn.charAt(12) != checksum) return false;
        }
        return true;
        },
        getTitle: function() {
        return this.title;
        },
        setTitle: function(title) {
        this.title = title || "";
        },
        getAuthor: function() {
        return this.author;
        },
        setAuthor: function(author) {
        this.author = author || "";
        },
        display: function() {
        return "Book: ISBN: " + this.isbn + ",Title: " + this.title + ",Author: " + this.author;
        }
        };

        現在就可以通過接口Publication來與外界進行通信。賦值方法也在構造器內部完成,不需要實現兩次同樣的驗證,看似非常完美的完全暴露對象方案了。雖然能通過set存儲器來設置屬性,但這些屬性仍然是公有的,可以直接賦值。但此方案到此已經無能為力了,我會在第二種信息隱藏解決方案中來優化。盡管如此,此方案對于那些沒有深刻理解作用域的新手非常容易上手。唯一的不足是不能保護內部數據且存儲器增加了多余的不必要代碼。
        2. 使用命名規則的私有方法。就是使用下劃線來標識私有成員,避免無意中對私有成員進行賦值,本質上與完全暴露對象是一樣的。但這卻避免了第一種方案無意對私有成員進行賦值操作,卻依然不能避免有意對私有成員進行設置。只是說定義了一種命名規范,需要團隊成員來遵守,不算是一種真正的內部信息隱藏的完美方案。
        代碼如下:
        var Publication = new Interface("Publication", ["getIsbn", "setIsbn", "getTitle", "setTitle", "getAuthor", "setAuthor", "display"]);
        var Book = function(isbn, title, author) {
        // implements Publication interface
        this.setIsbn(isbn);
        this.setTitle(title);
        this.setAuthor(author);
        }
        Book.prototype = {
        getIsbn: function() {
        return this._isbn;
        },
        setIsbn: function(isbn) {
        if(!this._checkIsbn(isbn)) {
        throw new Error("Book: Invalid ISBN.");
        }
        this._isbn = isbn;
        },
        _checkIsbn: function(isbn) {
        if(isbn == undefined || typeof isbn != "string") return false;
        isbn = isbn.replace("-", "");
        if(isbn.length != 10 && isbn.length != 13) return false;
        var sum = 0;
        if(isbn.length == 10) {
        if(!isbn.match(\^\d{9}\)) return false;
        for(var i = 0;i < 9;i++) {
        sum += isbn.charAt(i) * (10 - i);
        }
        var checksum = sum % 11;
        if(checksum == 10) checksum = "X";
        if(isbn.charAt(9) != checksum) return false;
        } else {
        if(!isbn.match(\^\d{12}\)) return false;
        for(var i = 0;i < 12;i++) {
        sum += isbn.charAt(i) * (i % 2 == 0 ? 1 : 3);
        }
        var checksum = sum % 10;
        if(isbn.charAt(12) != checksum) return false;
        }
        return true;
        },
        getTitle: function() {
        return this._title;
        },
        setTitle: function(title) {
        this._title = title || "";
        },
        getAuthor: function() {
        return this._author;
        },
        setAuthor: function(author) {
        this._author = author || "";
        },
        display: function() {
        return "Book: ISBN: " + this.getIsbn() + ",Title: " + this.getTitle() + ",Author: " + this.getAuthor();
        }
        };

        注意:除了isbn,title,author屬性被加上"_"標識為私有成員外,checkIsbn()也被標識為私有方法。

        3. 通過閉包來真正私有化成員。如果對閉包概念中的作用域和嵌套函數不熟悉的朋友,可以參考"面向對象的Javascript之一(初識Javascript)"文章,這里不再詳細論述。
        代碼如下:
        var Publication = new Interface("Publication", ["getIsbn", "setIsbn", "getTitle", "setTitle", "getAuthor", "setAuthor", "display"]);
        var Book = function(newIsbn, newTitle, newAuthor) {
        // private attribute
        var isbn, title, author;
        // private method
        function checkIsbn(isbn) {
        if(isbn == undefined || typeof isbn != "string") return false;
        isbn = isbn.replace("-", "");
        if(isbn.length != 10 && isbn.length != 13) return false;
        var sum = 0;
        if(isbn.length == 10) {
        if(!isbn.match(\^\d{9}\)) return false;
        for(var i = 0;i < 9;i++) {
        sum += isbn.charAt(i) * (10 - i);
        }
        var checksum = sum % 11;
        if(checksum == 10) checksum = "X";
        if(isbn.charAt(9) != checksum) return false;
        } else {
        if(!isbn.match(\^\d{12}\)) return false;
        for(var i = 0;i < 12;i++) {
        sum += isbn.charAt(i) * (i % 2 == 0 ? 1 : 3);
        }
        var checksum = sum % 10;
        if(isbn.charAt(12) != checksum) return false;
        }
        return true;
        }
        // previleged method
        this.getIsbn = function() {
        return isbn;
        };
        this.setIsbn = function(newIsbn) {
        if(!checkIsbn(newIsbn)) {
        throw new Error("Book: Invalid ISBN.");
        }
        isbn = newIsbn;
        }
        this.getTitle = function() {
        return title;
        },
        this.setTitle = function(newTitle) {
        title = newTitle || "";
        },
        this.getAuthor: function() {
        return author;
        },
        this.setAuthor: function(newAuthor) {
        author = newAuthor || "";
        }
        // implements Publication interface
        this.setIsbn(newIsbn);
        this.setTitle(newTitle);
        this.setAuthor(newAuthor);
        }
        // public methods
        Book.prototype = {
        display: function() {
        return "Book: ISBN: " + this.getIsbn() + ",Title: " + this.getTitle() + ",Author: " + this.getAuthor();
        }
        };

        這種方案與上一種有哪些不同呢?首先,在構造器中使用var來聲明三個私有成員,同樣也聲明了私有方法checkIsbn(),僅僅在構造器中有效。使用this關鍵字聲明特權方法,即聲明在構造器內部但卻可以訪問私有成員。任何不需要訪問私有成員的方法都在Book.prototype中聲明(如:display),也即是將需要訪問私有成員的方法聲明為特權方法是解決這個問題的關鍵。但此訪問也有一定缺陷,如對每一個實例而言,都要創建一份特權方法的副本,勢必需要更多內存。我們繼續優化,采用靜態成員來解決所面臨的問題。順便提一句:靜態成員僅僅屬于類,所有的對象僅共用一份副本(在"面向對象的Javascript之二(實現接口)中有說明,參見Interface.ensureImplements方法"),而實例方法是針對對象而言。
        代碼如下:
        var Publication = new Interface("Publication", ["getIsbn", "setIsbn", "getTitle", "setTitle", "getAuthor", "setAuthor", "display"]);
        var Book = (function() {
        // private static attribute
        var numsOfBooks = 0;
        // private static method
        function checkIsbn(isbn) {
        if(isbn == undefined || typeof isbn != "string") return false;
        isbn = isbn.replace("-", "");
        if(isbn.length != 10 && isbn.length != 13) return false;
        var sum = 0;
        if(isbn.length == 10) {
        if(!isbn.match(\^\d{9}\)) return false;
        for(var i = 0;i < 9;i++) {
        sum += isbn.charAt(i) * (10 - i);
        }
        var checksum = sum % 11;
        if(checksum == 10) checksum = "X";
        if(isbn.charAt(9) != checksum) return false;
        } else {
        if(!isbn.match(\^\d{12}\)) return false;
        for(var i = 0;i < 12;i++) {
        sum += isbn.charAt(i) * (i % 2 == 0 ? 1 : 3);
        }
        var checksum = sum % 10;
        if(isbn.charAt(12) != checksum) return false;
        }
        return true;
        }
        // return constructor
        return function(newIsbn, newTitle, newAuthor) {
        // private attribute
        var isbn, title, author;
        // previleged method
        this.getIsbn = function() {
        return isbn;
        };
        this.setIsbn = function(newIsbn) {
        if(!Book.checkIsbn(newIsbn)) {
        throw new Error("Book: Invalid ISBN.");
        }
        isbn = newIsbn;
        }
        this.getTitle = function() {
        return title;
        },
        this.setTitle = function(newTitle) {
        title = newTitle || "";
        },
        this.getAuthor = function() {
        return author;
        },
        this.setAuthor = function(newAuthor) {
        author = newAuthor || "";
        }
        Book.numsOfBooks++;
        if(Book.numsOfBooks > 50) {
        throw new Error("Book: at most 50 instances of Book can be created.");
        }
        // implements Publication interface
        this.setIsbn(newIsbn);
        this.setTitle(newTitle);
        this.setAuthor(newAuthor);
        };
        })();
        // public static methods
        Book.convertToTitle = function(title) {
        return title.toUpperCase();
        }
        // public methods
        Book.prototype = {
        display: function() {
        return "Book: ISBN: " + this.getIsbn() + ",Title: " + this.getTitle() + ",Author: " + this.getAuthor();
        }
        };

        這種方案與上種相似,使用var和this來創建私有成員和特權方法。不同之處在于使用閉包來返回構造器,并將checkIsbn聲明為私有靜態方法。可能有人會問,我為什么要創建私有靜態方法,答案在于使所有對象公用一份函數副本而已。我們這里創建的50個實例都只有一個方法副本checkIsbn,且屬于類Book。根據需要,你也可以創建公有的靜態方法供外部調用(如:convertToTitle)。這里我們繼續考慮一個問題,假設以后我們需要對不同的書做限制,比如<>最大印發量為500,<<.NET>>最大印發量為1000,也即說需要一個最大印發量的常量。思考一下,利用已有的知識,我們如何聲明一個常量呢?其實不難,我們想想,可以利用一個只有訪問器的私有特權方法就可以實現。
        代碼如下:
        var Publication = new Interface("Publication", ["getIsbn", "setIsbn", "getTitle", "setTitle", "getAuthor", "setAuthor", "display"]);
        var Book = (function() {
        // private static attribute
        var numsOfBooks = 0;
        // private static contant
        var Constants = {
        "MAX_JAVASCRIPT_NUMS": 500,
        "MAX_NET_NUMS": 1000
        };
        // private static previleged method
        this.getMaxNums(name) {
        return Constants[name.ToUpperCase()];
        }
        // private static method
        function checkIsbn(isbn) {
        if(isbn == undefined || typeof isbn != "string") return false;
        isbn = isbn.replace("-", "");
        if(isbn.length != 10 && isbn.length != 13) return false;
        var sum = 0;
        if(isbn.length == 10) {
        if(!isbn.match(\^\d{9}\)) return false;
        for(var i = 0;i < 9;i++) {
        sum += isbn.charAt(i) * (10 - i);
        }
        var checksum = sum % 11;
        if(checksum == 10) checksum = "X";
        if(isbn.charAt(9) != checksum) return false;
        } else {
        if(!isbn.match(\^\d{12}\)) return false;
        for(var i = 0;i < 12;i++) {
        sum += isbn.charAt(i) * (i % 2 == 0 ? 1 : 3);
        }
        var checksum = sum % 10;
        if(isbn.charAt(12) != checksum) return false;
        }
        return true;
        }
        // return constructor
        return function(newIsbn, newTitle, newAuthor) {
        // private attribute
        var isbn, title, author;
        // previleged method
        this.getIsbn = function() {
        return isbn;
        };
        this.setIsbn = function(newIsbn) {
        if(!Book.checkIsbn(newIsbn)) {
        throw new Error("Book: Invalid ISBN.");
        }
        isbn = newIsbn;
        }
        this.getTitle = function() {
        return title;
        },
        this.setTitle = function(newTitle) {
        title = newTitle || "";
        },
        this.getAuthor = function() {
        return author;
        },
        this.setAuthor = function(newAuthor) {
        author = newAuthor || "";
        }
        Book.numsOfBooks++;
        if(Book.numsOfBooks > 50) {
        throw new Error("Book: at most 50 instances of Book can be created.");
        }
        // implements Publication interface
        this.setIsbn(newIsbn);
        this.setTitle(newTitle);
        this.setAuthor(newAuthor);
        };
        })();
        // public static methods
        Book.convertToTitle = function(title) {
        return title.toUpperCase();
        }
        // public methods
        Book.prototype = {
        display: function() {
        return "Book: ISBN: " + this.getIsbn() + ",Title: " + this.getTitle() +
        ",Author: " + this.getAuthor() + ", Maximum: ";
        },
        showMaxNums: function() {
        return Book.getMaxNums("MAX_JAVASCRIPT_NUMS");
        }
        };

        最完美的情況就是你所封裝的程序對調用者而言,僅僅需要知道你的接口就可以,根本不關心你如何實現。但問題在于,隨著工程量的擴大,你的封裝內容必然會增大,在項目發生交接時,對于一個對作用域和閉包等概念不熟悉的成員來說,維護難度會變得如此之大。有些時候應需求響應必須改動源碼(這里不一定指改接口),可能是新增一些細節,即使拿到你的源碼卻無從下手,那就不好做了。因此,我的建議:封裝不要過度,接口一定要清晰,可擴展。

        聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

        文檔

        面向對象的Javascript之三(封裝和信息隱藏)_js面向對象

        面向對象的Javascript之三(封裝和信息隱藏)_js面向對象:同時,我們知道在面向對象的高級語言中,創建包含私有成員的對象是最基本的特性之一,提供屬性和方法對私有成員進行訪問來隱藏內部的細節。雖然JS也是面向對象的,但沒有內部機制可以直接表明一個成員是公有還是私有的。還是那句話,依靠JS的語言靈活性,我們
        推薦度:
        標簽: 隱藏 js 對象
        • 熱門焦點

        最新推薦

        猜你喜歡

        熱門推薦

        專題
        Top
        主站蜘蛛池模板: 亚洲久本草在线中文字幕| 国产成人综合亚洲AV第一页 | 黄网站色视频免费在线观看的a站最新 | 亚洲成AV人片在WWW色猫咪| 中文在线观看永久免费 | 在线观看亚洲人成网站| 免费A级毛片av无码| 亚洲色图古典武侠| 色婷婷7777免费视频在线观看| 亚洲精品国产第1页| 亚洲天堂免费在线| 亚洲日本一线产区和二线产区对比| 成熟女人牲交片免费观看视频| 亚洲av乱码中文一区二区三区| 又粗又硬又大又爽免费视频播放| 一区二区免费电影| 亚洲Av无码专区国产乱码DVD | 最近免费视频中文字幕大全| 亚洲在成人网在线看| 啦啦啦手机完整免费高清观看| 美女视频黄频a免费观看| 亚洲综合另类小说色区色噜噜| 精品亚洲永久免费精品 | 中文字幕亚洲色图| 成人免费a级毛片无码网站入口| 亚洲a∨无码一区二区| 国产成人精品久久亚洲| 嫩草影院在线播放www免费观看| 亚洲一区中文字幕在线电影网| 日本一区二区三区日本免费| 91精品成人免费国产| 亚洲国产精品久久人人爱| 天天天欲色欲色WWW免费| 国产免费高清69式视频在线观看| 久久亚洲精品成人av无码网站| 在线观看免费a∨网站| 国产精品成人69XXX免费视频| 亚洲国产成人精品无码一区二区| 免费亚洲视频在线观看| 日韩免费无码视频一区二区三区| 亚洲AV第一成肉网|