中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

javascript面向對象三大特征之封裝的示例分析

發布時間:2021-07-16 13:57:15 來源:億速云 閱讀:139 作者:小新 欄目:web開發

這篇文章主要介紹了javascript面向對象三大特征之封裝的示例分析,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。

具體如下:

封裝

封裝(Encapsulation):就是把對象內部數據和操作細節進行隱藏。很多面向對象語言都支持封裝特性,提供關鍵字如private來隱藏某些屬性和方法。要想訪問被封裝對象中的數據,只能使用對象專門提供的對外接口,這個接口一般為方法。調用該方法能夠獲取對象內部數據。

在JavaScript語言中沒有提供專門的信息封裝關鍵字,不過可以使用閉包來創建,只允許從對象內部訪問的方法和屬性。另外,接口也是數據封裝的一種工具,接口提供了外界訪問方法的約定。在應用開發中,所有類都應定義接口,類只向外提供已實現接口中規定的方法,任何別的方法都是隱藏的。其所有屬性都是私有的,外界只能通過接口中定義的存取操作與之打交道。

---引自 《jQuery開發從入門到精通》,不過原書有錯誤,或者可能是我錯買了盜版,不過下面代碼都是經過我修改的,沒有問題。

被動封裝

被動封裝:就是對對象內部數據進行適當約定,這種約定具有很強的主觀性,沒有強制性保證,主要針對公共對象而言。一般來說,JavaScript所包含的數據都是公開的,沒有隱私可言,其中的信息可以隨意被訪問。下面給出一個例子來闡述:

var Person = function (name,gender) {
 if(name === undefined) {
 throw new Error("name is necessary")
 } else {
 this.name = name;
 }
 if(gender === undefined) {
 throw new Error("gender is necessary")
 } else {
 this.gender = gender;
 }
}
var p = new Person("Tom",1); // 如果我們實例化的時候,如果傳遞參數錯誤了,將會報異常

為了數據安全,代碼中適當的增加了一些條件限制,避免非法信息侵入。

var Animal = function (species) {
 if(!this.checkSpecies(species)) {
 throw new Error('species is illegal');
 } else {
 this.species = species;
 }
}
Animal.prototype = {
 checkSpecies:function(species){
 // 檢測 species , 參數為 species , 合法返回true ,這里可自定義檢測邏輯
 // 這里先讓它直接返回 true
 return true;
 }
}
var ani = new Animal("dog");

從更安全和擴展的角度來說,凡是類都應該定義接口,這樣能夠保證數據存取更加安全,同時也方便團隊的合作。內部私有方法檢測和接口措施可在一定程度上保護對象內部數據,但是他們也存在一個致命漏洞(這些屬性和方法可以被公開重置,面對公開覆蓋屬性和方法值,任何人都無法阻止這種行為。),比如這樣的:

var Util = function() {};
Util.prototype = {
 _say:function(){
 console.log("這里有一個私有的成員 _say方法");
 }
}
// 下面我們來修改它
Util.prototype._say = function(){
 console.log('哈哈,我已經被修改了');
}
// 開始檢測
var util = new Util;
util._say(); // 哈哈,我已經被修改了

同時內部檢測和接口可以在一定程度上占用了系統開銷,這個問題也是必須認真考慮的。

就像上面的代碼那樣,一般我們約定了區別公共和私有成員,就是在一些方法和屬性名稱前或者后加下劃線,來表示私有。

下劃線命名是一種約定俗稱的命名規范,表示一個屬性和方法僅供內部使用,直接訪問可能會導致意外發生。

以上數據保護方式都是被動性防御,因為他們只是一種約定,只有在遵守的時候才有效果。主要適用于非敏感性的內部方法和屬性。

主動封裝

在js中,因為函數有作用域,在函數內部聲明的變量,在函數外部無法訪問。而所以的私有和公有的區別就在于在對象外部是否可以訪問。所以實現封裝的最佳選擇是使用函數的作用域。舉例:

function haha() {
 var n = 1;
 function hehe() {
 n++;
 }
 hehe();
 return n;
}
console.log(haha()); // 2

函數haha內部有私有變量n,在此作用域中,hehe能夠訪問n,而haha外部的任何函數都無法訪問haha里的n。

同樣的,我們在函數內部返回hehe,就可以在外部來調用haha私有函數hehe。

function haha() {
 var n = 1;
 function hehe() {
 return ++n;
 }
 return hehe;
}
console.log(haha()()); // 2

