前言
ECMAScript标准是深入学习JavaScript原理最好的资料,没有其二。
通过增加对ECMAScript语言的理解,理解javascript现象后面的逻辑,提升个人编码能力。
欢迎关注和订阅专栏 重学前端-ECMAScript协议上篇
一起讨论几个问题
Realm, Agent,Agent Cluster 是什么
- Realm:主要关注全局对象集和全局执行环境的隔离
- Agent:关注的是并发执行和执行上下文的管理
- Agent Cluster: 关注内存共享
其三者的关系图如下
-
一个Window对应的有一个Realm, Realm有一个
[[GlobalThis]]
属性指向 Window的实例,每个Window的下的内置对象是不同的。javascriptconst iframe = document.createElement("iframe"); document.body.appendChild(iframe); const xArray = window.frames[window.frames.length - 1].Array; // 不同领域的Array不相等 xArray === Array // false
-
一个Agent 对应有一个 事件循环的线程,一个事件循环可以涉及到多个Realm (Window实例)。 即多个Window实例共享一个事件循环。
通常情况下,同源下的
index.html
和iframe.html
共用一个事件循环。html// index.html <iframe src="./iframe.html"></iframe> <script> function checkExecution() { console.log('Checking execution in index page', new Date().toTimeString()); } setInterval(checkExecution, 1000); // 每秒执行一次 </script> // iframe.html <script> function longRunningOperation() { const startTime = Date.now(); let i = 0; while (Date.now() - startTime < 5000) { // 假设执行5秒 i++; } console.log('Long operation finished in iframe page', new Date().toTimeString()); } setTimeout(() => { longRunningOperation(); }, 2000) </script>
- index.html 前2000ms每秒输出,
- 2000ms之后因为iframe.html的阻塞,导致了 index.html暂停了输出,
- 5000ms之后,又继续输出。

-
同源的Window实例可能处于不同Agent,如果没有直接关联。比如
- 直接地址栏打开两个页面
rel=noopener
打开的新页面
怎么去验证呢,很简单呢,每个Agent有自己独立的执行线程。使用
rel=noopener
打开的other.html, other.html的阻塞不影响index.html的输出即可。 这里的 index.html和other.html就属于不同的Agent。html// index.html <h1> 同源下的不个Realm(Window)拥有独自的Agent</h1> <a href="./other.html" target="_blank" rel="noopener">other页面</a> <script> function checkExecution() { console.log('Checking execution in index page', new Date().toTimeString()); } setInterval(checkExecution, 1000); // 每秒执行一次 </script> // other.html <script> // 页面1(或Web Worker1) function longRunningOperation() { console.log('Long operation started ', new Date().toTimeString()); const startTime = Date.now(); let i = 0; while (Date.now() - startTime < 5000) { // 假设执行5秒 i++; } console.log('Long operation finished ', new Date().toTimeString()); } setTimeout(() => { longRunningOperation(); }, 2000) </script>
看输出结果
修改
rel="opener"
,结果会怎么样呢?
this是什么
随便提一个问题 this
是什么? 却少有人能够说清楚其来龙去脉, 因为要说清 this
, 从协议层面来说至少需要牵涉到
- 严格模式
- 函数对象
- 执行上下文
- 环境记录(全局环境记录,申明环境记录,函数环境记录,全局环境记录等)
- 函数绑定特异对象等概念。
其本质: 函数执行时从 环境记录 中临时借用的一个值而已。 且并不是所有的环境记录都可以保存这个 this的绑定关系的值。
其从设置到使用过程又分为
- 绑定(OrdinaryCallBindThis)
- 查找(ResolveThisBinding)
- 取值( GetThisBinding)
比如如下代码
javascript
var obj = {
log:() => {
"use strict"
return this.eName
},
eName: "object eName"
};
obj.log(); // undefined
最终的 this
的查找流程如下:
块是如何 let/const/class 离开之后就不能被访问到的
html
<script>
"use strict"
var varA = 'varA';
{
var varA = 'block_varA';
function constA(){};
console.log(varA, constA); // block_varA ƒ constA() { }
}
console.log(varA, constA); // Uncaught ReferenceError: constA is not defined
</script>
三张图解释清楚
进入Block之前

Block 内 console.log(varA, constA)
执行前
退出Block后
你会学到什么?
- ECMAScript协议的一些协议概念,模块章节,进化史等等;
- 语言类型,协议类型以及一些语法导向的操作
- 浏览器中环境中 Agent, Realm, Agent Clusters的概念和基本机制;
- 脚本是怎么从文本到被执行的
- 执行上下文,环境记录,引用记录,以及她们是怎么协作让标志符运作起来
- 作用域和作用域链,闭包的底层逻辑
- 函数对象的初始化,new 的机制
- 暂时性死区的协议原理,with语句运作机制,申明&赋值&属性赋值的区别
- 块是怎么生效等
- 各种运算符以及怪谈的底层逻辑
- 类型转换的最底层原则
- ECMAScript 的 Built-in Exotic Object 怪异对象
- 其他各种协议知识
- 数组和对象的 快慢机制和基本原理
- 写代码,理解代码
适宜人群
- 想完整阅读ECMASCript协议,强化内功,缺乏相关基础的同志;
- 前端1-3年的初中级前端工程师,想进一步向高级工程师的迈进;
- 对于JS各种现象和设计,追求知其然知其所以然的JSer;
- 想要跳槽,攻克技术面试知识点的同学。