国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

如何優雅的理解ECMAScript中的對象

why_rookie / 3218人閱讀

摘要:標準對象,語義由本規范定義的對象。這意味著雖然有,本質上依然是構造函數,并不能像那樣表演多繼承嵌套類等高難度動作。不過這里的并不是我們所說的數據類型,而是對象構造函數。

ECMAScript is an object-oriented programming language for performing computations and manipulating computational objects within a host environment.
— 摘自《ECMAScript? 2018 Language Specification》.

最近在看 ES 規范,越看越覺得這是一門神奇的語言。如標準所言,ES 是一門面向對象的編程語言,但它基于 prototype 的 OO 又很非主流。更神奇的是很多 JSer 拿著這門 OOP 來搞函數式和過程式編程,并且還浪的飛起。本文會圍繞 ES 中的對象來展開,一起探索技術,走近科學(瞎扯淡,這并不是一篇正兒八經的技術文章)。

創世篇 null

null是萬物之伊始,也是生命的盡頭。null 是一種空靈的狀態,似是非是,似空非空,正如 null == undefined 但是 null !== undefined,看起來什么都沒有,其實是支潛力股。

在 JS 宇宙中,null 是站在原型鏈頂端的男人,是所有對象原型的盡頭,擁有毀滅一切的能力,看誰不爽賦值為 null,這樣黑白無常在垃圾回收的時候便可以一波帶走。

后來 JS 的造物主 Brendan 覺得 null 的能力過于強大,于是便創造了超級英雄
undefined 與之抗衡。undefined 誕生的初衷,是為了維護 JS 宇宙秩序,解決錯誤處理和類型轉換帶來的問題。但是自 undefined 出現之后世界卻變得更加混亂,人類不知道何時召喚 null 何時該召喚 undefined。

簡單的說,undefined 表示此處應該有個值,但是這個值還沒給出來,其實就是占了個坑,這個坑是語言內部實現幫你做的,程序員完全沒有必要在代碼中顯示返回或者指定某個變量為 undefined,undefined 的處理完全交給程序實現就是了。所以這其實是個無需暴露給用戶的能力,傳說 Google 爸爸在創建 Dart 宇宙的時候就去掉了 undefined,只保留了 null。

Object

古人信奉五行陰陽之說,認為世界由金木水火土五種基本元素構成,基本元素構成各種物質,物質構成世界。在 JS 宇宙中也一樣,基本語言類型構成了各種對象,對象構成了整個 JS 世界,要理解這個世界,就得從找對象開始。

在 ES5 時代,對象分三種:

native object(原生對象),指語義完全由規范定義并且不摻雜任何宿主環境定義的的對象;

host object(宿主對象),由執行環境提供,比如瀏覽器的window對象和history對象。JS里的對象不是原生對象就是宿主對象。

build-in object(內置對象),由ECMA實現提供,程序執行時就存在的對象。所有內置對象都是原生對象。

這三類對象相輔相成,亦相克相生。所謂的道生一,一生二,二生三,三生萬物,在 JS 的世界觀中,大概就是指的 null 生 Object,Object 生 native & host,native 又分化出buid-in,是為三才,森羅萬象。

然而編碼不止,變化不息,在 ES6 時代,規范中有關對象的劃分又變成了四種:

ordinary object:普通對象,需要具備了對象的所有基本內置方法。

exotic object:外來對象,如果不完全具備標準對象擁有的基本內置方法,就是外來對象。JS里的對象不是普通對象就是外來對象。

standard object:標準對象,語義由本規范定義的對象。

built-in object:內置對象,跟ES5中描述一樣。

對比來看,ES5 中對象是以宿主環境為條件劃分的,ES6 中則是根據對象的基本內置方法。這其實要歸結于 ES6 跨越性的變化,必然要動搖到一些基本規范描述來擁抱變化。所謂的無極生太極,太極生兩儀,兩儀生四象,在 JS 宇宙中大概,也許,null 就是無極,Object 就是太極,一內一外是兩儀,四象嘛,當然就是上面那四種對象了啦......

當然我是在扯淡。

Class

