成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

阮一峰:讀懂ECMAScript規格

移動開發
規格文件(specification)是計算機語言的官方標準,詳細描述語法規則和實現方法。

一、概述

規格文件(specification)是計算機語言的官方標準,詳細描述語法規則和實現方法。

[[155984]]

一般來說,沒有必要閱讀規格,除非你要寫編譯器。因為規格寫得非常抽象和精煉,又缺乏實例,不容易理解,而且對于解決實際的應用問題,幫助不大。但是,如果你遇到疑難的語法問題,實在找不到答案,這時可以去查看規格文件,了解語言標準是怎么說的。規格是解決問題的"***一招"。

這對JavaScript語言很有必要。因為它的使用場景復雜,語法規則不統一,例外很多,各種運行環境的行為不一致,導致奇怪的語法問題層出不窮,任何語法書都不可能囊括所有情況。查看規格,不失為一種解決語法問題的最可靠、最權威的***方法。

本文介紹如何讀懂ECMAScript 6的規格文件。

ECMAScript 6的規格,可以在ECMA國際標準組織的官方網站(www.ecma-international.org/ecma-262/6.0/)免費下載和在線閱讀。

這個規格文件相當龐大,一共有26章,A4打印的話,足足有545頁。它的特點就是規定得非常細致,每一個語法行為、每一個函數的實現都做了詳盡的清晰的描述。基本上,編譯器作者只要把每一步翻譯成代碼就可以了。這很大程度上,保證了所有ES6實現都有一致的行為。

ECMAScript 6規格的26章之中,第1章到第3章是對文件本身的介紹,與語言關系不大。第4章是對這門語言總體設計的描述,有興趣的讀者可以讀一下。第5章到第8章是語言宏觀層面的描述。第5章是規格的名詞解釋和寫法的介紹,第6章介紹數據類型,第7章介紹語言內部用到的抽象操作,第8章介紹代碼如何運行。第9章到第26章介紹具體的語法。

對于一般用戶來說,除了第4章,其他章節都涉及某一方面的細節,不用通讀,只要在用到的時候,查閱相關章節即可。下面通過一些例子,介紹如何使用這份規格。

二、相等運算符

先來看這個例子,請問下面表達式的值是多少。

 

  1. 0 == null  

如果你不確定答案,或者想知道語言內部怎么處理,就可以去查看規格,7.2.12小節是對相等運算符(==)的描述。

規格對每一種語法行為的描述,都分成兩部分:先是總體的行為描述,然后是實現的算法細節。相等運算符的總體描述,只有一句話。

  "The comparison x == y, where x and y are values, producestrue or false."

上面這句話的意思是,相等運算符用于比較兩個值,返回true或false。

下面是算法細節。

 
  1. ReturnIfAbrupt(x).
  2. ReturnIfAbrupt(y).
  3. If Type(x) is the same as Type(y), then 
    Return the result of performing Strict Equality Comparison x === y.
  4. If x is null and y is undefined, return true.
  5. If x is undefined and y is null, return true.
  6. If Type(x) is Number and Type(y) is String, 
    return the result of the comparison x == ToNumber(y).
  7. If Type(x) is String and Type(y) is Number, 
    return the result of the comparison ToNumber(x) == y.
  8. If Type(x) is Boolean, return the result of the comparison ToNumber(x) == y.
  9. If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
  10. If Type(x) is either String, Number, or Symbol andType(y) is Object, then 
    return the result of the comparison x == ToPrimitive(y).
  11. If Type(x) is Object and Type(y) is either String, Number, or Symbol, then 
    return the result of the comparison ToPrimitive(x) == y.
  12. Return false.

上面這段算法,一共有12步,翻譯如下。

  1. 如果x不是正常值(比如拋出一個錯誤),中斷執行。
  2. 如果y不是正常值,中斷執行。
  3. 如果Type(x)與Type(y)相同,執行嚴格相等運算x === y。
  4. 如果x是null,y是undefined,返回true。
  5. 如果x是undefined,y是null,返回true。
  6. 如果Type(x)是數值,Type(y)是字符串,返回x == ToNumber(y)的結果。
  7. 如果Type(x)是字符串,Type(y)是數值,返回ToNumber(x) == y的結果。
  8. 如果Type(x)是布爾值,返回ToNumber(x) == y的結果。
  9. 如果Type(y)是布爾值,返回x == ToNumber(y)的結果。
  10. 如果Type(x)是字符串或數值或Symbol值,Type(y)是對象,返回x == ToPrimitive(y)的結果。
  11. 如果Type(x)是對象,Type(y)是字符串或數值或Symbol值,返回ToPrimitive(x) == y的結果。
  12. 返回false。

