【譯】Arrays, symbols, and realms

本文是中文翻譯硫眯,英文原文鏈接 https://jakearchibald.com/...

Allen Wirfs-Brock 在 Twitter上沒有查找到Array.isArray(obj)的原理爷辙,并且找到了錯誤的答案普办。

數(shù)組類型檢查

function foo(obj) {
  // …
}

假設obj是一個數(shù)組,并且對其做些特殊處理驼鞭。舉例JSON.stringify對數(shù)組做了特殊處理缨历。

我們可以這樣做:

if (obj.constructor == Array) // …

但是這樣不能判斷數(shù)組的派生:

class SpecialArray extends Array {}
const specialArray = new SpecialArray();
console.log(specialArray.constructor === Array); // false
console.log(specialArray.constructor === SpecialArray); // true

如果你想判斷子類可以使用instanceof:

console.log(specialArray instanceof Array); // true
console.log(specialArray instanceof SpecialArray); // true

但是當引入多realms時事情就變得復雜了揪罕。

Multiple realms

realm 包含JavaScript全局對象,self引用的它吆鹤,因此可以說程序在不同的頁面中運行在不同的realm 里厨疙。在iframe中也是這樣的,在同源iframe中共享 ECMAScript agent疑务,這意味著對象可以在跨realm傳播沾凄。

認真的看:

<iframe srcdoc="<script>var arr = [];</script>"></iframe>
<script>
  const iframe = document.querySelector('iframe');
  const arr = iframe.contentWindow.arr;
  console.log(arr.constructor === Array); // false
  console.log(arr.constructor instanceof Array); // false
</script>

這兩個都是false,因為:

console.log(Array === iframe.contentWindow.Array); // false

...iframe有自己的數(shù)組構造函數(shù),它是和父頁面的是不同的知允。

輸入 Array.isArray

console.log(Array.isArray(arr)); // true

Array.isArray判斷數(shù)組時會一直返回true撒蟀,即使是在其他realm創(chuàng)建的數(shù)組,它一直返回true無論是派生的數(shù)組還是其他realm中温鸽。這就是JSON.stringify使用的保屯。

但是手负,正如 Allen 所揭示的,這并不意味這arr有任何數(shù)組的方法姑尺。一些或者所有方法都可能被設置為undefined竟终,甚至刪除掉數(shù)組的整個原型:

const noProtoArray = [];
Object.setPrototypeOf(noProtoArray, null);
console.log(noProtoArray.map); // undefined
console.log(noProtoArray instanceof Array); // false
console.log(Array.isArray(noProtoArray)); // true

這就是我在 Allen 的投票中弄錯的地方,我選擇了’it has Array methods‘切蟋,這是選擇最少的答案统捶。所以現(xiàn)在感覺挺時髦的。

總之敦姻,你想防御上述問題瘾境,你可以從數(shù)組原型上使用數(shù)組方法:

if (Array.isArray(noProtoArray)) {
  const mappedArray = Array.prototype.map.call(noProtoArray, callback);
  // …
}

Symbols and realms

看看這個:

<iframe srcdoc="<script>var arr = [1, 2, 3];</script>"></iframe>
<script>
  const iframe = document.querySelector('iframe');
  const arr = iframe.contentWindow.arr;

  for (const item of arr) {
    console.log(item);
  }
</script>

上面會打印出1、2镰惦、3迷守。但是for-of循環(huán)工作時會調(diào)用arr[Symbol.iterator],這是它可以跨realm工作的原因:

const iframe = document.querySelector('iframe');
const iframeWindow = iframe.contentWindow;
console.log(Symbol === iframeWindow.Symbol); // false
console.log(Symbol.iterator === iframeWindow.Symbol.iterator); // true

雖然每個realm都有自己的Symbol對象旺入,但是Symblo.iterator在不同的realm都是相同的兑凿。

借用 Keith Cirkel 的話:SymbolsJavaScript中最獨特和最不獨特的東西。

最獨特的