在我開始用 JS 搬磚之前,是不那么認真的先用了 Java 和 C++。所以一般看來,在有對象之前必先有類,對象只是類的一個實例而已。就好比找女朋友之前先得構造一個理想女票該有的屬性和行為的類,然后再從該類實例化一個對象:

public class GirlFriend {
  public static final Integer age = 18;
  public static final String sex = "女";
  public void eat() {}
  public void shop() {}
  public void sleep() {}

  public static void main(String[] args) {
    GirlFriend honey = new GirlFriend();
  }
}

這很符合人類的常識,人們喜歡分類,這樣便于組織管理,可以將復雜的問題簡單化,清晰化。但是,這并不是世界原本的樣子,也不能表現出內心最真實的渴求,只是我們自己一廂情愿的束縛。或許只有當你放下類,放下包袱,放棄規則,放縱去愛,放肆自己,放空未來......才能享受這盛夏光年激蕩地青春,才會發現,會發現自己喜歡的并不是蘿莉,而是御姐......

這便是 JS 的無類哲學:世界本無類,對象亦無根,本是弱類型,何處惹塵埃?

然塵世熙攘,你我結廬于人境,誰能不聞車馬喧?能夠做到超脫的畢竟是少數,這不,ES6 中還是引入了類的概念。

不過在我看來,ES6 的 class 并未動搖 JS 無類對象的哲學根基,更像是普渡眾生的炫邁語法糖。畢竟,typeof class GirlFriend {} 返回的并不是一個類,而是一個 function。這意味著JS雖然有 class,本質上依然是構造函數,并不能像 Java 那樣表演多繼承、嵌套類等“高難度”動作。

這樣也好,讓 JSer 們繼續做一個不拘一格的自由主義者。

混沌篇 function VS object

有很長一段時間,我無法清晰的理解 function 和 object 之間的曖昧關系,就像這樣:

Function instanceof Object // 返回 true
Object instanceof Function // 依然返回 true

那么問題來了,到底是先有 Object,還是先有 Function ?

按照創世篇的理念來講,必然是先有 Object 的概念,然后才孕育出 Function,所以 Object 是蛋,Function 是雞(有關先有蛋還是先有雞的哲學問題,我是更傾向于先有蛋的。這個蛋是天地未開,陰陽一體,混沌之道。所謂道生蛋,蛋生雞,雞中有蛋,蛋中有雞,雞又生蛋,蛋又生雞,蛋蛋雞雞,無窮盡也,說的就是這個道理)。

當然我是有理論依據的,按照 ES2018 中關于 Object 的描述:

In ECMAScript, an object is a collection of zero or more properties each with attributes that determine how each property can be used—for example, when the Writable attribute for a property is set to false, any attempt by executed ECMAScript code to assign a different value to the property fails. Properties are containers that hold other objects, primitive values, or functions. A primitive value is a member of one of the following built-in types: Undefined, Null, Boolean, Number, String, and Symbol; an object is a member of the built-in type Object; and a function is a callable object. A function that is associated with an object via a property is called a method.

這里明確指出了函數是可調用的對象。對象本身的定義就是屬性的集合,函數就是擁有特定屬性的集合。所以從表面上看,確實是先有對象的概念才衍生出函數的概念。然細思極恐,如果你仔細研讀標準,就會發現在對象誕生之時,函數其實已經出現了!所以標準中才叫function object:

An ECMAScript function object is an ordinary object and has the same internal slots and the same internal methods as other ordinary objects.

這是一種既滿足先有蛋后有雞又滿足同時有蛋和雞的量子疊加態。所以這個時候討論誰先誰后已經沒有意義了,本自同根生,相煎何太急?

況且他們真的是同根生,這是有科學依據的:

Object.getPrototypeOf(Function) === Object.getPrototypeOf(Object)

規范中使用[[prototype]]表示原型,并提供了getPrototypeOf方法來獲取它,瀏覽器有一個非標準的實現,可通過__proto__內部屬性來訪問,本文圖方便就使用__proto__來訪問。

回到最初的問題,正是因為 Object 和 Function 的[[prototype]]相同,所以 instanceof 才會返回 true。不過這里的 Object 并不是我們所說的 Object 數據類型,而是對象構造函數。

typeof Function // 返回 "function"
typeof Object   // 依然返回 "function"

