天天躁日日躁狠狠躁AV麻豆-天天躁人人躁人人躁狂躁-天天澡夜夜澡人人澡-天天影视香色欲综合网-国产成人女人在线视频观看-国产成人女人视频在线观看

Javascript 中的類和閉包

有人說Javascript也是面向對象的,只是它是prototype based,當然這只是概念上的區別,我不想討論js是不是面向對象的,關鍵是想說明雖然Javascript的類表現得很像其他語言中的類,但是內部的實現機理確不太一致,如果一味的把Javascript中的類類比作其他語言中的類,有時候腦子會犯混。

先看一段簡單的代碼,一般教材上介紹如何新建一個類的時候都是這樣的(當然還有更復雜的方法,不過本質上是一樣的):
復制代碼 代碼如下:
function MyClass(x) {
this.x = x;
}
var obj = new MyClass('Hello class');
alert(obj.x);

毫無疑問,此時obj具有一個x屬性,現在的值是 Hello class. 但是,obj到底是什么?MyClass僅僅是一個函數而已,我們稱之為構造函數。在其他OO的語言中,構造函數是要放在class關鍵字內部的,也就是先要聲明一個類。另外,函數體內的this又是什么?其他OO語言中,this的概念是很明確的,就是當前對象,因為它在構造函數執行之前已經聲明了類,類的內部的一些字段都是已經定義好的。

先解釋下,在Javascript的函數中,this關鍵字表示的是調用該函數的作用域(scope),作用域的概念也不是太好理解,下面再解釋。不過可以簡單的認為它是調用函數的對象。再看MyClass函數,它內部的this是什么呢?

如果我們把代碼改成:
復制代碼 代碼如下:
var obj = MyClass('Hello class');

這是完全合乎語法的。如果這段代碼是在瀏覽器中運行的,調試一下可以發現,this是window對象。而和obj沒有任何關系,obj還是undefined,alert也不會有結果。原來的代碼之所以可以工作,都是new關鍵字的功勞。new關鍵字把一個普通的函數變成了構造函數。也就是說,MyClass還是一個普通的函數,它之所以能構造出一個obj,基本上是new的功勞。當函數之前有new關鍵字的時候,Javascript會創造一個匿名對象,并且把當前函數的作用域設置為這個匿名對象。然后在那個函數內部引用this的話就是引用的這個匿名對象,最后,即使這個函數沒有return,它也會把這個匿名對象返回出去。那么obj自然就具有了x屬性。

現在這個MyClass已經有點像一個類了。但是,這并不是new的工作的全部。Javascript同樣可以方便的實現繼承――依靠是prototype.prototype也是一個對象,畢竟除了原始類型,所有的東西都是對象,包括函數。更為重要的是,前面提到Javascript是prototype based,它的含義就是在Javascript中沒有類的概念,類是不存在的,一個函數,它之所以表現的像類,就是靠的prototype. prototype可以有各種屬性,也包括函數。上一段說的new在構造對象的過程中,在最終返回那個匿名對象之前,還會把那個函數的prototype中的屬性一一復制給這個對象。這里的復制是復制的引用,而不是新建的一個對象,把內容復制過來,在其內部,相當于保留了一個構造它的函數的prototype的引用。有些教材含糊的說所有的“所有對象都有一個prototype屬性”,這種說法是不確切的,雖然它內部確實有一個prototype屬性,但是對外是不可見的。只有函數對象是有prototype屬性的,函數對象的prototype默認有一個constructor屬性。

看如下的代碼:
復制代碼 代碼如下:
function MyClass(x) {
this.x = x;
}
var proObj = new MyClass('x');
InheritClass.prototype = proObj;
MyClass.prototype.protox = 'xxx';
function InheritClass(y) {
this.y = y;
}
var obj = new InheritClass('Hello class');
MyClass.prototype.protox = 'changed';
proObj.x = 'Changed Too';
alert(obj.protox);
alert(obj.x);