const symbolOne = Symbol('foo');
const symbolTwo = Symbol('foo');
console.log(symbolOne === symbolTwo); // false
const obj = {};
obj[symbolOne] = 'hello';
console.log(obj[symbolTwo]); // undefined
console.log(obj[symbolOne]); // 'hello'

Symbol函數(shù)中的string參數(shù)僅僅是個描述茵瘾,即使在相同的realm中這些symbols都是唯一的礼华。

最不獨特的

const symbolOne = Symbol.for('foo');
const symbolTwo = Symbol.for('foo');
console.log(symbolOne === symbolTwo); // true
const obj = {};
obj[symbolOne] = 'hello';
console.log(obj[symbolTwo]); // 'hello'

Symbol.for(str)會創(chuàng)建一個唯一的symbol和你傳遞的字符串綁定。有趣的是在不同的realm中它得到的也是一樣的拗秘。

const iframe = document.querySelector('iframe');
const iframeWindow = iframe.contentWindow;
console.log(Symbol.for('foo') === iframeWindow.Symbol.for('foo')); // true

這就可以解釋Symbol.iterator是怎么工作的圣絮。

創(chuàng)建自己的is函數(shù)

如果我們想創(chuàng)建一個可以在不同realm工作的is函數(shù),可以通過Symbol做到雕旨。

const typeSymbol = Symbol.for('whatever-type-symbol');

class Whatever {
  static isWhatever(obj) {
    return obj && Boolean(obj[typeSymbol]);
  }
  constructor() {
    this[typeSymbol] = true;
  }
}

const whatever = new Whatever();
Whatever.isWhatever(whatever); // true

來自其他realm的實例扮匠、該實例的子類和刪除原型的實例都可以使用這個方法。

唯一的小問題是你要手動保證Symbol名稱是在所有代碼中是唯一的凡涩。如果有別人創(chuàng)建了Symbol.for('whatever-type-symbol')并賦予了其他含義棒搜,則isWhatever可能會報錯。

(原文地址 http://www.reibang.com/p/a… 活箕,轉載需經(jīng)過作者同意A︳铩)

進一步閱讀

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市育韩,隨后出現(xiàn)的幾起案子克蚂,更是在濱河造成了極大的恐慌,老刑警劉巖座慰,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件陨舱,死亡現(xiàn)場離奇詭異,居然都是意外死亡版仔,警方通過查閱死者的電腦和手機游盲,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進店門误墓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人益缎,你說我怎么就攤上這事谜慌。” “怎么了莺奔?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵欣范,是天一觀的道長。 經(jīng)常有香客問我令哟,道長恼琼,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任屏富,我火速辦了婚禮晴竞,結果婚禮上,老公的妹妹穿的比我還像新娘狠半。我一直安慰自己噩死,他們只是感情好,可當我...
    茶點故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布神年。 她就那樣靜靜地躺著已维,像睡著了一般。 火紅的嫁衣襯著肌膚如雪已日。 梳的紋絲不亂的頭發(fā)上垛耳,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天,我揣著相機與錄音飘千,去河邊找鬼艾扮。 笑死,一個胖子當著我的面吹牛占婉,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播甫恩,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼逆济,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了磺箕?” 一聲冷哼從身側響起奖慌,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎松靡,沒想到半個月后简僧,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡雕欺,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年岛马,在試婚紗的時候發(fā)現(xiàn)自己被綠了棉姐。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡啦逆,死狀恐怖伞矩,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情夏志,我是刑警寧澤乃坤,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站沟蔑,受9級特大地震影響湿诊,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜瘦材,卻給世界環(huán)境...
    茶點故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一厅须、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧宇色,春花似錦九杂、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至抢蚀,卻和暖如春镀层,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背皿曲。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工唱逢, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人屋休。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓坞古,卻偏偏與公主長得像,于是被迫代替她去往敵國和親劫樟。 傳聞我的和親對象是個殘疾皇子痪枫,可洞房花燭夜當晚...
    茶點故事閱讀 43,472評論 2 348