由于0的類型是數值,null的類型是Null(這是規格4.3.13小節的規定,是內部Type運算的結果,跟typeof運算符無關)。因此上面的前11步都得不到結果,要到第12步才能得到false。

  1. 0 == null // false 

三、數組的空位

下面再看另一個例子。

  1. const a1 = [undefined, undefined, undefined]; 
  2. const a2 = [, , ,]; 
  3.  
  4. a1.length // 3 
  5. a2.length // 3 
  6.  
  7. a1[0// undefined 
  8. a2[0// undefined 
  9.  
  10. a1[0] === a2[0// true 

上面代碼中,數組a1的成員是三個undefined,數組a2的成員是三個空位。這兩個數組很相似,長度都是3,每個位置的成員讀取出來都是undefined。

但是,它們實際上存在重大差異。

0 in a1 // true
0 in a2 // false

a1.hasOwnProperty(0) // true
a2.hasOwnProperty(0) // false

Object.keys(a1) // ["0", "1", "2"]
Object.keys(a2) // []

a1.map(n => 1) // [1, 1, 1]
a2.map(n => 1) // [, , ,]

上面代碼一共列出了四種運算,數組a1和a2的結果都不一樣。前三種運算(in運算符、數組的hasOwnProperty方法、Object.keys方法)都說明,數組a2取不到屬性名。***一種運算(數組的map方法)說明,數組a2沒有發生遍歷。

為什么a1與a2成員的行為不一致?數組的成員是undefined或空位,到底有什么不同?

規格的12.2.5小節《數組的初始化》給出了答案。

"Array elements may be elided at the beginning, middle or end of the element list. Whenever a comma in the element list is not preceded by an AssignmentExpression (i.e., a comma at the beginning or after another comma), the missing array element contributes to the length of the Array and increases the index of subsequent elements. Elided array elements are not defined. If an element is elided at the end of an array, that element does not contribute to the length of the Array."

翻譯如下。

  "數組成員可以省略。只要逗號前面沒有任何表達式,數組的length屬性就會加1,并且相應增加其后成員的位置索引。被省略的成員不會被定義。如果被省略的成員是數組***一個成員,則不會導致數組length屬性增加。"

上面的規格說得很清楚,數組的空位會反映在length屬性,也就是說空位有自己的位置,但是這個位置的值是未定義,即這個值是不存在的。如果一定要讀取,結果就是undefined(因為undefined在JavaScript語言中表示不存在)。

這就解釋了為什么in運算符、數組的hasOwnProperty方法、Object.keys方法,都取不到空位的屬性名。因為這個屬性名根本就不存在,規格里面沒說要為空位分配屬性名(位置索引),只說要為下一個元素的位置索引加1。

至于為什么數組的map方法會跳過空位,請看下一節。

四、數組的map方法

規格的22.1.3.15小節定義了數組的map方法。該小節先是總體描述map方法的行為,里面沒有提到數組空位。

后面的算法描述是這樣的。

  1. Let O be ToObject(this value).
  2. ReturnIfAbrupt(O).
  3. Let len be ToLength(Get(O, "length")).
  4. ReturnIfAbrupt(len).
  5. If IsCallable(callbackfn) is false, throw a TypeError exception.
  6. If thisArg was supplied, let T be thisArg; else let Tbe undefined.
  7. Let A be ArraySpeciesCreate(O, len).
  8. ReturnIfAbrupt(A).
  9. Let k be 0.
  10. Repeat, while k < len 
    a. Let Pk be ToString(k). 
    b. Let kPresent be HasProperty(O, Pk). 
    c. ReturnIfAbrupt(kPresent). 
    d. If kPresent is true, then 
    d-1. Let kValue be Get(O, Pk). 
    d-2. ReturnIfAbrupt(kValue). 
    d-3. Let mappedValue be Call(callbackfn, T, «kValue, k, O»). 
    d-4. ReturnIfAbrupt(mappedValue). 
    d-5. Let status be CreateDataPropertyOrThrow (A, Pk, mappedValue). 
    d-6. ReturnIfAbrupt(status). 
    e. Increase k by 1.
  11. Return A.

翻譯如下。

  1. 得到當前數組的this對象
  2. 如果報錯就返回
  3. 求出當前數組的length屬性
  4. 如果報錯就返回
  5. 如果map方法的參數callbackfn不可執行,就報錯
  6. 如果map方法的參數之中,指定了this,就讓T等于該參數,否則T為undefined
  7. 生成一個新的數組A,跟當前數組的length屬性保持一致
  8. 如果報錯就返回
  9. 設定k等于0
  10. 只要k小于當前數組的length屬性,就重復下面步驟 
    a. 設定Pk等于ToString(k),即將K轉為字符串 
    b. 設定kPresent等于HasProperty(O, Pk),即求當前數組有沒有指定屬性 
    c. 如果報錯就返回 
    d. 如果kPresent等于true,則進行下面步驟 
    d-1. 設定kValue等于Get(O, Pk),取出當前數組的指定屬性 
    d-2. 如果報錯就返回 
    d-3. 設定mappedValue等于Call(callbackfn, T, «kValue, k, O»),即執行回調函數 
    d-4. 如果報錯就返回 
    d-5. 設定status等于CreateDataPropertyOrThrow (A, Pk, mappedValue),即將回調函數的值放入A數組的指定位置 
    d-6. 如果報錯就返回 
    e. k增加1
  11. 返回A

仔細查看上面的算法,可以發現,當處理一個全是空位的數組時,前面步驟都沒有問題。進入第10步的b時,kpresent會報錯,因為空位對應的屬性名,對于數組來說是不存在的,因此就會返回,不會進行后面的步驟。

  1. const arr = [, , ,]; 
  2. arr.map(n => { 
  3.   console.log(n); 
  4.   return 1
  5. }) // [, , ,] 

上面代碼中,arr是一個全是空位的數組,map方法遍歷成員時,發現是空位,就直接跳過,不會進入回調函數。因此,回調函數里面的console.log語句根本不會執行,整個map方法返回一個全是空位的新數組。

V8引擎對map方法的實現如下,可以看到跟規格的算法描述完全一致。

責任編輯:倪明 來源: 阮一峰的技術博客
相關推薦

2011-12-05 10:44:38

inodeLinux文件系統

2015-09-06 10:34:54

蒙特卡洛阮一峰

2015-09-17 15:23:56

阮一峰網頁性能

2012-11-15 09:43:08

開發算法高斯模糊

2015-11-02 19:11:27

阮一峰javascript循環加載

2015-10-08 08:44:23

阮一峰Github清點對象

2015-09-24 09:43:08

阮一峰持續集成

2015-09-18 15:21:33

求職就業創業阮一峰

2020-11-20 08:41:19

ES6

2015-09-29 08:51:59

內存地址主引導

2025-04-16 00:00:02

2023-12-22 19:59:15

2021-08-04 16:06:45

DataOps智領云

2011-06-21 14:42:37

ECMAScriptJavaScript

2021-12-16 06:52:33

Flex屬性布局

2024-06-28 11:39:21

2023-11-27 17:35:48

ComponentWeb外層

2023-05-20 17:58:31

低代碼軟件

2022-07-05 06:30:54

云網絡網絡云原生

2022-07-26 00:00:03

語言模型人工智能
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 91干b| а_天堂中文最新版地址 | 国产高清免费 | 精品久久久久久一区二区 | 日韩av成人| 久久99精品久久久久久狂牛 | 久久精品久久久久久 | 求个av网址| 国产精品中文在线 | 国产免费福利小视频 | 欧美老少妇一级特黄一片 | 欧美日韩成人在线 | 日韩欧美精品一区 | 特黄视频 | 国产成年人小视频 | 亚洲欧美日韩高清 | 激情的网站 | 国内精品在线视频 | 欧美综合久久久 | 日韩一区欧美一区 | 国产精品久久久久久久久久妞妞 | 风间由美一区二区三区在线观看 | 亚洲国产成人av | 精区3d动漫一品二品精区 | 草草草网站 | 日韩视频免费看 | 欧美4p | 蜜桃视频在线观看www社区 | 国产一区二区美女 | 91国在线 | 97伦理 | 久在线视频播放免费视频 | 欧美精品在线观看 | 91国自产 | 一区二区三区国产好 | 欧美视频精品 | 精品国产一区二区三区在线观看 | 99精品视频免费观看 | 久在线 | 伊人久久成人 | 中文字幕一区二区三区四区五区 |