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

首頁 > 編程 > JavaScript > 正文

深入理解JavaScript系列(17):面向?qū)ο缶幊讨耪撛敿毥榻B

2019-11-20 13:01:07
字體:
供稿:網(wǎng)友

介紹

在本篇文章,我們考慮在ECMAScript中的面向?qū)ο缶幊痰母鱾€方面(雖然以前在許多文章中已經(jīng)討論過這個話題)。我們將更多地從理論方面看這些問題。 特別是,我們會考慮對象的創(chuàng)建算法,對象(包括基本關(guān)系 - 繼承)之間的關(guān)系是如何,也可以在討論中使用(我希望將消除之前對于JavaScript中OOP的一些概念歧義)。

英文原文:http://dmitrysoshnikov.com/ecmascript/chapter-7-1-oop-general-theory/

概論、范式與思想

在進行ECMAScript中的OOP技術(shù)分析之前,我們有必要掌握一些OOP基本的特征,并澄清概論中的主要概念。

ECMAScript支持包括結(jié)構(gòu)化、面向?qū)ο蟆⒑瘮?shù)式、命令式等多種編程方式,某些情況下還支持面向方面編程;但本文是討論面向?qū)ο缶幊蹋詠斫o出ECMAScript中面向?qū)ο缶幊痰亩x:

ECMAScript是基于原型實現(xiàn)的面向?qū)ο缶幊陶Z言。
基于原型的OOP和基于靜態(tài)類的方式直接有很多差異。 讓我們一起來看看他們直接詳細的差異。

基于類特性和基于原型

注意,在前面一句很重要的一點已經(jīng)指出的那樣-完全基于靜態(tài)類。 隨著“靜態(tài)”一詞,我們了解靜態(tài)對象和靜態(tài)類,強類型(雖然不是必需的)。

關(guān)于這種情況,很多論壇上的文檔都有強調(diào)這是他們反對將在JavaScript里將“類與原型”進行比較的主要原因,盡管他們在實現(xiàn)上的有所不同(例如基于動態(tài)類的Python和Ruby)不是太反對的重點(某些條件寫,盡管思想上有一定不同,但JavaScript沒有變得那么另類),但他們反對的重點是靜態(tài)類和動態(tài)原型(statics + classes vs. dynamics + prototypes),確切地說,一個靜態(tài)類(例如:C + +,JAVA)和他的屬下及方法定義的機制可以讓我們看到它和基于原型實現(xiàn)的準(zhǔn)確區(qū)別。

但是,讓我們來一個一個列舉一下。 讓我們考慮總則和這些范式的主要概念。

基于靜態(tài)類

在基于類的模型中,有個關(guān)于類和實例的概念。 類的實例也常常被命名為對象或范例 。

類與對象

類代表了一個實例(也就是對象)的抽象。在這方面有點像數(shù)學(xué),但我們一把稱之為類型(type)或分類(classification)。

例如(這里和下面的例子都是偽代碼):

復(fù)制代碼 代碼如下:

C = Class {a, b, c} // 類C, 包括特性a, b, c

實例的特點是:屬性(對象描述 )和方法(對象活動)。特性本身也可視為對象:即屬性是否可寫的,可配置,可設(shè)置的(getter/setter)等。因此,對象存儲了狀態(tài) (即在一個類中描述的所有屬性的具體值),類為他們的實例定義了嚴格不變的結(jié)構(gòu)(屬性)和嚴格不變的行為(方法)。
復(fù)制代碼 代碼如下:

C = Class {a, b, c, method1, method2}
 
c1 = {a: 10, b: 20, c: 30} // 類C是實例:對象с1
c2 = {a: 50, b: 60, c: 70} // 類C是實例:對象с2,擁有自己的狀態(tài)(也就是屬性值)

層次繼承

為了提高代碼重用,類可以從一個擴展為另一個,在加上額外的信息。 這種機制被稱為(分層)繼承 。

復(fù)制代碼 代碼如下:

D = Class extends C = {d, e} // {a, b, c, d, e}
d1 = {a: 10, b: 20, c: 30, d: 40, e: 50}

在類的實例上調(diào)用方的時候,通常會現(xiàn)在原生類本書就查找該方法,如果沒找到就到直接父類去查找,如果還沒找到,就到父類的父類去查找(例如嚴格的繼承鏈上),如果查到繼承的頂部還沒查到,那結(jié)果就是:該對象沒有類似的行為,也沒辦法獲取結(jié)果。