構造函數都有一個prototype屬性,所有通過構造函數實例化的對象的[[prototype]]都會指向該構造函數的 prototype 屬性的引用,即:

實例對象.__proto__ === 構造函數.prototype              // ①

所有函數都是基于 Function 構造出來的,由式①可知:

// Function 和 Object 作為構造函數,自然不例外
Function.__proto__ === Function.prototype           // ②      
Object.__proto__ === Function.prototype             // ③
在座的各位函數.__proto__ === Function.prototype    // ④

前面也有說到,所有對象的原型都會指向一個最基本的太極對象,太極原型終于無極。Function 構造函數作為一個特殊的對象,自然也有:

Object.prototype.__proto__ === null
Object.__proto__.__proto__ === Object.prototype
Function.__proto__.__proto__ === Object.prototype   // ⑤
Function.prototype.__proto__ === Object.prototype   // 可由②⑤推出
在座的各位函數.__proto__.__proto__ === Object.prototype // 可由④⑤推出

明白了上述道理,也就明白了 JS 原型的真諦,可謂玄之又玄,眾妙之門。

prototype chain

ES 原型鏈的設計,其實是非常符合自然法則的。

我們每個人看似獨立的個體,其實都可以追溯到共同的祖先。就好比 JS 中的對象看似獨立,其實都有著同一個原型。原型鏈就跟血液一樣,可以遺傳父輩屬性實現繼承,但是比起血緣關系,又更像是血繼限界,除了遺傳之外還能進化出新的能力。這一點,比起基于類的繼承更加靈活,也更符合進化論的思想。

但是有一點,ES 是單原型單繼承的,這不符合自然規律。現實中孩子一般繼承了父母雙方的基因。試想一下,如果對象的原型是一個數組,可繼承每一個原型對象的屬性,那么 JS 世界會發生哪些變化?

最直接的就是可以支持多繼承了,但本質上不會有變化,最終都會上溯到 Object.prototype。不過查戶口會變得異常困難。如果要判斷一個對象是否具有某個屬性,要遍歷的就不是原型鏈了,而是原型網,這是一個十分耗時的操作,所以單繼承雖然喪失了生物的多樣性,卻保持了血統的純正性,讓這門語言可以一直保持簡單,優雅。

嗯,我成功的說服了自己,單原型單繼承并不是 JS 的缺陷,而是體現 JS 簡單耐用的神來之筆,在前端開發場景下,更能突顯出它的優勢。因為,老實說,前端的業務場景本就沒有后端復雜,沒必要引入一套復雜的體系。

然而原型鏈設計的最讓我詫異的是,實例對象竟然可直接訪問并修改原型,從而影響所有其他實例對象,不愧是一把原型鏈,連接彼此心,牽動你和我:

function GirlFriend() {} // 或者 class GirlFriend {}

// 假設張無忌同時談了兩個女朋友
let zhaoMin = new GirlFriend()
let zhouZhiRuo = new GirlFriend()

// 某天周芷若黑化跟張無忌分手了
zhouZhiRuo.breakUp = true

// 周芷若一氣之下將其原型也修改了
zhouZhiRuo.__proto__.breakUp = true

// 然后趙敏也躺槍了,張無忌成單身狗了
console.log(zhaoMin.breakUp) // true

這是不是一件非常可怕的事情!這肯定是一件非常可怕的事情!趙敏是無辜的啊!韋小寶該怎么辦?

后來,我在規范中看到這樣一段描述:

Every ordinary object has a Boolean-valued [[Extensible]] internal slot that controls whether or not properties may be added to the object. If the value of the [[Extensible]] internal slot is false then additional properties may not be added to the object. In addition, if [[Extensible]] is false the value of the [[Prototype]] internal slot of the object may not be modified. Once the value of an object"s [[Extensible]] internal slot has been set to false it may not be subsequently changed to true.

看樣子,只要將原型對象的內部屬性[[Extensible]]設置為 false 即可防止被子對象篡改。然而由于是內部屬性,并不屬于 ES 語言的一部分,瀏覽器也沒有像暴露原型一樣將其暴露出來,所以此路不通。另外,即使用 ES6 新增的 class,也無法避免被子對象修改的命運,估計在后面的
ES 版本中會加上 class 限定符吧。

