版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
JavaScript发展史目录01语言诞生02标准建立与命名03统一与未来语言诞生01030201图形化浏览器问世NCSAMosaic-1993第一个被广泛使用的图形化浏览器,它可以显示图片并与文本内联,这使得网页变得生动有趣。Mosaic极大地推动了互联网的普及,被认为是引发第一次互联网热潮的关键软件。Netscape-1994
在Mosaic的基础上迅速崛起,成为1990年代中期占主导地位的商业浏览器。它引入了许多新特性,并奠定了早期网页的标准。InternetExplorer-1995为了与Netscape竞争,微软开发了IE,并将其与Windows操作系统捆绑销售。这一策略导致了著名的“第一次浏览器大战”。IE最终击败Netscape,成为市场垄断者。JavaScript之父——BrendanEichBrendanEich曾任Mozilla公司的CEO,也是Mozilla项目和基金会的创始人。在此期间,他协助推出了Firefox浏览器,同时作为JavaScript的发明者被广为人知。JavaScript1.0值/名字/字面量函数表达式与运算符内置对象语句内核对象模型JavaScript1.1JavaScript1.1的改动并不大,主要体现在了增加Array、escape等内置对象或函数上。JavaScript1.2JavaScript1.2增加了少量数组方法(concat、slice等)以及大量的字符串方法(concat、search、match、charCodeAt)。并丰富了语句(switch、do-while)。标准建立与命名02ECMAScript2和ECMAScript3ECMAScript2ECMAScript2是建立现代规范的原型,它就语言的标准化过程,一致性测试等方面形成了统一。但语言自身并未引入重大变更。ECMAScript3其内容基于JavaScript1.2完成。它不但新增了一些特性(try-catch-finally、Error等),也废弃了一些不再适合的内容(substr()等),但为了保持Web兼容性,这些特性仍被浏览器支持。ECMAScript4与ECMAScript3.1修订版草案ECMAScript4ECMAScript4代表了JavaScript标准发展中的一次大胆尝试,它包含了众多新特性和改进方案。不过,由于各方意见分歧,它最终未被正式采用,但为后续版本的发展提供了很多思路。ECMAScript3.1修订版草案ECMAScript3.1修订版草案是在ECMAScript3基础上进行的修订尝试。它对一些特性进行了优化和改进,是标准不断完善过程中的一个过渡阶段,对JavaScript的标准化进程有一定推动作用。严格模式与OneJS严格模式严格模式是JavaScript中的一种特殊运行模式,它对代码的编写提出了更严格的要求。通过开启严格模式,可以避免一些常见的错误,提高代码的质量和安全性,使代码更符合规范。OneJSOneJS主张拒绝创建任何方言子集,推动语言整体优化。这种理念有效的阻止了语言的再次分裂。JavaScript<scriptl=1.0><scriptl=2.0>strict<scriptl=1.0>strictstrictOnejs统一与未来章节副标题03更完善的提案制度倡导者模型保证了有效的问题领域被提出并避免浪费委员会的时间。分阶段的提案制度保证了问题的有序进展,最大可能的避免了阶段回退的情况发生。向前兼容的关键字向前兼容的关键字是保障JavaScript持续发展的关键。通过对关键字进行兼容性设计,使得新的代码能够与旧版本的代码相互兼容,避免了因版本更新而带来的代码不兼容问题。语义完善通过引入早期错误(静态语义)来规避可能存在的语法错误,也为代码编辑器提供语法检测提供了有效支持。简化概念重新梳理规范中的概念。例如,对象的分类将聚焦于对象的行为,而非创建方式,有助于语言设计者对特性进行归纳和分析。快速发展ECMAScript采用年度发布为周期推出大量的新特性,这意味着语言会紧跟社区的需求不断演进。社区沟通社区沟通对于JavaScript的发展至关重要,开发者可以通过Github、Discourse等平台交流经验。规范性公约1.避免将参数强制为布尔值以外的类型。
2.当缺少必需的参数时应抛出错误。
3.期待非NaN参数的内置函数应明确拒绝NaN。4.期待整数参数的内置函数应明确拒绝非整数参数。规范性公约是指在未来的设计向上应该遵守的一些约定,这些约定往往由实践及经验总结而成。谢谢ThankyouJavaScript类型系统CONTENTS目录String类型BooleanSymbol类型类型转换数值Undefined和Null类型类型检测不同类型的相等性测试0305070204060801String类型01
String01字符串编码多进制表示方式代码点转换规则计算JavaScript字符串中的符号数量结构良好的字符串结构良好的JSON.stringify020304050607字符串的归一化模板字符串标签函数字符串方法080910String类型StringString(字符串)类型是由零个或多个16位无符号整数值(元素)组成的所有有序序列的集合。在这种情况下,字符串中的每个元素都被视为UTF-16代码单元值,这些位置用非负整数索引表示,并用length属性获取。特殊字符的length常见的字符表情,组合字符往往拥有不同的length属性,即使它们看上去只是一个字符。字符串编码
ECMAScript是JavaScript的标准化规范,其规定ECMAScript的一致性实现必须根据新版本的Unicode标准和ISO/IEC10646(网址详见前言二维码)解释源文本输入,字符串这种数据类型也遵循此规则。JavaScript字符串在规范上使用UTF-16编码,但出于主机兼容性考虑等原因,它也可能保留早期UCS-2的历史行为。UCS-2可以对Unicode版本3.0指令表中定义的所有(16位)字符进行编码。然而,对于从Unicode版本3.1开始引入的每个新补充的字符进行编码则必须采用两个16位字符。这些补充字符在原始的16位“基本多语言平面”外部定义。这也是UTF-16诞生的意义,它是对UCS-2的扩展,允许成对使用以表示BMP之外的代码点。对于可以采用16位编码的字符(U+0000~U+FFFF),这两种编码实际上是一样的。第一个平面(U+0000→U+FFFF)称为基本多语言平面(BasicMultilingualPlane,简称BMP),它包含65536个代码点,是最重要的平面,因为它包含所有最常用的编码,并在UTF-16编码中作为单个代码单元进行访问。此外,剩余的15个平面也给我们留下了大约100万个可用的代码点,这些代码点所属的平面称为辅助平面(SupplementaryPlanes),并作为UTF-16中的代理对进行访问。多进制表示方式十六进制转义序列由两个十六进制数字组成,用于表示U+0000到U+00FF范围内的Unicode代码点。Unicode转义序列由4个代表代码点的十六进制数字组成。这些转义序列可用于表示整个BMP,但是却无法很好的表示其他平面的字符。代码点转义代码点转义允许在大括号之间最多使用六个十六进制数字,这种形式足以表示所有Unicode代码点。兼容ECMAScript5的代理对为了向后兼容ECMAScript5和旧环境,也可以使用效果等同的代理对表示补充字符。代码点转换规则
解释字符串值的操作将每个元素视为单个UTF-16代码单元,并且对每个包含范围0xD800到0xDBFF的代码单元以及包含范围0xDC00到0xDFFF的代码单元使用以下规则进行特殊处理:(1)作为前导代理或尾随代理但不属于代理对的代码单元,将被解释为具有相同值的代码点。(2)一种由两个代码单元组成的序列,其中第一个代码单元c1是前导代理,第二个代码单元c2是一个尾随代理项,它被解释为一个码点。代理对转换代码点一个正确的代理对可通过公式:(高代理-0xD800)*0x400+低代理-0xDC00+0x10000转换为一个代码点。代码点转换代理对同样的,我们6也可以反向将代码点转换为代理对,公式如下:高代理=Math.floor((codePoint-0x10000)/0x400)+0xD800低代理=(codePoint-0x10000)%0x400+0xDC00计算JavaScript字符串中的符号数量在讨论字符的长度时,最重要的是要认识到,通常用户讨论的字符(character,语言书写系统的基本单位)可能不是由单个Unicode代码点组成。如果我们使用转义序列来表示符号,显然仅需要为每个符号进行一次转义。然而,由于代理对的存在,事情就会变得复杂。若仅使用与ECMAScript5兼容的转义序列来表示符号,每个补充字符则需要两次转义。为了更好的计算符号的数量,可以使用正则表达式匹配补充字符,也可以使用ES6提供的基于迭代器的方法。结构良好的字符串开发者需要使用格式正确的Unicode文本格式创建数据,以便在各种接口协议中有效的工作,这在前后端数据交互时十分常用。为此,ES2024为开发者在Stotype上提供了两个全新API:isWellFormed()和toWellFormed()。顾名思义,前者用于检测目标是否良构,后者用于将所有未匹配代理项替换为专用的Unicode替换字符U+FFFD。结构良好的JSON.stringify在ECMAScript2019前,如果为JSON.stringify()方法传入任何包含单独的代理项,则会返回格式错误的Unicode字符串。Well-formedJSON.stringify提案更改了这一行为,它使用JSON转义序列表示它们。结构良好的JSON.stringify结构良好的字符串归一化是指将字符串中的所有字符都转换为它们的标准形式,以便在比较和处理字符串时能够得到正确的结果。因此,字符串的归一化是我们必须要重视的问题。支持归一化的API方法normalize()可用于显式归一化字符串值,接受一个参数以指定normalize的方式,可选参数如下所示:(1)NFC,默认参数,表示“标准等价合成”(NormalizationFormCanonicalComposition),返回多个简单字符的合成字符。所谓“标准等价”指的是视觉和语义上的等价。(2)NFD,表示“标准等价分解”(NormalizationFormCanonicalDecomposition),即在标准等价的前提下,返回合成字符分解的多个简单字符。(3)NFKC,表示“兼容等价合成”(NormalizationFormCompatibilityComposition),返回合成字符。所谓“兼容等价”指的是语义上存在等价,但视觉上不等价,比如上文中出现的多种“é”。(4)NFKD,表示“兼容等价分解”(NormalizationFormCompatibilityDecomposition),即在兼容等价的前提下,返回合成字符分解的多个简单字符。JavaScript使用反引号(`)创建模板字面量,为生成和查询其他语言内容的领域特定语言(DSL)提供了一种安全且高效的方式,这使得该特性一出现就受到开发者的青睐。严格来讲,模板字符串并不是单纯的字符串,而是包含特殊执行结构的JavaScript表达式。模板字符串中的变量会在定义后从其作用域中提取并求值,进而将整个模板字符串转换为字符串实例。在规范中,模板字符串的评估与函数的参数评估被视为一类,但与函数参数列表评估不同的是,模板字符串是一种罕见的可以在求值字符串时进行评估的结构体。模板字符串总是与当前域中的一个模板对象关联,并且这个模板对象是被冻结的。因此,在后续评估相同形式的模板时可以进行复用。如下图所示:标签函数模板字符串的另一个用途是借助标签函数来实现自定义插值行为。标签函数使用不定参数来定义,第一个参数是字符串字面量组成的数组,其余参数则是每一个占位符替换后的值。有趣的是,每一个占位符周围都必定会产生一个字符串字面量。第一个参数除了字面量信息外,还具有一个包含了原生字符串信息的raw属性,开发者也可使用String.raw()方法来获取包含嵌入值的等价原生字符串信息。字符串方法元素查找与匹配JavaScript提供了大量的字符串查找方法,ES5时期,indexOf()等方法常被用于检测一段字符串中是否包含另一段字符串,并返回子串出现的位置。但在大多数时候,我们并不需要知道确切位置。ES6引入的String#includes()方法可以直接判断是否包含特定字串。String#startsWith()/String#endsWith()方法还提供了首尾匹配的直接方式。字符串原始表示String.raw()方法可以访问字符的原始表示形式而不处理任何的转义序列,在大多数情况下,它与模板字符串同时出现。除此之外,该方法还用于减少转义,这在构建正则表达式时尤为有用字符串方法字符串填充String#padStart()/String#padEnd()方法允许你在字符串的开头或末尾填充其他字符。这两个方法的第一个参数指定了填充字符的长度,第二个参数为填充的内容。当填充内容为undefined时其结果将等同于空格,而填充null则会将其转换为字符串字面量。代码点转换为符号String.fromCharCode()方法允许创建基于Unicode代码点的字符串,但它仅适用于BMP范围内的代码点(即从U+0000到U+FFFF)。ECMAScript6引入了String.fromCodePoint()方法以弥补String.fromCharCode()方法不适用于BMP范围外字符的问题。字符串方法索引获取字符串中的代码单元早期的JavaScript使用charAt()和charCodeAt()方法获取参数索引位置的字符,但这两种方法无法很好地处理代码点大于0xFFFF的字符,而且会在超出索引范围时返回空字符串或NaN。ECMAScript2022中为我们提供了更加简洁的at()方法来搜索代码单元。该方法支持负数索引,在找不到指定索引的时候会返回undefined而不是空字符串('')。从字符中获取代码单元和代码点at()方法并未解决补充字符的检索问题,ECMAScript6引入了codePointAt()方法以更好的支持代理对,它同时也保留了at()方法修正的部分行为。数值02
数值01NumberBigInt类型数值字面量的表示数值的比较数值的转换数值分隔符020304050607数值与安全精确求和08NumberNumber类型用于表示整数和近似实数,它是基于64位双精度浮点数类型实现的。Number类型具有18,437,736,874,454,810,627(即264-253+3)个值,表示IEEE二进制浮点运算标准中指定的双精度64位格式的值。其中包含三个特殊值:NaN,Infinity和-Infinity。NumberNaNIEEE标准的不同“Not-a-Number”值在ECMAScript中表示为单个特殊NaN值,它用于在本应返回数字的操作中产生了错误时,替代抛出错误的情况。犹豫期与自身不等的特性,建议开发者使用Number.NaN和Number.isNaN()方法代替NaN和isNaN()方法。整数在JavaScript中,整数与浮点数的界限并不那么清晰。对于可以表示为整数的浮点数会被认为是整数,此外,精度限制也可能影响判断结果。因此无法仅从字面量表示上通过点和零进行判断。为此,你可以使用Number.isInteger()方法。BigIntBigInt是ECMAScript2020引入的一种用于处理任意精度整数的数值原始类型,你可以使用BigInt()函数调用,也可以直接使用字面量形式(添加后缀n)进行创建。考虑到Number类型与BigInt类型的混合操作会丢失信息,因此这类操作被禁止。在两种类型参与的计算中,必须显式的转换其中一个类型,并且在从Number到BigInt的转换过程中添加了更多的限制。数值字面量的表示与Number类型一样,BigInt类型也是支持多进制(二进制,八进制和十六进制)字面量表示法的,不过它摒弃了一些存在于Number类型中的遗留语法,在表达上更为严格。需要注意的是,BigInt类型数据是不支持科学记数法和隐式八进制的。数值的比较数值类型之间的大小比较是基于数学值(Mathematicalvalue)的,即使出现两种不同类型同时出现的情况,也会遵循着良好的数学定义。唯一需要注意的是,有NaN参与比较的运算永远返回false。不过,数值之间相等性比较的过程要繁琐得多(这里不强调类型),它们基于多种策略:(1)当出现一个Number类型和一个BigInt类型时会比较他们的数学值是否相等。(2)当两个操作数同为Number类型时应用Number::equal抽象操作。该操作不区分0与-0并认为NaN不与自身相等,由==、===、!=和!==使用。(3)当两个操作数同为BigInt类型时应用BigInt::equal抽象操作。由于此类型中没有-0和NaN,比较会更加纯粹。此外,规范中为Number类型扩展了Number::sameValue和Number::sameValueZero算法,这两种算法同时修复了NaN不与自身相等的问题,唯一的区别是前者将0与-0视为不同,而后者则视为相同。数值的转换Number类型和BigInt类型的转换本质上是双精度浮点数和一个整数的互操作性问题,为了表达明确意图,不同类型数值之间的转换操作应该总是显式的。NumberToBigInt(number)抽象操作定义从Number类型转换到BigInt类型的算法过程:(1)如果被转换的操作数number不是一个整数,则抛出RangeError错误。(2)将number转换为数学值后再转换为BigInt类型。Number类型转换到BigInt类型的类型转换则与之相反,它先获取BigInt的数学值再转换为Number类型。数值分隔符为了更好的书写数值字面量,JavaScript允许对数值类型使用分隔符,且应用规则相对宽松,大致遵循以下几条原则:(1)分隔符出现的位置不能是数字字面量末尾,且不能位于前导0后。(2)不允许与小数点相邻,甚至没有规定间隔的位数。(3)不能出现连续的分隔符。(4)不可跟随在表示进制的字母后面。数值与安全Math.random()方法使用伪随机算法,此类算法往往基于高效的数学算法。不过,由于其不提供加密安全的随机数,应用中可使用具有足够熵的种子来创建随机数的crypto.getRandomValues()方法。最后需要注意的是,虽然BigInt提供了更大的精度支持,但由于其操作不是恒定时间,所以开发者不应该将其直接应用于密码学领域。精确求和当前,众多的求和计算实现都是基于Array#reduce()(归约)方法实现的,但这种方法不够便捷。Math.sumPrecise提案给出了一种比简单求和更精确的算法,用于返回可迭代对象中值的总和。Boolean03Boolean类型布尔类型在JavaScript中只有两个值,即true和false。它常用于条件判断语句中,根据布尔值的真假来决定程序的执行流程,是控制程序逻辑的重要基础。在JavaScript中仅有8个假(falsy)值,其余的都是真(truth)值,其中包括:false、0、-0、0n、''、undefined、null和NaNUndefined类型和Null类型04Undefined类型和Null类型Undefined类型undefined代表了一个未定义的值。undefined的出现是为了区别于null,用来标识一个未初始化的变量。尽管这是最恰当的理解方式,但在typeof操作符的作用下,一个标识符是否可以解析变得扑朔迷离。因为在JavaScript这门语言中,使用typeof检测未解析的引用的返回值也是undefined。Null类型null代表了空值,使用typeof操作符检测会得到一个“object”。这种设计或许源自Java,在Java中声明一个对象变量时,其默认值为null,以此代表不引用任何对象。因此在JavaScript中你也可以使其作为对象变量的初始值。空值判断的演进&&操作符ES5时期使用&&操作符来验证一个属性是否为空值,其结果是任何假值都会被判定为空值。可选链运算符为了解决属性验证的繁琐问题,ES6引入了可选链运算符(?.)。它避免了重复访问自身和创建多个中间变量的麻烦,同时将空值的范围缩小为了undefined和null。空值合并运算符ES2020引入了空值合并运算符(nullcoalescingoperator),它在空值判定的基础上提供了默认赋值的功能。支持私有属性&&参数及解构默认值中的空值判定支持私有属性的可选链对于私有属性,可选链运算符仍然支持短路操作。虽然私有属性的访问语法与一般属性相同,但却脱离了对象基本内部操作。参数及解构中的空值判定尽管undefined和null一直被开发者混用,但ES6后出现的一些新特性却有意将这两个值加以区分。参数默认值及解构默认值的语义仅当属性不存在或属性的值为undefined时,才会被视为无值并使用默认值。Symbol类型05Symbol类型Symbol类型Symbol是ES6新增的一种原始类型数据,主要用于生成唯一的值。创建该类型值的方式是使用Symbol()函数并传入一个描述值。Symbol属性检索与对象的设计相同,Symbol也提供了获取符号列表的方法:Object.getOwnPropertySymbols()Object.getOwnPropertyDescriptors()Reflect.ownKeys()Symbol共享体系为了在不同的代码中共享一个Symbol,ES6提供了一个全局Symbol注册表,可以在全局范围内共享和重用符号实例。开发者可通过Symbol.for()方法在注册表中创建或获取Symbol。Well-knownSymbolsSymbol类型的另一个主要用途就是提供扩展语言的机制。ES6通过使用预定义的Symbol属性定义了一组Well-knownSymbols(公认符号)。得益于该数据类型的好处,它不会与任何已有代码产生冲突。这些符号与语言内置的一种行为或机制相关联,并将这种行为暴露给开发者。你可以通过重置这些方法改变语言的现有行为,却不可过度使用造成行为的混乱。
Symbol.hasInstanceinstanceof的既定逻辑是查询右侧操作数的prototype属性是否出现在左侧操作数的原型链中。而当右侧操作数拥有Symbol.hasInstance属性时,则会将上述的查找过程委托给该方法。
Symbol.isConcatSpreadableSymbol.isConcatSpreadable属性用于控制数组拼接时的行为,该属性时一个布尔值。当该值为true时,在使用concat()方法时将展开数组和类数组对象。Well-knownSymbols
Symbol.speciesSymbol.species属性用于为创建派生对象时指定构造方式,其返回值为创建实例对象的构造函数(类)。需要注意的是,这一属性并不总是在运行时触发,一般来讲,他们多被安装于重新生成实例的原型方法上。
Symbol.toStringTag为了更好地扩展对象类别,引入了Symbol.toStringTag用于自定义类别标签返回,该属性由toString()触发。Well-knownSymbols
Symbol.unscopablesSymbol.unscopables属性的值是一个对象,该对象及其继承的属性将在with环境中无法访问
Symbol.matchSymbol.match属性用于定义字符匹配的逻辑,其值是一个函数。String#match()方法在其第一个参数上查找此符号,以确定输入字符串与当前对象进行匹配的方式Well-knownSymbols
Symbol.matchAllSymbol.matchAll属性是Symbol.match的全局匹配版本,并返回一个包含结果的迭代器。除此之外,二者大致相同。
Symbol.split、Symbol.replace和Symbol.searchSymbol.split、Symbol.replace和Symbol.search是字符串方法split()、replace()和search()方法的行为委托机制,可以更好地描述匹配过程。Well-knownSymbols
Symbol.toPrimitive通过定义Symbol.toPrimitive属性,我们能够覆盖对象类型到原始值的默认转换过程。规范中定义了一个ToPrimitive抽象方法处理这一转换过程,该抽象方法接收一个可选的首选类型(preferredType)参数。若对象在没有定义Symbol.toPrimitive属性且没有传递首选类型参数的情况下,会默认采用偏数值算法,这一过程的更多细节可参考2.7节类型转换。Well-knownSymbols
Symbol.matchAllSymbol.iterator是用作返回对象默认迭代器的属性,并由for-of语句的语义调用。通过在任意对象上定义该属性,可使该对象变得可迭代。
Symbol.asyncIteratorSymbol.asyncIterator是Symbol.iterator的异步版本,并由for-await-of语句的语义调用。Well-knownSymbols类型检测06typeof是如何识别类型的在JavaScript中,typeof操作符作为语言早期提供的类型检测工具,仅对原始类型数据提供可靠及直观的效果,这是由其底层实现机制决定的。在算法执行过程中,typeof操作符首先会对一元表达式(UnaryExpression)求值,并将该值记录为val,再执行以下步骤:(1)如果val是一个引用记录类型(ECMAScript规范类型,指对环境记录中的变量绑定的引用),并且不能成功解析,则返回“undefined”。(2)得到引用记录的值,重新赋值给val。(3)undefined和null分别对应为“undefined”和“object”。(4)对于String、Symbol、Boolean、Number和BigInt类型,分别返回:“string”、“symbol”、“boolean”、“number”和“bigInt”。(5)如果val具有[[call]]内部槽,则值的类型为“function”。(6)其他情况下,值为“object”。Ototype.toString()为了扩展新引入的类型,底层通过Symbol.toStringTag规范了类型标签检测机制,并由Object#toString()方法体现。其大致过程如下:(1)对于undefined/null,直接返回“[objectUndefined]”/“[objectNull]”。(2)将this值转为对象。(3)判断其是否为数组,是则令builtinTag为“Array”。(4)检测其是否包含特定的内部槽,并设置builtinTag为相应的值。如果不满足该条件,则设置builtinTag为“Object”。(5)如果具有Symbol.toStringTag属性并返回一个字符串,则将该值作为tag,否则使用builtinTag作为tag的值。(6)拼接字符串:"[object"+tag+"]",并返回。例如代码:品牌检查品牌检查(BrandCheck)是TC39中的一个术语,用于描述针对唯一数据类型的检查,这些品牌往往由特定构造器逻辑创建。通过检测对象是否具有特定的内部插槽(用于存储JavaScript对象的状态),实际上这与内置私有字段相同,常用于读/写的前置操作。鉴于这种理念,在ES6的内置函数的原型方法或静态方法中都以各种方式进行品牌检查。例如,Map#get()方法会使用RequireInternalSlot抽象操作检查是否具有[[MapData]],以此来判定正在处理的对象是否是Map对象,这在原型方法上很常见。品牌检查并不是新概念,Object#toString()方法是在早期加入的品牌检查操作之一,这种遗留用法用于检测一个对象是否是ES5中的对象(包括"Function"、"Array"、"RegExp","Date"等)。类型转换07类型转换早期的JavaScript不具备抛出错误的能力,在处理不同数据类型间的操作时非常灵活,以此避免错误的产生。首先需要明确的是,不同类型之间往往是不具备操作性的,这意味着转换发生的必然性。学习隐式转换规则就是在理解操作的目标类型。在语言里,原始值到对象类型的隐式转换场景多出现于对象方法中,这些方法总是期望自己的目标是一个对象并由引擎默认完成转换,在现实代码中几乎不会有开发者显式转换的情况。原始类型到对象类型的规则很容易理解。在ES5时期,每种具有包装器的原始类型在转换对象时,最终都会尝试使用所对应的包装函数进行构造,以获得相应的对象,这与使用Object()方法进行转换结果相同。对象到原始类型的转换要相对复杂,这是因为对象类型往往有多种原始值表示。比如,Date对象可以用字符串表示,也可以用时间戳表示。另一个例子是,数组的值形态和字符串形态同样有用。ECMAScript规范定义了对象到原始值转换的3种基本算法。具体选择哪种则是由偏好类型(preferredType,在一些书中称其为首选类型)决定的:(1)偏好字符串类型:该算法会尽可能的返回字符串。(2)偏好数值类型:该算法会尽可能的返回数值。
(3)无偏好类型:由类定义自己的转换规则。不同类型的相等性测试08相等性转换JavaScript提供了宽松相等(==)和
严格相等(===)
两个操作符用于测试相等性。当参与比较的两个值同属于相同类型时,无论使用哪种操作符都会应用严格相等的检查语义。而对于不同类型的相等测试,总是遵循着上面的转换流程,最终转换为同一类型再进行比较。谢谢ThankyouJavaScript代码组织方式CONTENTS目录脚本模块脚本01脚本评估检查当引擎收到已经加载完毕的JavaScript脚本(Script)时,会首先对脚本进行解析。在对代码源文本进行解析时会检查是否存在早期错误。评估环境脚本中的源代码将在一个独立的环境中进行评估,这个环境包含了全局环境以及评估时所需的内置对象。全局声明初始化全局声明初始化(GlobalDeclarationInstantiation)是脚本评估的重要一环,它包含对全局声明标识符的注册过程,它接受两个参数:脚本记录和环境记录。字符串形式记录var声明全局声明初始化过程图示检查var声明记录函数声明于functionsToInitialize实例化lexDeclaration中的名字记录var声明于declaredVarNames之中使用undefined初始化declaredVarNames中的名字并建立全局绑定检查词法名字创建declaredVarNames初始化functionsToInitialize之中的函数声明并建立全局绑定字符串形式记录lexical声明分别处理检查var声明中不同类别的声明创建lexDeclarations并记录词法声明受限全局属性与词法遮蔽
受限全局属性是指在JavaScript中受到一定限制的全局属性。这些属性可能在使用上有特定的规则或条件,了解它们有助于开发者正确使用全局属性,避免出现意外的错误。模块02导出语法导出语法要求名字必须是唯一的,其中最常见的是命名导出(namedexport)语法。如果你需要对相同内容做不同导出可以使用后面介绍的导出重命名语法。命名导出语法默认导出语法使用“exportdefault”两个关键字,随后紧跟要导出的内容。在一个模块文件中,最多只能有一个默认导出。默认导出语法导入语法与导出语法相比,导入语法允许你从模块说明符中导入多种形式的绑定,其基本语法形式及示例如上图所示。除上图中描述的导入语法外,还可以使用import"specifer"导入一个具有副作用的模块,而非具体的绑定。这种方式可以应用于实际场景中的某些初始化工作,在Polyfill和Shim中尤为常见。
重命名导入导出WeakSet中的元素必须是引用类型或非注册的符号类型。它不允许存储原始类型值和null,因为这不仅毫无意义,也阻碍了垃圾回收机制的实现。WeakSet中引用的存在不会阻碍垃圾回收,也就是说,当WeakSet中的引用是唯一的引用时,该对象便符合了回收的条件。
间接绑定与模块隐私性详细描述:类具有自身独特的特点,这些特点在编程中有着重要意义。它可能包括封装性、继承性、多态性等,这些特点有助于提高代码的复用性、可扩展性和可维护性。模块命名空间对象
受限全局属性是指在JavaScript中受到一定限制的全局属性。这些属性可能在使用上有特定的规则或条件,了解它们有助于开发者正确使用全局属性,避免出现意外的错误。模块元数据模块需要访问其自身的元数据,其中包括使用(加载它的)加载器动态加载相对于它自身的其他模块的能力。在CJS中,开发者可以通过module和require来访问模块的元数据。而ESM则提供了import.meta元属性。脚本中的模块导入语法模块脚本(<scripttype="module">)旨在为JavaScript提供最简洁的代码组织(封装)设计,同时更清晰地区分脚本与模块。你可以在一个干净的作用域中开始代码编写,顶级声明的作用域限定于模块。除此之外,你还将获得隐式静态分析、严格模式以及内联源代码的优势。作为模块使用的<script>标签隐式的包含了一个defer属性,这使得模块及其依赖项的加载可以同HTML的解析同时进行,并延迟外联脚本的执行,如上图所示。导入和导出记录导入记录是对单个声明性导入的信息进行摘要的记录。每个导入记录都定义了以下字段:(1)[[ModuleRequest]]:导入声明中的模块说明符。(2)[[ImportName]]:由[[ModuleRequest]]标识的模块导出所需绑定的名称,对于命名空间对象来说这个名字是namespace-object。(3)[[LocalName]]:用于访问从导入模块中导入本地的导入值的名字。每种导入语法对应的记录内容如表所示。导入语法形式[[ModuleRequest]][[ImportName]][[LocalName]]importvfrom"mod";"mod""default""v"import*asnsfrom"mod";"mod"namespace-object"ns"import{x}from"mod";"mod""x""x"import{xasv}from"mod";"mod""x""v"import"mod";AnImportEntryRecordisnotcreated.导入和导出记录导出记录是对单个声明性导出的信息进行摘要的记录。每个导出记录都定义了以下字段:(1)[[ExportName]]:当前模块用于导出该绑定的名称,默认导出为“default”。(2)[[ModuleRequest]]:导出声明的模块说明符。如果导出声明没有模块说明符,则为null,否则用于重新导出的情况。(3)[[ImportName]]:由[[ModuleRequest]]标识的模块导出所需绑定的名称。如果导出声明没有模块说明符,则为null。All用于export*asnsfrom"mod"声明。All-but-default用于export*from"mod"的声明。(4)[[LocalName]]:用于从导入模块内部访问导出值的名称。如果无法从模块内访问导出的值,则为null。需要注意的是,使用as子句会导致该字段的内容与[[ExportName]]字段的内容不一致。每种导出语法对应的记录内容如表所示。导入语法形式[[ModuleRequest]][[ImportName]][[LocalName]]importvfrom"mod";"mod""default""v"import*asnsfrom"mod";"mod"namespace-object"ns"import{x}from"mod";"mod""x""x"import{xasv}from"mod";"mod""x""v"import"mod";AnImportEntryRecordisnotcreated.模块加载阶段(1)解析阶段:导入语句中的说明符相对于引用模块进行解析。在网络上,这使用URL解析或导入映射。(2)获取/编译阶段:从磁盘、网络或其他地方获取并编译已解析的说明符。(3)附加评估上下文阶段:加载的源被转换为具有身份的模块实例。(4)链接阶段:模块实例将所有静态导入链接到它。延迟模块(语句importdefer*asnsfrom"./test.js";)返回尚未评估的模块名称空间对象,该对象在首次使用时评估。(5)评估阶段。执行模块源代码,可以访问和使用链接的绑定。与CJS交互在ESM的生命周期中,代码在完全链接之前不会对其进行评估,这是因为所有的导入导出项都是可以静态分析得到的,模块之间的依赖关系会在执行前明确。然而,当与CommonJS交互时,必须能够提前执行一些代码。这是由于CommonJS模块的输出接口是module.exports,它是一个真真切切的对象,只能通过链接之后的评估阶段来确定内容。为了使ESM能够导入CommonJS模块,需要将CommonJS模块的评估提前到链接阶段(与ESM确定导出内容的时机保持一致),以此构建整个模块图,进而确保从转译器过渡到原生模块。使用CommonJS模块加载ESM就没那么轻松了。顶层await的出现导致ES6模块可能存在异步执行的情况,这是与CommonJS模块同步加载完全不兼容的特性。截至目前,还没有任何正式实现能完成此任务,不过Node.js社区正在重新尝试引入require(esm)特性,该特性将在满足以下条件时启用:(1)不包含顶层await。(2)文件扩展名为.mjs;或文件扩展名为.js,但目录层级中最近的package.json包含"type":"module";或文件扩展名为.js,但目录层级中最近的package.json不包含"type":"commonjs",且该模块包含ES6模块语法。从概念上讲,ESM基于共享绑定,而CommonJS模块基于共享值。在绑定语义下,所有对同一导出的引用都将始终访问同一内容,并且你不能查看尚未初始化的绑定。在值语义下,所有对同一导出的引用都将是一个全新的副本,彼此之间不受影响,你将所有内容视为属性,可能会看到未定义的内容。动态导入ESM是基于静态导入的理念进行创造的,在大多数情况下可以很好地完成任务,并且可以很好地支持静态分析(staticanalysi)、打包工具(bundlingtools)和摇树。动态导入是为代码加载需要延迟的场景设计的,由于动态导入不需要在静态分析中完成,所以导入代码的位置可以嵌套在任何层级,且指示符也不再需要是一个在静态分析时必须确定的指向性字符。import()是一个类函数(function-like)的模块加载语法,与在脚本中动态插入<scripttype=module>标签的方式相比,它不仅更易使用也不会污染DOM。
ImportAttributesImportAttributes允许开发者将具有type属性的对象通过with子句附加到导入语句中,对于给定的请求模块说明符,无论是否存在类型指示,主机都应该始终返回相同的模块
JSON模块JSON模块(JSONmodules)提案建立在ImportAttributes提案的基础之上,添加了在跨JavaScript环境中以更通用的方式导入指定模块的功能。如果导入具有“type”类型为“json”的模块,则主机应该将其视为JSON模块处理。相反,则必须拒绝导入。
ImportAttributesImportAttributes允许开发者将具有type属性的对象通过with子句附加到导入语句中,对于给定的请求模块说明符,无论是否存在类型指示,主机都应该始终返回相同的模块
JSON模块JSON模块(JSONmodules)提案建立在ImportAttributes提案的基础之上,添加了在跨JavaScript环境中以更通用的方式导入指定模块的功能。如果导入具有“type”类型为“json”的模块,则主机应该将其视为JSON模块处理。相反,则必须拒绝导入。
延迟模块评估延迟模块评估(DeferringModuleEvaluation)提案引入了importdefer语法。通过延迟语法导入的模块,仅会解析并加载依赖项,但模块的执行将延迟到真正需要它们的时候。谢谢Thankyou语言基础CONTENTS目录源代码词法环境与词法声明表达式与操作符可选的分号标识符与保留字循环上下文与环境记录030507020406080910语句Realm错误与异常01源代码01源代码ECMAScript源文本同样由一系列Unicode代码点所组成。从U+0000到U+10FFFF的所有Unicode代码点值,包括代理代码点,都可能出现在ECMAScript语法允许的ECMAScript源文本中。用于存储和交换ECMAScript源文本的实际编码与ECMAScript规范无关,无论外部源文本编码如何,符合ECMAScript的实现都会将源文本处理为等效的字符(Character)值序列,每个源字符都是一个Unicode代码点。源代码类型根据执行环境加以分类,ECMAScript源文本作为以下四种代码进行评估:(1)全局代码:被视为ECMAScript脚本的源文本。其中不包括任何函数(方法)及类。(2)Eval代码:提供给内置eval函数的源文本。(3)函数代码:被解析以提供ECMAScript函数对象的[[ECMAScriptCode]]和[[FormalParameters]]内部槽的源文本。(4)模块代码:作为模块内容提供的代码的源文本,它是初始化模块时直接评估的代码且不包含函数(方法)及类。标识符与保留字02标识符与保留字在ECMAScript规范中,标识符名称定义如下:根据Unicode标准附件#31,按照“标识符和模式语法”中给出的默认标识符语法进行解释的标记,并进行了一些细微调整。在语法上,将标识符(Identifier)定义为不是保留字的标识符名称。标识符与保留字关键字与保留字关键字是在JavaScript中具有特殊含义的标记(具有语法用途),许多关键字是保留字,但有些不是,有些仅在某些上下文中保留。if和while是保留字,但await仅在异步函数和模块内保留。有效标识符在规范中为标识符名称定义了以下几条规则:(1)始终允许用作标识符而不是关键字的变量,如Math、window,toString和_。(2)永远不允许用作标识符的字符,即上述列出的保留字,但await和yield除外。(3)在特定上下文中被允许作为标识符的那些,await和yield。(4)在严格模式下,那些在上下文中不允许作为标识符的标识符:let、static、implements、interface、package,privateprotected和public。(5)那些始终被允许作为标识符的名字,也可以在某些语法产生式中作为关键字出现:as、from、get、meta、of,set和target等。可接受的Unicode符号在明确了标识符的合法范围后,接下来的任务便是要了解标识符的编码规范。在ES2015中,标识符必须以$、_或具备Unicode派生核心属性ID_Start(标识符字符集表示,主要包括常用的大小写字母,也包括修饰字符这样不常用的字符)的任意符号开头。标识符的其余部分可以包含$、零宽度非连接符(U+200C)、零宽度连接符(U+200D)或具有Unicode派生核心属性ID_Continue(ID_Continue包括ID_Start,和诸如数字这样常见的字符)的任何符号。词法环境与词法声明03词法环境与词法声明let和const声明定义了范围为正在运行的执行上下文的词法环境(LexicalEnvironment)的变量和常量,该环境中的变量不可被外部访问。这些变量和常量是在实例化它们包含的环境记录时创建的,但在评估变量和常量的词法绑定(LexicalBinding)之前,不得以任何方式访问它们,这正是暂时性死区(TDZ,TemporalDeadZone)形成的根本原因。
TDZ的选择与应用TDZ(暂时性死区)指的是在评估期间当访问未初始化的变量时将得到一个错误。
暂时性死区的价值TDZ定义了未初始化词法绑定的错误语义,这是一种基于运行时的检查机制,在操作未初始化的词法绑定时会引发错误。从性能上考虑,这种检查随着环境选择的复杂度而增加成本,另一方面,静态检查工具或代码转译工具也会在一定程度上消除暂时性死区。
const与不变性无关const并不是表示某个值是常量或不可变的,它真正指的是绑定不可变。对于原始类型,这个绑定就是值,对于引用类型,这个绑定是引用。要使对象的值不可变,可以使用Object.freeze(),但它只能做浅层冻结,对于嵌套对象仍然需要我们手动去实现
voidDiscardBindings这是从显式资源管理提案中独立出来的提案,它允许你使用一个没有命名的占位符(void)来替代你不会使用的命名绑定标识符(BindingIdentifier)。丢弃绑定可以出现在多种场景中,包括using声明、解构、函数参数等。未来也可能加入更多特性中,如提取器(Extractors,增强绑定模式以扩展现有解构语法形式)和模式匹配(PatternMatching)。声明过程与提升可以引用它,
此时它的值为undefined使用程序代码进行赋值记录它存在于作用域中创建这个变量,
此时不可引用声明实例化初始化赋值引用记录规范类型在ECMAScript中,将变量的查找过程统一称为解析引用(ResolveBinding),与之对应的,这个描述变量查找的中间数据结构被称为引用记录规范类型(ReferenceRecordSpecificationType)。引用记录规范类型用于解释诸如删除,typeof,赋值运算符,super关键字和其他语言功能等运算符的行为。它包含了名字或属性的基本信息,如代码所处模式和所在的环境记录等。简单来讲,这里所说的引用并不是数据类型中的引用类型,而是指一个标识符的绑定结果。待解析的标识符无非是两种:一种是在环境记录中查找一个标识符,另一种则是在一个值的属性中查找。这也就确定了在标识符可以解析的情况下,[[base]]的值总是一个JavaScript语言值,或者是规范类型中的环境记录。而当引用不可解析时,[[base]]的值为UNRESOLVABLE。对于环境记录中不可解析的引用总是抛出一个引用错误(ReferenceError),而属性查找中则仅仅返回undefined引用记录规范类型除全局环境外,每个函数在调用时都会产生一个新的上下文及对应的环境记录,并将被调用函数所处的环境记录作为其外部环境记录,并记录在[[outEnv]]字段。以此类推,便形成了嵌套的环境(作用域)。例如,在全局环境中执行的函数outer(),其外部环境即为全局环境;在函数outer()中声明的函数inner(),其外部环境则是outer()函数所生成的环境记录。而标识符的查找也会沿着环境记录向上搜寻,如上图所示。语句04语句在程序的运行中,记录语句的完成状态是必不可少的。它不但包含了当前语句的执行状况,也揭示了值和控制流的运行时传播。在语言规范中,描述语句的完成记录主要由三部分构成:类型([[Type]]),携带的值([[Value]]),定向控制转移的目标标签([[Target]])。详细定义如表所示:名字描述[[Type]]包括:normal、break、continue,return和throw。其中只有normal是正常完成(NormalCompletion)。[[Value]]完成时产生的值(除了完成记录的任何值)。例如,函数的返回值或可能抛出的异常。[[Target]]用于定向控制传输,字符串或empty。一般来说:(1)执行完一条没有控制能力的语句后,程序会返回正常完成并继续执行下一条指令。(2)当程序抛出异常或中断等改变正常执行流的语句时,会返回抛出完成或中断完成。try-catch-finally的执行流这段代码中,我们尝试在函数中抛出一个错误,并将该错误捕获的同时执行一个return语句。根据try-catch-finally的语义,位于finally中的代码一定会执行,但在本例中却形成了矛盾。这是因为如果在catch中执行了返回操作,便无法执行finally中的代码,为了不破坏finally的语义,这里并不真正执行return,只是将返回结果记录下来并继续执行,直到遇到了finally语句中的return才真正的返回。可选的catch语句在实际场景中,开发者经常会忽略掉具体的异常,取而代之的是自定义的提示逻辑。这就导致catch中的绑定不再是必须。HashbangHashbang注释具有位置敏感性,仅在脚本或模块解析目标起始处效。它类似于Unix中的shebang,可提供一个特定的JavaScript解释器的路径,用以指示如何执行该文件。表达式与操作符05表达式与操作符表达式是一个可以被求值并产生一个值的短语。在ECMAScript规范中,从简单的标识符引用到拥有复杂语义的关系运算操作(如instanceof)都可以构成表达式。一个独立的不可拆解为更简单的表达式被称为主表达式(primaryexpression),构造复杂表达式的最简单方式是组合表达式。例如,数组字面量中可以包含简单的字面量、另一个数组,甚至是一个函数表达式的求值结果。
逻辑赋值运算符这是组合逻辑运算符和赋值表达式功能的语法,它包含“||=”、“&&=”和“??=”三种形式。前两种形式依赖于隐式转换,或者更直接地说,这是构建在已有错误上的语法糖。因此,在实践中,建议开发者只使用“??=”。
解构赋值这是一种扩展了赋值表达式(AssignmentPattern)中的左手端表达式(LeftHandSideExpression),并巧妙地利用了对象和数组字面量的语法。结构如下:对象的解构模式可以看作为构造对象字面量的逆过程,解构语法所得到的每一个值都等同于对属性的直接访问,当属性不存在是得到的是undefined。循环06ES5时期的for循环ES5时期的for循环支持下面两种形式:(1)for(Expression;Expression;Expression)Statement。(2)for(varVariableDeclarationList;Expression;Expression)Statement。在这两种语法形式中,所有的表达式(Expression)部分都是可选的。唯一不同的是,for语句是否存在自己的声明。在JavaScript的早期设计中,var声明只能存在于函数环境之中(全局可以看作是一个更大的函数),进而导致两种语法形式所绑定的变量都将存在于for循环所在的环境之中。换句话说,异步代码的执行访问的都是同一个全局变量。使用let的for循环ES6后,块作用域的出现改变了循环的过程,它使用了一种近乎魔法的手法修复了上面的问题。而这种近乎魔法的背后也不过是将手动创建环境记录的这一过程内置其中。使用let的for循环会在每一次迭代过程中创建环境记录并将变量注册其中,这意味着即使循环结束,异步中的代码依然可以访问的是当前循环过程中创建的变量,而非全局变量,实现了隔离性。可选的分号07可选的分号ASI有两部分:语法纠错+限制产生式。语法纠错的自动插入机制是为了代码的有效解析,通常在遇到一个由任何可能的产生式都无法生成的token时就会触发,或是在多个产生式中确定唯一的语义,这可在一定程度上修复语法解析的错误。当从左到右解析源文本时,遇到token输入流的结尾,并且解析器无法将输入token流作为目标非终结符的单个实例进行解析,则会在输入流的末尾自动插入分号。产生错误的语法产生错误的语法主要表现为以下三方面:(1)当有问题的token与上一个token中间包含至少1个换行符时,如案例1代码所示,将在let后添加分号组成合理的表达式语句,最后let被解析为一个标识符。(2)当有问题的token是“}”时自动添加分号,如案例2所示。(3)有问题的token的前一个token是“)”,如案例3所示,会在4前自动插入分号避免连续解析。上述规则中,自动分号的引入都是为了避免产生语法错误。产生错误的语法限制产生式则是语言设计之初用来约定特定语法的规则。当源文本进行从左到右的进行解析时,若遇到语法的某些产生式所允许的token,但产生式属于受限产生式的,同时该token将是紧跟在受限产生式中的注释“[noLineTerminatorhere]”之后的终结或非终结符的第一个token,并且受限token通过至少一个行终结符与前一个token分隔开,然后在受限token之前自动插入分号,它包括:(1)当以return语句结束时,在行末自动插入分号。(2)当以break语句结束时,在行末自动插入分号。(3)当以throw语句结束时,在行末自动插入分号。(4)当以continue语句结束时,在行末自动插入分号。(5)当以ES6的yield结尾时,在行末自动插入分号。(6)++、--后缀表达式作为新行的开始,在行首自动插入分号。(7)当以async语句结束时,需要判断下一个token。如果下一个token是函数关键字或标识符则插入分号,以便将后面的表达式或类元素单独解析;如果后面是“*”,并且在二者中间包含空行,插入的分号将导致语法错误。(8)当胖箭头(=>)前出现空行也会导致分号的插入,并产生一个错误。上下文与环境记录08上下文与环境记录执行上下文(ExecutionContext,下文简称上下文)的概念在JavaScript中至关重要,它是一种规范设备(specificationdevice),我们先来看下规范中的定义:它用于跟踪ECMAScript实现对代码的运行时评估。在任何时间点,每个实际执行代码的代理最多有一个执行上下文。正在运行的执行上下文始终处于当前栈的顶层。每当控制权从与当前运行的执行上下文关联的可执行代码转移到与该执行上下文无关的可执行代码时,将创建一个新的执行上下文。新创建的执行上下文被推送到栈上,成为正在运行的执行上下文。执行上下文包含跟踪其关联代码的执行进度所需的任何特定于实现的状态。它不仅包含当前上下文相关代码评估所产生的状态,也关联了一组程序执行的必要信息:其中包括与之关联的脚本或模块、提供JavaScript内置功能的Realm记录以及当该上下文是一个函数时独有的关联字段等。每个执行上下文都关联着特定的环境记录,所有定义的变量和函数都记录于环境记录上,且此记录无法通过JavaScript代码访问。上下文当执行到代码中的letglobalName='globalContext'时,便会在全局环境记录下globalName这个名字,就如同我们在全局环境初始化中讲的那样。当函数被调用时,引擎就会创建一个函数上下文并被推送到上下文栈上,此时该函数上下文即为正在执行的上下文。函数执行完成后,该上下文会从栈中弹出,将控制权返还给上一个执行的上下文。因此,变量“fName”和变量“innerName”将分别注册在各自的函数环境记录之中。此功能控制整个JavaScript程序的执行流程。作用域如果将上下文比喻为描述运行时环境的动态状态管理器,那么作用域(Scope)则是描述变量可访问范围的静态轮廓。JavaScript中的变量使用词法作用域(LexicallyScoped),它也被称为静态作用域。因此,引擎可以通过分析程序的静态结构来确定变量的作用域。在分析变量的作用域时,你总是可以依靠文本静态的分析引用位置,它不会受到执行(调用)位置的影响。环境组件的变迁环境记录是为变量提供存储空间的数据结构,JavaScript中的词法环境根据JavaScript代码的词法嵌套结构定义标识符、变量和函数值的关联,实现了JavaScript词法作用域的嵌套结构。在ES3时代,变量的作用域语义是使用JavaScript对象来描述的。彼时的变量注册机制还没有如此复杂,只是将变量与函数绑定到活动对象(ActivationObject,AO)中。由于这种对象几乎等同于用户创建的对象,因此他们使用了相同的语义。在ES6引入词法声明后,活动对象便不再适合描述变量机制,因为它无法为词法声明描述一个单独的块级作用域轮廓,这正是环境记录引入的主要原因。环境记录通常,环境记录与JavaScript代码的某些特定语法结构相关联,如FunctionDeclaration,BlockStatement或TryStatement的Catch子句。每次解析此类代码时,都会创建一个新的环境记录,以此来记录由该代码创建的标识符绑定。每个环境记录都有一个[[OuterEnv]]内部槽,该字段的值为null或是对外部环境记录的引用,此引用用于对环境记录值的逻辑嵌套进行建模。(内部)环境记录的外部引用,是对逻辑上围绕内部环境记录的引用,并且外部环境记录也同样可以具有自己的外部环境记录。外部环境记录可以用作多个内部环境记录的外部环境。在左侧代码中,除全局环境记录外,当我们执行了函数f的调用时,便会为函数上下文创建LexicalEnvironment和VariableEnvironment两个组件(这里两个组件指向同一个记录),用来记录变量inner。Realm09Realm在程序执行前,所有JavaScript代码都必须与一个Realm(域)相关联。从概念上讲,域由一组内部对象(intrinsicobjects)、一个JavaScript全局环境(globalenvironment)、在该全局环境范围内加载的所有JavaScript代码以及其他相关联的状态和资源组成,从而为执行环境描述一个全局的语义。在我们常用的浏览器环境中,每一个标签页(窗口)都拥有一个域,其中的内置对象和函数是JavaScript
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026中银行面试题目及答案
- 乔迁新居庆典主持稿开场白五篇
- 2026-2030中国坚果行业市场深度分析及发展预测与投资策略研究报告
- 2026-2030中国立德粉市场运行格局及投资前景评估研究报告
- 2026-2030生物能源行业市场深度调研及发展规划与投资前景研究报告
- 人教部编版五年级语文上册期中考试(完整版)
- 2026年证券行业专业资格水平测试基础题库历年真题汇编
- 2026年环境影响评价工程师《环境影响评价案例分析》专项训练卷
- 2026年税务师考试《税法》冲刺押题卷
- 医疗常识测试题目与答案
- 工程档案保密培训课件
- 初一数学入学考试试卷及评分标准
- 烹饪营养教程-全套
- 小学睡觉纪律整改措施
- 第四届全国急救中心急救技能大赛医疗急救知识800题及参考答案
- 高中历史研究性课题心得体会范文
- 军衔等级划分课件
- 电厂重要阀门管理制度
- 净菜加工车间管理制度
- 2025-2030中国KNX产品行业市场发展趋势与前景展望战略研究报告
- 尿失禁的中医护理
评论
0/150
提交评论