復(fù)制代碼 代碼如下:

d1.method1() // D.method1 (no) -> C.method1 (yes)
d1.method5() // D.method5 (no) -> C.method5 (no) -> no result

與在繼承里方法不復(fù)制到一個子類相比,屬性總是被復(fù)雜到子類里的。 我們可以看到子類D繼承自父類C類:屬性a,b,c是復(fù)制過去了,D的結(jié)構(gòu)是{a, b, c, d, e} } 。然而,方法{method1, method2}是沒有復(fù)制過去,而是繼承過去的。 因此,也就是說如果一個很深層次的類有一些對象根本不需要的屬性的話,那子類也有擁有這些屬性。

基于類的關(guān)鍵概念

因此,我們有如下關(guān)鍵概念:

1.創(chuàng)建一個對象之前,必須聲明類,首先有必要界定其類
2.因此,該對象將由抽象成自身“象形和相似性”(結(jié)構(gòu)和行為)的類里創(chuàng)建
3.方法是通過了嚴格的,直接的,一成不變的繼承鏈來處理
4.子類包含了繼承鏈中所有的屬性(即使其中的某些屬性是子類不需要的);
5.創(chuàng)建類實例,類不能(因為靜態(tài)模型)來改變其實例的特征(屬性或方法);
6.實例(因為嚴格的靜態(tài)模型)除了有該實例所對應(yīng)類里聲明的行為和屬性以外,是不能額外的行為或?qū)傩缘摹?/p>

讓我們看看在JavaScript里如何替代OOP模型,也就是我們所建議的基于原型的OOP。

基于原型
這里的基本概念是動態(tài)可變對象。轉(zhuǎn)換(完整轉(zhuǎn)換,不僅包括值,還包括特性)和動態(tài)語言有直接關(guān)系。下面這樣的對象可以獨立存儲他們所有的特性(屬性,方法)而不需要的類。

復(fù)制代碼 代碼如下:

object = {a: 10, b: 20, c: 30, method: fn};
object.a; // 10
object.c; // 30
object.method();

此外,由于動態(tài)的,他們可以很容易地改變(添加,刪除,修改)自己的特性:

復(fù)制代碼 代碼如下:

object.method5 = function () {...}; // 添加新方法
object.d = 40; // 添加新屬性 "d"
delete object.c; // 刪除屬性 "с"
object.a = 100; // 修改屬性 "а"
 
// 結(jié)果是: object: {a: 100, b: 20, d: 40, method: fn, method5: fn};

也就是說,在賦值的時候,如果某些特性不存在,則創(chuàng)建它并且將賦值與它進行初始化,如果它存在,就只是更新。

在這種情況下,代碼重用不是通過擴展類來實現(xiàn)的,(請注意,我們沒有說類沒辦法改變,因為這里根本沒有類的概念),而是通過原型來實現(xiàn)的。

原型是一個對象,它是用來作為其他對象的原始copy,或者如果一些對象沒有自己的必要特性,原型可以作為這些對象的一個委托而當(dāng)成輔助對象。

基于委托

任何對象都可以被用來作為另一個對象的原型對象,因為對象可以很容易地在運行時改變它的原型動態(tài)。

注意,目前我們正在考慮的是概論而不是具體實現(xiàn),當(dāng)我們在ECMAScript中討論具體實現(xiàn)時,我們將看到他們自身的一些特點。

例(偽代碼):

復(fù)制代碼 代碼如下:

x = {a: 10, b: 20};
y = {a: 40, c: 50};
y.[[Prototype]] = x; // x是y的原型
 
y.a; // 40, 自身特性
y.c; // 50, 也是自身特性
y.b; // 20 主站蜘蛛池模板: 兴业县| 玛多县| 临武县| 南召县| 铁岭县| 陈巴尔虎旗| 汶上县| 民和| 上犹县| 横山县| 沙河市| 林西县| 军事| 临湘市| 耒阳市| 马山县| 虎林市| 武冈市| 泾源县| 安阳市| 巩留县| 石城县| 平顶山市| 广宁县| 交城县| 邹平县| 当雄县| 晋中市| 横峰县| 咸宁市| 崇礼县| 浪卡子县| 郑州市| 无棣县| 沈阳市| 龙川县| 油尖旺区| 安阳市| 松滋市| 安阳市| 彭泽县|