難道就沒有別的辦法了嗎?解鈴還須系鈴人,既然問題出在原型上,那么還是得從原型下手。趙敏心想,如果我也直接修改原型上breakUp屬性為 false,那么周芷若也會回到無忌哥身邊,干脆一不做二不休:

function Wife() {}
zhaoMin.__proto__ = Wife.prototype

從此,張無忌和趙敏過上了幸福快樂的生活。這個故事有些夸張,但你我身邊,或許就有周芷若和趙敏這樣的人才。

可以說,ES 的原型鏈設計的相當自由,它只是提供了一個 playground,至于怎么去寫,怎么去玩,規則都可以由你自己定義。ES 設計之初的理念就是越簡單越好,所謂大道至簡,悟在天成,JS 的靈活,得益于它的簡單,JS 的復雜,亦歸咎于它的簡單。

飛升篇

慢慢地,我開始覺著 ES 的設計理念由內到外散發著一股自由的氣息,在 JS 的世界中,你可以很面向對象,也可以很面向過程,還可以很函數式;時而騰云駕霧游九州,時而不慎跌落終結谷;有精華亦有糟粕,正如有光明必有陰影。JS 開發路上,可能會經歷人生的大徹大悟,大起大落,但這不正是我們生活的真實寫照嗎?我們要時刻保持一種包容和謙卑的態度,去書寫更加優雅和睿智的人生,打造屬于前端開發者的未來。

好了我編不下去了了,先這樣吧。本文是《ECMAScript 2018 標準導讀》中的第一篇番外,感興趣的話可以關注下,帶著哲思搞技術,你會發現編程竟如此有趣。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/83646.html

相關文章

  • ECMAScript 2018 標準導讀

    摘要:標準對象,語義由本規范定義的對象。三個冒號作為分隔符分割數字字符串文法的產生式。所有因為帶來的問題,基本上是占著茅坑不拉屎的行為導致。以數組測試操作為例,標準中的描述如下相對于來說,規范中增加了對的處理。 前言 本文是對《ECMAScript 2018 Language Specification》的解讀。本文是對標準的概述性導讀,不是對 ES2018特性的詳細描述,也不會針對某個技術...

    MiracleWong 評論0 收藏0
  • JavaScript 優雅實現方式包含你可能不知道知識點

    摘要:優點簡單粗暴,直接調用缺點兼容性不太好,不過的話都支持你可能不知道的前端知識點對象和的方法。下面從深層次剖析一下對于開始的兩個賦值語句,,,相當于,而顯然等于。同理可以分析第三個賦值語句 有些東西很好用,但是你未必知道;有些東西你可能用過,但是你未必知道原理。 實現一個目的有多種途徑,俗話說,條條大路通羅馬。很多內容來自平時的一些收集以及過往博客文章底下的精彩評論,收集整理拓展一波,發...

    617035918 評論0 收藏0
  • JavaScript 優雅實現方式包含你可能不知道知識點

    摘要:優點簡單粗暴,直接調用缺點兼容性不太好,不過的話都支持你可能不知道的前端知識點對象和的方法。下面從深層次剖析一下對于開始的兩個賦值語句,,,相當于,而顯然等于。同理可以分析第三個賦值語句 有些東西很好用,但是你未必知道;有些東西你可能用過,但是你未必知道原理。 實現一個目的有多種途徑,俗話說,條條大路通羅馬。很多內容來自平時的一些收集以及過往博客文章底下的精彩評論,收集整理拓展一波,發...

    Zhuxy 評論0 收藏0
  • JavaScript 優雅實現方式包含你可能不知道知識點

    摘要:優點簡單粗暴,直接調用缺點兼容性不太好,不過的話都支持你可能不知道的前端知識點對象和的方法。下面從深層次剖析一下對于開始的兩個賦值語句,,,相當于,而顯然等于。同理可以分析第三個賦值語句 有些東西很好用,但是你未必知道;有些東西你可能用過,但是你未必知道原理。 實現一個目的有多種途徑,俗話說,條條大路通羅馬。很多內容來自平時的一些收集以及過往博客文章底下的精彩評論,收集整理拓展一波,發...

    KaltZK 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<