国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

簡單理解JavaScript中的封裝與繼承特性

2019-11-20 10:22:09
字體:
來源:轉載
供稿:網友

JavaScript中的封裝
封裝簡單地說就是讓外界只能訪問對象的共有變量和函數,隱藏細節和數據。
js中有三種方法創建對象,分別為門戶大開型、用命名規范區分私有變量、閉包創建真正的私有變量三種。
1.門戶大開型,是實現對象的最基礎的方法,所有方法與變量都是共有的外界可以訪問。

var Book = function(name){   if(this.check(name)){     console.log("error");     throw new Error("name null");   }   this.name = name; } Book.prototype = {   check:function(name){     if(!name){       return true;     }   },   getName:function(){     return this.name;   } }  var book = new Book("哈哈"); //output:哈哈 哈哈 console.log(book.name,book.getName()); 

這個例子是門戶大開型的典型,外界能直接訪問對象的屬性和方法。可以注意到屬性和變量都有"this"來創建。
 
2.用命名規范區分私有變量,該方法是門戶大開型的優化版本,只不過是在私有變量或方法前面用"_"區分,如果有程序員有意使用_getName()的方法來調用方法,還是無法阻止的,不是真正地將變量隱藏。
 
3.閉包創建真正的私有變量,該方法利用js中只有函數具有作用域的特性,在構造函數的作用域中定義相關變量,這些變量可以被定義域該作用域中的所有函數訪問。

var Book2 = function(name){   if(check(name)){     console.log("error");     throw new Error("name null");   }   name = name;   function check(name){     if(!name){       return true;     }   }   this.getName = function(){     return name;   } } Book2.prototype = {   display:function(){     //無法直接訪問name     return "display:"+this.getName();   } } var book2 = new Book2("哈哈"); //output:undefined "哈哈" "display:哈哈" console.log(book2.name,book2.getName(),book2.display()); 

 可以看到,這個例子中的結果,直接訪問name會返回undefined的結果。可以看到這個例子與門戶大開型的區別,門戶大開型中的變量使用"this"來創建,而這個例子中使用var來創建,check函數也是如此,使得name與check函數只能在構造函數的作用域中訪問,外界無法直接訪問。
該方法解決了前兩種方法的問題,但是也有一定的弊端。在門戶大開型對象創建模式中,所有方法都創建在原型對象中,因此不管生成多少對象實例,這些方法在內存中只存在一份,而采用該方法,每生成一個新的對象都會為每個私有變量和方法創建一個新的副本,故會耗費更多的內存。

JavaScript中的繼承
Book基類:

var Book = function(name){   if(this.check(name)){     console.log("error");     throw new Error("name null");   }   this.name = name; } Book.prototype = {   check:function(name){     if(!name){       return true;     }   },   getName:function(){     return this.name;   } } 

繼承方法:

function extend(subClz,superClz){ var F = function(){} F.prototype = superClz.prototype; subClz.prototype = new F(); subClz.prototype.constructor = subClz; subClz.superClass = superClz.prototype; if(superClz.prototype.constructor == Object.prototype.constructor){   superClz.prototype.constructor = superClz; } 

 
使用空函數F作為橋接,可以避免直接實例化父類時調用父類的構造函數帶來額外開銷,而且當父類的構造函數有參數時,想直接通過subClass.prototype = new superClass();實現父類構造函數的調用和原型鏈的繼承是不行的。

subClz.superClass = superClz.prototype; if(superClz.prototype.constructor == Object.prototype.constructor){   superClz.prototype.constructor = superClz; } 

 
添加這三句可以避免子類繼承父類寫Book.call(this,name);而是簡單地寫ArtBook.superClass.Constructor.call(this,name)便能實現。
并且在子類重寫父類方法的時候,可以調用到父類的方法:

ArtBook.prototype.getName = functiion(){   return ArtBook.superClass.getName.call(this) + "!!!"; } 

ArtBook子類:

var ArtBook = function(name,price){   ArtBook.superClass.Constructor.call(this,name);   this.price = price; } extend(ArtBook,Book); ArtBook.prototype.getPrice = function(){     return this.price; } ArtBook.prototype.getName = function(){    return ArtBook.superClass.getName.call(this)+"!!!";  } 

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 博罗县| 温州市| 郴州市| 台北县| 康定县| 怀来县| 玉环县| 鹤峰县| 平南县| 林州市| 兴城市| 措美县| 封开县| 基隆市| 成都市| 蒙自县| 启东市| 津市市| 聂拉木县| 九江县| 尼木县| 民和| 岱山县| 五台县| 隆尧县| 甘肃省| 昌都县| 抚松县| 天气| 南溪县| 双牌县| 寻乌县| 宜宾县| 昌都县| 牙克石市| 四会市| 五河县| 睢宁县| 朝阳市| 文成县| 尼木县|