js的一些潜在规则示例分析

目录
  • 宏任务和微任务
  • 语句的执行过程 (Completion Record )
  • 文法
    • 词法
  • 语句是否需要加分号
    • no LineTerminator here规则
  • 脚本和模块
  • 声明提升
  • 解析HTML
  • DOM API
  • 节点
  • 遍历
  • Range
  • DOM中的位置
    • 全局尺寸信息
  • 事件
  • 性能优化

宏任务和微任务

采纳 JSC 引擎的术语,我们把宿主发起的任务称为宏观任务,把 JavaScript 引擎发起的任务称为微观任务。

JavaScript 引擎等待宿主环境分配宏观任务,在操作系统中,通常等待的行为都是一个事件循环,所以在 Node 术语中,也会把这个部分称为事件循环。在底层的 C/C++ 代码中,这个事件循环是一个跑在独立线程中的循环。

宏观任务的队列就相当于事件循环。

在宏观任务中,JavaScript 的 Promise 还会产生异步代码,JavaScript 必须保证这些异步代码在一个宏观任务中完成,因此,每个宏观任务中又包含了一个微观任务队列。

语句的执行过程 (Completion Record )

我们知道有的语句按顺序执行,有的语句会阻断执行。那么这是何种原因导致的呢?

我们来看一下js语句执行的完成状态。JavaScript 语句执行的完成状态,我们用一个标准类型来表示:Completion Record。

Completion Record 表示一个语句执行完之后的结果,它有三个字段:

  • [[type]] 表示完成的类型,有 break continue return throw 和 normal 几种类型;如果返回的type是normal,那么语句将会顺序执行。
  • [[value]] 表示语句的返回值,如果语句没有,则是 empty;只有表达式语句会产生 [[value]]。
  • [[target]] 表示语句的目标,通常是一个 JavaScript 标签。当在循环语句中,结合break/continue可以跳出多层循环。
outer: while(true) {
    inner: while(true) {
        break outer;
    }
}
console.log("finished")

在任何一个js语句之前都可以加一个标签。

    firstStatement: var i = 1;

控制语句跟 break 、continue 、return 、throw四种类型与控制语句两两组合产生的效果。

  • 消费就是在当前语句中结束了。

穿透就是继续执行下一条语句。

文法

文法 = 词法 + 语法。

词法

JavaScript 源代码中的输入可以这样分类:

WhiteSpace 空白字符

LineTerminator 换行符

Comment 注释

Token 词

  • IdentifierName 标识符名称,典型案例是我们使用的变量名,注意这里关键字也包含在内了。
  • Punctuator 符号,我们使用的运算符和大括号等符号。
  • NumericLiteral 数字直接量,就是我们写的数字。 为什么12.toString会报错?

十进制的 Number 可以带小数,小数点前后部分都可以省略,但是不能同时省略。12.被当成一个词。如果想让表达式正常运行,我们可以让.成为一个词。

    12. toString()
  • StringLiteral 字符串直接量,就是我们用单引号或者双引号引起来的直接量。