函數作用域內部的方法無法被外界訪問,但是在函數作用域內部的其他公共方法可以訪問到它們,于是利用公共方法為中轉站,可以巧妙的把內部私有方法公開化。因此這些公共方法也被稱為特權方法,即在方法前面加this關鍵字。

使用這種方式創建的對象具有真正的封裝性如:

function A() {
 // 私有方法 _xx
 function _xx(){}
 // 公有方法
 this.xx = function() {
 return _xx;
 }
}
A.prototype = {
 other:function() {
 console.log("other方法代表不需要訪問私有屬性和方法的方法,一般放在原型里");
 }
}

但是這種方式也有一些缺點:

① 新生成的每個實例對象都會拷貝構造函數中的屬性和方法,而私有的_xx 無疑在每次實例化的時候都會重復拷貝,這樣會占用大量內存,所以不適合大量使用,僅在必要時適當使用

② 不利于類的繼承,所有派生的子類都不能訪問超類中的私有屬性和方法。不過可以使用特權方法來訪問超類中的私有屬性和方法。舉個例子:

// B 是超類
function B() {
 var _private = 1;
 function _checkPrivate() {
 return _private;
 }
 this.checkPrivate = function() {
 return _checkPrivate;
 }
}
// C 是派生類
function C() {
 B.call(this); // 用call 實現繼承 ,后面我們會講到如何繼承
 // this.private = _private; // 這里嘗試訪問超類的私有屬性,因為無法訪問,會報錯
}
// 實例化 派生類C
var c = new C();
// console.log(c.private); // 和在C內部的嘗試一樣,是無法訪問的,報錯
// 不過可以用下面的方法訪問超類中的私有屬性
console.log(c.checkPrivate()()); // 1

靜態方法

在面向對象編程中,大多數的方法和屬性與類的實例產生聯系。還有一種情況是,靜態屬性和方法是與類本身直接聯系,可直接從類訪問,也就是說,靜態成員在類上操作,而不是實例上。在JavaScript中的Math和Global都是靜態對象,不需要實例化就可直接訪問。

類的靜態成員,包括私有和公共兩種。他們在系統中只有一份副本,意思就是說他們不會被分成多份傳遞給不同的實例對象。而是通過函數指針進行引用。書上有個例子非常好,下面舉例:

var F = (function(){ // 把閉包函數賦給F,返回一個構造函數
 var _a = 1; // 定義一個閉包體內的私有變量
 this.a = _a; // 閉包體內的公共屬性 a
 this.get1 = function(){ // 閉包體內的公共方法get1
 return _a;
 }
 this.set1 = function(x){ // 閉包體內的公共方法set1
 _a = x;
 };
 return function(){ // 返回一個構造函數,構造函數也是函數,更是對象(相當于一個類)
 this.get2 = function() { // 類的get2方法
  return _a;
 };
 this.set2 = function(x) { // 類的set2方法
  _a = x;
 };
 }
})();
// 定義類的靜態公共方法和屬性
F.get3 = function(){ // 定義一個靜態方法get3
 return get1(); // 這里可以直接使用 F內的公共方法get1
}
F.set3 = function(x) { // 定義一個靜態方法set3
 return set1(x); // 同get1
}
// 下面開始測試
var f = new F(); // 實例化這個類
console.log(f.get2()); // 1 用實例對象訪問公共方法get2
F.set3(3); // 調用靜態方法set3
console.log(F.get3()); // 3
F.A = ++a; // 定義一個靜態屬性A
console.log(F.A); // 2

感謝你能夠認真閱讀完這篇文章,希望小編分享的“javascript面向對象三大特征之封裝的示例分析”這篇文章對大家有幫助,同時也希望大家多多支持億速云,關注億速云行業資訊頻道,更多相關知識等著你來學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

古交市| 长治县| 宁陕县| 商都县| 大化| 麻城市| 浮梁县| 和龙市| 津南区| 齐河县| 沧源| 湘潭市| 黄平县| 台安县| 吉安市| 石首市| 万源市| 兴义市| 越西县| 白朗县| 昭苏县| 介休市| 荃湾区| 南涧| 仁怀市| 兰州市| 宾川县| 邵东县| 会昌县| 万荣县| 宜良县| 丰顺县| 高阳县| 修武县| 西平县| 扎兰屯市| 英超| 湘潭市| 西乌| 长宁区| 剑川县|