輸出的結果是changed和Changed Too。此代碼說明了對象內部保留的是構造函數的prototype的引用,要注意的是,proObj中也是保留的它的構造函數的prototype的引用。如果把代碼改成:
復制代碼 代碼如下:
var obj = new InheritClass('Hello class');
proObj.protox = 'I am winner';
MyClass.prototype.protox = 'changed';
proObj.x = 'Changed Too';
alert(obj.protox);
alert(obj.x);

輸出的就是 I am winner 和 Changed Too了。事實上,這些prototype逐層引用,構成了一個prototype鏈。當讀取一個對象的屬性的時候,首先尋找自己定義的屬性,如果沒有,就逐層向內部隱含的prototype屬性尋找。但是在寫屬性的時候,就會把它的引用覆蓋掉,是不會影響prototype的值的。
再介紹閉包,首先說明下,這里的閉包(closure)和離散數學中關系的傳遞閉包中的不是一個概念,我曾以為他們之間有關聯,后來仔細想想,似乎并無什么關聯,恰好名字一樣而已。先看定義:
Closure
A "closure" is an expression (typically a function) that can have free variables together with an environment that binds those variables (that "closes" the expression).
要完全理解閉包需要對Javascript函數的機理有比較透徹的理解,而這個機理有點復雜,并不是三言兩語能講清的,有興趣的朋友可以看這里 Javascript clousures. 即使是這篇文章,也只是大概講了下原理。大意就是任何一個函數調用都在一個運行上下文(Execution Context)中執行的,這個上下文中有一個作用域對象,其中包括了這個函數的局部變量、參數等。另外,如果一個函數是一個內部函數,它的作用域中含有它外部函數的作用域。在內部函數遇到一個變量名的時候,它是從內部的作用域找起,不斷往外層的作用域找。因此,如果內部函數作為一個對象返回出外部函數的時候,即使外部函數已經執行完畢,但是由于其內部函數仍有引用指向它,內部函數不會被釋放,因為內部函數有外部函數的作用域,因此外部函數的局部變量也不會被釋放。這就構成了閉包。

JavaScript技術Javascript 中的類和閉包,轉載需保留來源!

鄭重聲明:本文版權歸原作者所有,轉載文章僅為傳播更多信息之目的,如作者信息標記有誤,請第一時間聯系我們修改或刪除,多謝。

主站蜘蛛池模板: 欧美高清vivoesosexo10 | 日产2021免费一二三四区在线 | 国产成人免费在线观看 | 成年人免费观看的视频 | 亚洲 日本 中文字幕 制服 | 妖精视频一区二区免费 | 老师别揉我胸啊嗯小说 | 国产成人免费在线观看 | 在线观看亚洲AV无码每日更新 | 四虎国产精品高清在线观看 | 私人玩物在线观看 | 乱淫67194 | 肉动漫3D卡通无修在线播放 | 亚洲欧洲自拍偷拍 | 色综合色综合久久综合频道 | 午夜福到在线4国产 | 亚洲欧美国产旡码专区 | 国内精品视频一区二区在线观看 | 亚洲精品中文字幕一二三四区 | 神马午夜不卡片 | 色欲AV亚洲永久无码精品 | 伦理电影v男人天堂 | 亚洲久热无码中文字幕 | 日本高清免费看 | 国产高清视频在线观看不卡v | av天堂影音先锋在线 | z00兽200俄罗斯| 久久一er精这里有精品 | 办公室里做好紧好爽H | 一品道门在线观看免费视频 | 香蕉久久日日躁夜夜嗓 | 伊人热人久久中文字幕 | 午夜无码国产理论在线 | 久久热精品18国产 | 精品网站一区二区三区网站 | 久久精品亚洲精品国产欧美 | 耻辱诊察室1一4集动漫在线观看 | 无人区日本电影在线观看 | 色综合久久中文色婷婷 | 精品动漫国产亚洲AV在线观看 | 国产一级做a爰片久久毛片男 |