字符串中其他必须转义的字符是\和所有换行符。

  • Template 字符串模板,用反引号`括起来的直接量。
  • RegularExpressionLiteral

正则表达式有自己的语法规则,在词法阶段,仅会对它做简单解析。

语句是否需要加分号

自动插入分号规则其实独立于所有的语法产生式定义,它的规则说起来非常简单,只有三条。

  • 要有换行符,且下一个符号是不符合语法的,那么就尝试插入分号。
  • 有换行符,且语法中规定此处不能有换行符,那么就自动插入分号。
  • 源代码结束处,不能形成完整的脚本或者模块结构,那么就自动插入分号。

no LineTerminator here规则

这个规则与自动插入分号的第二条规则紧密相关。

脚本和模块

脚本是可以由浏览器或者 node 环境引入执行的,而模块只能由 JavaScript 代码用 import引入执行。

从概念上,我们可以认为脚本具有主动性的 JavaScript 代码段,是控制宿主完成一定任务的代码;而模块是被动性的 JavaScript 代码段,是等待被调用的库。

直接 import 一个模块,只是保证了这个模块代码被执行,引用它的模块是无法获得它的任何信息的。带 from 的 import 意思是引入模块中的一部分信息,可以把它们变成本地的变量。

通过export default导出的值,和导入文件的变量不是实时绑定的。导出文件的变量改变不会影响导入变量的变化。

声明提升

预处理阶段,var 和函数声明的作用能够穿透一切语句结构,它只认脚本、模块和函数体三种语法结构。

函数声明提升和var变量声明提升的区别

函数声明能穿过if等语句,但是只是在全局创建一个同名的变量赋值为undefined,并没有把函数体提升。

    console.log(foo); // undefined
    if(true) {
        function foo(){}
    }
    // 因为一般函数都是整体提升的。
    var a = 1;
    function foo() {
        console.log(a); // undefined
        if(false) {
            var a = 2;
        }
    }
    foo();

解析HTML

编译阶段。会将html标签拆分成一个个token(表示最小的有意义的单元), 种类大约只有标签开始、属性、标签结束、注释、CDATA 节点几种。

实现分词,又用到了状态机。用状态机做词法分析,其实正是把每个词的“特征字符”逐个拆开成独立状态,然后再把所有词的特征字符链合起来,形成一个联通图结构。 其中每一个状态函数都返回一个状态函数,做状态迁移。

把html元素分成若干词后,我们就可以构建dom树了。这个过程是使用栈来实现的。我们把每个解析的词加入到栈中,当接收完所有输入,栈顶就是最后的根节点。

对于 Text 节点,我们则需要把相邻的 Text 节点合并起来,我们的做法是当词(token)入栈时,检查栈顶是否是 Text 节点,如果是的话就合并 Text 节点。

可以点击这里查看解析规则

github上别人写了一个简易的解析器

排版。

  • 浏览器对行的排版,一般是先行内布局,再确定行的位置,根据行的位置计算出行内盒和文字的排版位置。
  • 块级盒比较简单,它总是单独占据一整行,计算出交叉轴方向的高度即可。
  • 浮动元素排版,float 元素非常特别,浏览器对 float 的处理是先排入正常流,再移动到排版宽度的最左 /最右(这里实际上是主轴的最前和最后)。
  • 绝对定位元素。完全跟正常流无关的一种独立排版模式,逐层找到其父级的 position 非 static 元素即可。

渲染。

浏览器中渲染这个过程,就是把每一个元素对应的盒变成位图。 这里的元素包括 HTML 元素和伪元素,一个元素可能对应多个盒(比如 inline 元素,可能会分成多行)。每一个盒对应着一张位图。

渲染过程,是不会把子元素绘制到渲染的位图上的,这样,当父子元素的相对位置发生变化时,可以保证渲染的结果能够最大程度被缓存,减少重新渲染。

合成。

合成的过程,就是为一些元素创建一个“合成后的位图”(我们把它称为合成层),把一部分子元素渲染到合成的位图上面。

绘制。

绘制过程,实际上就是按照 z-index 把合成位图依次绘制到屏幕上。

DOM API

DOM API 大致会包含 4 个部分。

  • 节点:DOM 树形结构中的节点相关 API。
  • 事件:触发和监听事件相关 API。
  • Range:操作文字范围相关 API。
  • 遍历:遍历 DOM 需要的 API。

节点

元素在DOM树中关系api

  • parentNode
  • childNodes
  • firstChild
  • lastChild
  • nextSibling
  • previousSibling

操作 DOM 树的API

  • appendChild
  • insertBefore
  • removeChild
  • replaceChild

一些高级 API

  • compareDocumentPosition 是一个用于比较两个节点中关系的函数。
  • contains 检查一个节点是否包含另一个节点的函数。这个方法一般用于做一些点击判断,然后关闭一些dom的功能。
  • isEqualNode 检查两个节点是否完全相同。
  • isSameNode 检查两个节点是否是同一个节点,实际上在 JavaScript 中可以用“===”。
  • cloneNode 复制一个节点,如果传入参数 true,则会连同子元素做深拷贝。

创建DOM的api

  • createElement
  • createTextNode
  • createCDATASection
  • createComment
  • createProcessingInstruction
  • createDocumentFragment
  • createDocumentType

操作属性的api

  • getAttribute
  • setAttribute
  • removeAttribute
  • hasAttribute 如果你喜欢 property 一样的访问 attribute,还可以使用 attributes 对象,比如document.body.attributes.class =“a”等效于document.body.setAttribute(“class”,“a”)。

查找元素api

  • querySelector
  • querySelectorAll
  • getElementById
  • getElementsByName
  • getElementsByTagName
  • getElementsByClassName

我们需要注意,getElementById、getElementsByName、getElementsByTagName、getElementsByClassName,这几个 API 的性能高于 querySelector。

新增加的节点会被添加到非querySelector, querySelectorAll查询出来的对象上的。

遍历

  • createNodeIterator
  • createTreeWalker

Range

Range API 表示一个 HTML 上的范围,这个范围是以文字为最小单位的,所以 Range 不一定包含完整的节点。

具体请看这里

DOM中的位置

全局尺寸信息

我们获取宽高的对象应该是“盒”,于是 CSSOM View 为 Element 类添加了两个方法:

  • getClientRects()。返回一个列表,里面包含元素对应的每一个盒所占据的客户端矩形区域,这里每一个矩形区域可以用 x, y, width, height 来获取它的位置和尺寸。
  • getBoundingClientRect()。它返回元素对应的所有盒的包裹的矩形区域,需要注意,这个 API 获取的区域会包括当 overflow 为visible 时的子元素区域。

这两个 API 获取的矩形区域都是相对于视口的坐标,这意味着,这些区域都是受滚动影响的。

事件

事件捕获的由来?

我们操作元素时,都是通过输入设备来做到的,点击事件来自触摸屏或者鼠标,鼠标点击并没有位置信息,但是一般操作系统会根据位移的累积计算出来,跟触摸屏一样,提供一个坐标给浏览器。把这个坐标转换为具体的元素上事件的过程,就是捕获过程了。

建议这样使用冒泡和捕获机制:默认使用冒泡模式,当开发组件时,遇到需要父元素控制子元素的行为,可以使用捕获机制。

事件处理函数不一定是函数,也可以是个 JavaScript 具有 handleEvent 方法的对象。

var o = {
    handleEvent: event => console.log(event)
}
document.body.addEventListener("keydown", o, false);

自定义事件。DOM API 中的事件并不能用于普通对象,所以很遗憾,我们只能在 DOM 元素上使用自定义事件。

    var evt = new Event("look", {
        "bubbles":true,
        "cancelable":false
    });
    document.dispatchEvent(evt); // 调用自定义事件

性能优化

以上就是js的一些潜在规则示例分析的详细内容,更多关于js潜在规则的资料请关注我们其它相关文章!

(0)

相关推荐

  • js的一些潜在规则使用分析

    目录 为什么开发中建议使用void 0 来代替undefined 为什么开发中将未赋值的变量赋值为null,而不是undefined String类型的长度 为什么parseInt在将字符串转为数字的时候,需要指定第二个参数 对象转基本数据类型的规律 JavaScript 中对象独有的特色 JavaScript对象分类 宿主对象 内置对象 特殊行为对象 为什么开发中建议使用void 0 来代替undefined 因为 JavaScript 的代码 undefined 是一个变量,而并非是一个关键

  • 详解package.json版本号规则

    版本的格式 major.minor.patch 主版本号.次版本号.修补版本号 patch:修复bug,兼容老版本 minor:新增功能,兼容老版本 major:新的架构调整,不兼容老版本 依赖版本号规则 version 必须匹配某个版本 如:1.1.2,表示必须依赖1.1.2版 >version 必须大于某个版本 如:>1.1.2,表示必须大于1.1.2版 >=version 可大于或等于某个版本 如:>=1.1.2,表示可以等于1.1.2,也可以大于1.1.2版本 <ve

  • js 公式编辑器 - 自定义匹配规则 - 带提示下拉框 - 动态获取光标像素坐标

    引言 前段时间发了一个编辑器的插件,忙完后自己再次进行了详细的测试,然后心里冒出一句:"这谁写的这么奇葩的插件?完全没什么luan用啊!" 自己做了让自己不满意的事,咋整?男人不怕累,花了时间重写(为世界上所有像我一样勤劳的男人点赞)~ 思维导图 在小生看来,在开发每一个新功能的时候都应该做到心中有一张思维导图:功能实现逻辑和实现功能大致的方法.当然我们不可能在还没动手 前就考虑得面面俱到,但在正式开发之前心里对整个流程有个清晰的印象肯定会让我们在动手时愈加流畅(喝口娃哈哈美滋滋,看图

  • 超详细的JavaScript基本语法规则

    目录 01 JavaScript (简称:js) js分三个部分: JavaScript是什么? js的代码可以分三个地方写: 02 操作符 操作符:一些符号-----用来计算 关系运算符: 关系运算表达式: 逻辑运算符: 逻辑运算表达式: 03 JS变量 变量名的注意问题-变量名的命名: 04 JS变量作用 05 JS变量的交换 使用第三方的变量进行交换 第二种方式交换:一般适用于数字的交换 06 注释 注释的方式: 07 JS的数据类型 值类型(基本类型): 引用数据类型: 08 JS的数字

  • JavaScript中运算符规则和隐式类型转换示例详解

    前言 本文主要给大家介绍了关于JavaScript运算符规则和隐式类型转换的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 隐式类型转换 在 JavaScript 中,当我们进行比较操作或者加减乘除四则运算操作时,常常会触发 JavaScript 的隐式类型转换机制:而这部分也往往是令人迷惑的地方.譬如浏览器中的 console.log 操作常常会将任何值都转化为字符串然后展示,而数学运算则会首先将值转化为数值类型(除了 Date 类型对象)然后进行操作. 我们首先来

  • JS实现遍历不规则多维数组的方法

    本文实例讲述了JS实现遍历不规则多维数组的方法.分享给大家供大家参考,具体如下: 直接进入正文: 我们有时候处理数据,可能会遇到一些不规则(无法预料的数据结构),那么拿到这种数据我们如何进行遍历操作呢?举个例子: var data= { a: { one: 1, two: 2, three: {four:'2',five:'4'} }, b: { six: 4, seven: 5, eight: 6 }, c: { nine: 7, ten: 8} } 比如上边的数据(实际情况是这个数据会有各种

  • js的一些潜在规则示例分析

    目录 宏任务和微任务 语句的执行过程 (Completion Record ) 文法 词法 语句是否需要加分号 no LineTerminator here规则 脚本和模块 声明提升 解析HTML DOM API 节点 遍历 Range DOM中的位置 全局尺寸信息 事件 性能优化 宏任务和微任务 采纳 JSC 引擎的术语,我们把宿主发起的任务称为宏观任务,把 JavaScript 引擎发起的任务称为微观任务. JavaScript 引擎等待宿主环境分配宏观任务,在操作系统中,通常等待的行为都是

  • js的Object.assign用法示例分析

    本文实例讲述了js的Object.assign用法.分享给大家供大家参考,具体如下: 作用 Object.assign() 用于将所有可枚举的自有属性的值从一个或多个源对象复制到目标对象.它将返回目标对象. 语法 Object.assign(target, -sources) 参数: target: 目标对象 sources:任意多个源对象 返回值 返回值为合并属性后的目标对象,即target. 示例1(属性值是值类型) var obj1 = { a:1 }; var obj2 ={ b:2 }

  • Sentinel热点规则示例详解分析

    目录 概念 @SentinelResource 小试牛刀 TestController.java defaultFallback fallback 流量控制 熔断降级 热点参数限流 高级选项 概念 商品 ID 为参数,统计一段时间内最常购买的商品 ID 并进行限制 用户 ID 为参数,针对一段时间内频繁访问的用户 ID 进行限制 热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流. 热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源

  • vue.js前端网页弹框异步行为示例分析

    目录 1. 序 2. 找两个弹框组件看看 3. 自己肝一个 3.1. 封装 Promise 3.2. 确定时允许异步等待 3.3. 细节完善 3.4. 改革 1. 序 网页弹框是个很常见的功能,比如需要告知用户消息的时候 (Alert),需要用户进行确认的时候 (Confirm),需要用户补充一点信息的时候 (Prompt) -- 甚至可以弹框让用户填写表单 (Modal Dialog). 弹框之后,开发者需要知道这个弹框是什么时候关闭以便进行接下来的操作. 在比较古老的 UI 组件中,这个事情

  • node.js基础模块http、网页分析工具cherrio实现爬虫

    一.前言       说是爬虫初探,其实并没有用到爬虫相关第三方类库,主要用了node.js基础模块http.网页分析工具cherrio. 使用http直接获取url路径对应网页资源,然后使用cherrio分析. 这里我主要学习过的案例自己敲了一遍,加深理解.在coding的过程中,我第一次把jq获取后的对象直接用forEach遍历,直接报错,是因为jq没有对应的这个方法,只有js数组可以调用. 二.知识点     ①:superagent抓去网页工具.我暂时未用到.     ②:cherrio

  • C语言编程深入理解取整取余取模问题示例分析

    目录 1. 取整问题 1.0向取整(C语言默认的取整方案) 2.地板取整(向负无穷的方向取整) 3.天花板取整(向+无穷的方向取整) 4.四舍五入取整 汇总例子 2.取模问题  1.余数的定义 2.两种余数 3.为什么会有这种现象? 3.区分取余与取模 1.取余与与取模的本质区别 2.理解链 3.同符号与不同符号 1.同符号: 2.不同符号 1. 取整问题 1.0向取整(C语言默认的取整方案) #include<stdio.h> #include<windows.h> int ma

  • MVVMLight项目之绑定在表单验证上的应用示例分析

    目录 常见的表单验证机制有如下几种: 验证交互的关系模式如图: 下面详细描述下这三种验证模式 1.Exception 验证: 2.ValidationRule 验证: 3.IDataErrorInfo 验证: 表单验证是MVVM体系中的重要一块.而绑定除了推动 Model-View-ViewModel (MVVM) 模式松散耦合 逻辑.数据 和 UI定义 的关系之外,还为业务数据验证方案提供强大而灵活的支持. WPF 中的数据绑定机制包括多个选项,可用于在创建可编辑视图时校验输入数据的有效性.

  • HTML+JS实现猜拳游戏的示例代码

    目录 效果图 关于JS构建过程 添加事件监听器 函数 gameRules() 函数 whoWon() 效果图 游戏可以通过这个链接进入 关于JS构建过程 首先,我创建了一个对象,其中包含每种可能性的文本格式(石头.纸.剪刀),然后将图像源也添加到该对象中. 在我制作的 HTML 中: playerChoiceImg playerChoiceTxt computerChoiceImg computerChoiceTxt 能够修改其中的每个内容. 然后创建了一个points变量,它将存储每个玩家(玩

  • Vue.js实现watch属性的示例详解

    目录 1.写在前面 2.watch的实现原理 3.立即执行的watch与回调执行时机 立即执行的回调函数 回调函数的执行时机 4.过期的副作用函数和cleanup 5.写在最后 1.写在前面 在上篇文章中,我们讨论了compted的实现原理,就是利用effect和options参数进行封装.同样的,watch也是基于此进行封装的,当然watch还可以传递第三参数去清理过期的副作用函数.不仅可以利用副作用函数的调度性,去实现回调函数的立即执行,也可以控制回调函数的执行时机. 2.watch的实现原

随机推荐