javaScript閉包實現(xiàn)類與繼承(非ES6)

首先我們都知道js的一個函數(shù)定義是這樣的

function func(){ //聲明一個普通的函數(shù)
  //省略代碼
}

而沒有名字的函數(shù)叫匿名函數(shù),是長這樣的

function(){ //聲明一個匿名函數(shù)怎棱,一般這樣聲明方式是用于回調(diào)函數(shù)
  //省略代碼
}

或者我們習(xí)慣用一個變量來保存匿名函數(shù)旁赊,那么這個變量成為函數(shù)本身

var func = function(){ //匿名函數(shù)保存到func變量內(nèi)
  //省略代碼
}

同樣,在調(diào)用函數(shù)的時候绞蹦,使用函數(shù)名或者變量名后面加上一個括號力奋,像以下這樣

func(); //調(diào)用函數(shù)

再者,也可以在聲明函數(shù)的時候直接調(diào)用幽七,這種叫做即時執(zhí)行函數(shù)景殷,需要加上兩個括號,像這樣

(function(){ //即時執(zhí)行函數(shù)
  //省略代碼
})();

當(dāng)然,函數(shù)是可以有返回值的猿挚,如果是即時執(zhí)行函數(shù)有返回值咐旧,那么效果會怎樣?

var func = (function(){ //即時執(zhí)行函數(shù)
   var i = 1;
   return i;
})();

這樣寫亭饵,func獲取的就不只匿名函數(shù)休偶,而是函數(shù)的返回結(jié)果,func = 1

----------------------------------------我是分割線-----------------------------------------

剛剛辜羊,我們的函數(shù)返回的是一個整數(shù)踏兜,但如果我們的函數(shù)返回的是另一個函數(shù)呢?就成了閉包八秃,像這樣:

var func = (function(){ //即時執(zhí)行函數(shù)
   var resultFunc = function(){ //要返回的函數(shù)
       //省略代碼
   }
   return resultFunc;
})();

以上這樣寫 func就是resultFunc函數(shù)碱妆,這樣有什么用呢?看下面的代碼昔驱,注意變量 i 的作用域

var func = (function(){
   var i = 5;   //聲明了局部變量
   var resultFunc = function(){ 
        console.log(i);      //返回的函數(shù)體內(nèi)能訪問變量 i
       //省略代碼
   }
   //作用域內(nèi)能訪問變量 i
   return resultFunc;
})();
//函數(shù)體外能不能訪問變量 i

這樣聲明的 i 變量外部是不能訪問的疹尾,是不是很像面向?qū)ο蟮乃接谐蓡T變量?接下來我們試試內(nèi)部方法

var func = (function(){
   var i = 5;  
   var privateFunc = function(){  //聲明了局部變量
        //省略代碼
    }
   var resultFunc = function(){ 
        privateFunc();  //調(diào)用局部函數(shù)
       //省略代碼
   }
   return resultFunc;
})();

小結(jié)一下:實際情況下骤肛,我們可以嘗試這樣寫:

var func = (function(){
   var i = 5;  
   var privateFunc = function(){  //聲明了局部變量
        console.log("執(zhí)行了privateFunc局部函數(shù)");
    }
   var resultFunc = function(j){ 
        console.log("外部變量:"+j);
        console.log("內(nèi)部變量:"+i);
        privateFunc();  //調(diào)用局部函數(shù)
       //省略代碼
   }
   return resultFunc;
})();

var test = new func(9);
執(zhí)行結(jié)果

這樣看纳本,其實 resultFunc 更像是一個構(gòu)造函數(shù),這個函數(shù)在我們new func()的時候腋颠,必須且只執(zhí)行一次繁成,并且這個函數(shù)可以接受外部參數(shù)的哦。

----------------------------------------我是分割線-----------------------------------------

好了淑玫,接下來我們可以通過prototype的方式為其添加一些公開函數(shù)巾腕,而這些函數(shù)都是可以訪問局部變量及局部函數(shù)的:

var func = (function(){
   var i = 5;  
   var privateFunc = function(){  //聲明了局部變量
        console.log("執(zhí)行了privateFunc局部函數(shù)");
    }
   var resultFunc = function(j){ 
        console.log("外部變量:"+j);
        console.log("內(nèi)部變量:"+i);
        privateFunc();  //調(diào)用局部函數(shù)
       //省略代碼
   }
   var _proto = resultFunc.prototype; //取出prototype變量
    _proto.myName = "ken"; //prototype的變量
    _proto.publicFunc = function(){ //prototype的方法
        console.log("這個是公共的方法,還有我的名字是"+this.myName);
   }
   return resultFunc;
})();

var test = new func(9);
test.publicFunc();
console.log(test.myName);
運行結(jié)果

在外部能通過"."的方式調(diào)用prototype的內(nèi)容,prototype函數(shù)體內(nèi)通過this.訪問自身變量絮蒿。
就這樣尊搬,公共及私有成員方法都通過閉包實現(xiàn)出來。

----------------------------------------再次分割線-----------------------------------------

通過以上的土涝,公共變量及方法都是保存在prototype內(nèi)佛寿,那么其實如果想模擬面向?qū)ο蟮睦^承,只要把prototype拷貝就可以了但壮,先整理一下父類的代碼:

var Super = (function(){
    function _super(){
        console.log("Super constructor");
        this.name = "Super";
    }
    var _proto = _super.prototype;
    _proto.sayHi = function(){
        console.log("hello ! my name is "+this.getMyName());
    }
    _proto.getMyName = function(){
            return this.name;
        }
    return _super;
})();

var s = new Super();
s.sayHi();
父類被new的時候結(jié)果

以下是子類的繼承方式

var child = (function(){
  var extend = Super;         //定義要繼承的父類
  function _child(){          //子類的構(gòu)造函數(shù)
    extend.call(this);        //讓父類內(nèi)部的this替換成子類的this冀泻,執(zhí)行函數(shù)
    console.log("child constructor");
    this.name="child";        //覆蓋子類的name
  }
  var nullObj = function(){};  //這里建立一個空白對象
  nullObj.prototype = extend.prototype; //空白對象的prototype指向父類的prototype
  _child.prototype = new nullObj();     //新建nullObj(實際上是復(fù)制一份)的prototype給_child
  _child.prototype.constructor = _child;//把_child的構(gòu)造函數(shù)放回prototype里,因prototype剛剛已經(jīng)被覆蓋了
  var _proto = _child.prototype;  //取得prototype
  ///這里可以繼續(xù)添加子類的方法
  return _child;
})();

注意:nullObj.prototype = extend.prototype; 這里nullObj.prototype是引用,不能直接修改nullObj.prototype內(nèi)容茵肃,不然會影響父類的代碼,只能通過new nullObj 復(fù)制給 _child.prototype

調(diào)用測試

var c = new child();
c.sayHi();
console.log(c.name);
運行結(jié)果

可以看到這里首先是調(diào)用了父類的構(gòu)造函數(shù)袭祟,再調(diào)用子類的構(gòu)造函數(shù)验残,而后sayHi方法被子類繼承過來,而name內(nèi)容變成了子類的child字符串巾乳。

采用閉包的方式跟ES6的class有什么不一樣您没?
● ES6的class不存在私有成員鸟召,內(nèi)部通過this訪問變量或函數(shù),外部通過"."方式訪問氨鹏。
● 采用閉包方式可以擁有私有成員欧募,公共成員跟ES6訪問方式一樣,訪問私有成員因為作用域的關(guān)系仆抵,只要直接調(diào)用就好了跟继。
● ES6的使用比閉包方式要簡單,可以根據(jù)自己的情況選擇使用镣丑。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末舔糖,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子莺匠,更是在濱河造成了極大的恐慌金吗,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,496評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件趣竣,死亡現(xiàn)場離奇詭異摇庙,居然都是意外死亡,警方通過查閱死者的電腦和手機遥缕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評論 3 392
  • 文/潘曉璐 我一進店門卫袒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人通砍,你說我怎么就攤上這事玛臂。” “怎么了封孙?”我有些...
    開封第一講書人閱讀 162,632評論 0 353
  • 文/不壞的土叔 我叫張陵迹冤,是天一觀的道長。 經(jīng)常有香客問我虎忌,道長泡徙,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,180評論 1 292
  • 正文 為了忘掉前任膜蠢,我火速辦了婚禮堪藐,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘挑围。我一直安慰自己礁竞,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,198評論 6 388
  • 文/花漫 我一把揭開白布杉辙。 她就那樣靜靜地躺著模捂,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上狂男,一...
    開封第一講書人閱讀 51,165評論 1 299
  • 那天综看,我揣著相機與錄音,去河邊找鬼岖食。 笑死红碑,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的泡垃。 我是一名探鬼主播析珊,決...
    沈念sama閱讀 40,052評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼兔毙!你這毒婦竟也來了唾琼?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,910評論 0 274
  • 序言:老撾萬榮一對情侶失蹤澎剥,失蹤者是張志新(化名)和其女友劉穎锡溯,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體哑姚,經(jīng)...
    沈念sama閱讀 45,324評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡祭饭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,542評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了叙量。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片倡蝙。...
    茶點故事閱讀 39,711評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖绞佩,靈堂內(nèi)的尸體忽然破棺而出寺鸥,到底是詐尸還是另有隱情,我是刑警寧澤品山,帶...
    沈念sama閱讀 35,424評論 5 343
  • 正文 年R本政府宣布胆建,位于F島的核電站,受9級特大地震影響肘交,放射性物質(zhì)發(fā)生泄漏笆载。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,017評論 3 326
  • 文/蒙蒙 一涯呻、第九天 我趴在偏房一處隱蔽的房頂上張望凉驻。 院中可真熱鬧,春花似錦复罐、人聲如沸涝登。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽胀滚。三九已至咳短,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蛛淋,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評論 1 269
  • 我被黑心中介騙來泰國打工篡腌, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留褐荷,地道東北人。 一個月前我還...
    沈念sama閱讀 47,722評論 2 368
  • 正文 我出身青樓嘹悼,卻偏偏與公主長得像叛甫,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子杨伙,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,611評論 2 353

推薦閱讀更多精彩內(nèi)容