前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >​什么是 JavaScript?

​什么是 JavaScript?

作者头像
LIYI
发布2023-08-31 19:43:02
2670
发布2023-08-31 19:43:02
举报
文章被收录于专栏:艺述论专栏艺述论专栏

JS 的定义

JavaScript 是一种脚本,一门编程语言,它可以在网页上实现复杂的功能,网页展现给你的不再是简单的静态信息,而是实时的内容更新,交互式的地图,2D/3D 动画,滚动播放的视频等等。

img

它是标准 Web 技术蛋糕的第三层。

HTML 是一种标记语言,用来结构化我们的网页内容。CSS 是一种样式规则语言,可将样式应用于结构化的 HTML 内容,控制其外观。JavaScript 是一种动态脚本语言,用于动态创建和控制页面内容(包含结构化的内容及其样式),它可以响应用户输入并做出及时反馈。

如何理解“结构化”?

所谓结构化,就是一层一层的包含关系。下面就是一段结构化的 HTML 文本:

代码语言:javascript
复制
<div>
  <span>LIYI</span>
  <span>yishulun.com</span>
</div>

两个子标签 span 包含在一个父标签 div 之内。

HTML 用了尖括号作为了标签的边界符,这只是一种语法规定,事实上如果我们愿意,我们使用 JSON 或 TOML 格式实现结构化也是可以的,我们也可以使用方括号代替尖括号,但从实际结果来看,还是使用 XML 格式更好,尖括号因为在文本中使用不多,用它作为边界符也比较合适。

如何理解“样式规则”?

一种样式规则规定了一种特定的渲染效果,例如 color:red 表示红色,padding:15px 表示 15 个像素的内间距。

没有任何其它渲染库,像 CSS 这样既简单、又丰富地实现了对各种渲染效果的控制,再加上 HTML 标签几乎不够约束的构建结构化内容的能力,CSS+HTML 成为了普适性最强的界面构建标准,再加上 JS 强大而灵活的互动能力,CSS+HTML+JS 理所当然地成为了最流行的大前端界面构建标准。从 Web,到手机 App,再到 PC(Personal Computer)桌面软件,CSS+HTML+JS 三剑客畅通无阻,一切可以用前端技术实现的界面,终将全部被大前端技术所覆盖。

JS 能干什么事?

JS 在 Web 页面上几乎能干一切事,举例:

  • 在当前页面的变量中存储一些值;
  • 在内存中操作一些文本,例如将“作者”与“LIYI”拼接起来,形成“作者:LIYI”;
  • 在页面上画出一个圆;
  • 响应某个按钮的单击事件,调用 alert 接口弹出一个提示;
  • 向服务器端的某个接口发出网络请求,发送一些数据,拉取一些数据,并在页面上更新一些数据;
  • 其它更多操作。

JS 能干这么事情,一些是基于它本身语言具有的能力,一些基于浏览器宿主环境提供的 API,一些则基于第三方 API。

浏览器 API 主要包括:

  • 文档对象模型 API,一般称为 DOM API,包括创建、修改、移除 HTML 节点,移除与应用 CSS 样式等,这也是 JS 在页面上主要的用武之地;
  • 地理位置 API,是用于获取地理信息的;
  • 画布 Canvas 及 WebGL API,用于创建和控制 2D、3D 图像;
  • 多媒体影音类 API,例如 HTMLMediaElement 和 WebRTC 等;
  • 其它浏览器提供的接口。

第三方 API 由第三方厂商发布,例如 Twitter API、新浪微博 API 等。

当浏览器加载一个 URL 地址时发生了什么事?

img

浏览器在读取一个网页时,代码(HTML, CSS 和 JavaScript)将在一个运行环境(浏览器标签页)中得到执行。就像一间工厂,将原材料(代码)加工为一件产品(网页)。在 HTML 和 CSS 集合组装成一个网页后,浏览器的 JavaScript 引擎将执行 JavaScript 代码。这保证了当 JavaScript 开始运行之前,网页的结构和样式已经就位。

在这个过程中,浏览器具体都做了什么事?

这个过程有点复杂,主要有以下 11 步:

  • DNS 查询
  • TCP 握手
  • TSL 协商:为了建立安全传输数据的 https 连接,避免第三方窥探;
  • 服务器响应:HTML 页面的文本将从服务器发到用户的浏览器中;
  • 14KB 慢启动:页面大小是以 14KB 为计量单位的,一个页面是 4KB 还是 14KB,加载速度如果不考虑解析,可能是一样的;
  • 解析页面:将解析出 HTML 代码、CSS 代码、JS 代码、网络图片资源等;
  • 树的构建:同时构建 DOM(文档对象)树、CSSOM(CSS 对象)树,这里构建的是原始树,display 等于 none 的节点也是存在的。 为了加快页面的解析速度,浏览器(例如 Chrome 浏览器)设置了一个资源预加载器,在不影响主线程解析页面的情况下,提前加载了 css style、js、图片等网络资源。在这里需要明确的是:css 样式文件、网络图片、使用 script 标签加载且已添加了 async 或 defer 标记的 js 脚本,都是不会阻塞 HTML 页面解析的。 有什么启示?各种资源文件放在页面的头部、尾部都没有关系,关键对于 js 文件,要添加 async 或 defer 属性,要让 js 文件老早就开始加载,但不会阻碍页面解析。
  • 构建渲染树:将 CSSOM 与 DOM 合成了一个 Render 树,在这一步,凡 display 等于 none 的节点已经不存在了,凡 visibility 等于 hidden 的节点还存在,这给我们什么启示?在当前页面内如果一个节点在任何时候都不会显示,就设置 display 为 none;如果只是动画性质的暂时不显示,设置 visibility 为 hidden。
  • 布局:渲染树形成的时候,每个 HTML 节点是有自己的样式的,但大小和位置还没有确定,在这一步,渲染引擎将从渲染树的根节点开始,遍历整颗树,处理与确定所有节点的大小及位置信息,这便叫布局。完成后,形成有正确、完善布局信息的 Layout 树。这给我们什么启示?HTML 节点的嵌套不要太深、太多!
  • Layer 树:有些浏览器(例如 Chrome)为了提供渲染效率,渲染树是有分层的,例如所有 canvas 与影音类元素 video 分在一个层,所有使用 opacity(透明)、transform(动画转换)、will-change(将要变化什么)样式的元素分在一个层,其它元素分到一个层。 当需面需要重新渲染时,先检查在哪个层,凡只涉及某层的变化,就只在该层处理。 这给我们什么启示?在使用 opacity、transform、will-change 这些样式时要小心,能够合并的样式尽量合并,例如在多个子元素上使用 opacity 样式,就不如直接在父元素上使用 opacity 样式;能够使用一个 canvas 完成的事情,就不要使用多个 canvas(在微信小程序开发中,默认只有一个 canvas 是上屏画布)。
  • 合成与渲染:如果有分层,那必有合成,将散开的层按正确的上下层遮挡关系合在一起。最后渲染输出。每次页面至少要控制在 16.7 毫秒以内,这样才感觉不到页面卡顿。
  • 回流:当 js 加载完成后,会在页面的 HTML 和 CSS 全面准备好以后执行,如果 js 在 onload 事件中改变了某页面元素的大小,或者刚才没有加载完成的网络图片现在加载好了,则会触发页面回流。回流会使页面渲染从新进入布局节点,会将变化节点的子项及后项全部重新计算一遍。这给我们什么启示?如果页面中有动画,尽量往下放,往底部放,这里指在 HTML 标签中的位置。

image-20230602081007700

JS 是一种编译型语言,还是一种解释型语言?

什么是解释型语言?

在解释型语言中,代码自上而下运行,且实时返回运行结果。代码在由浏览器执行前,不需要将其转化为其他形式(二进制机器码)。代码将直接以文本格式(text form)被接收和处理。

什么是编译型语言?

编译型语言需要先将代码转化(编译)成另一种形式才能运行,比如 C/C++ 先被编译成汇编语言,然后才能由计算机运行。

这里有个问题,C++代码是被编译为了汇编代码,还是被编译为了机器码?这里的描述有没有问题?

计算机大厦是一级一级向上建起来的,早期 C++编译器甚至都是直接将 C++代码编译为 C 代码,然后直接扔给 C 编译器处理。不同 CPU 架构具有不同的指令集,因此汇编指令也不同;即使是同样的 CPU 架构,操作系统不同,可以复用的汇编语言代码集也是不同的。在 C/C++的编译过程中,先是将源代码编译为目标文件,这个目标文件依 CPU 架构不同、依系统不同,具有不同的汇编语言代码集,目标文件经过进一步链接,才变成了可执行文件。

image-20230602074439397

所以,上面讲“C/C++ 先被编译成汇编语言,然后才能由计算机运行”问题也不大,确定在中间状态编译为了汇编语言,只是中间少了一句“接着被连接为可执行文件”。

无论是解释型语言,还是编译型语言,最终在 CPU 中运行的,肯定都是只有 0 和 1 的机器码,两种类型的语言只是在不同程度上利用了系统能力。解释型语言比较懒惰,是直接将代码明文文本交给解释器,然后由解释器翻译成汇编代码或机器码,利用系统能力执行;编译型语言勤快一点,在执行之前就已经由编译器编译为了汇编代码,或机器码,或中间状态的字节码,最后由系统或运行时提供的能力完成执行。如果将两类语言的代码比作农民种植的稻谷,解释型语言是直接销售的带壳的稻子,编译型语言则是已经脱粒的稻子。

从这点看,编译型语言与解释型语言并无本质不同。

服务器端代码与客户端代码

这是一种普遍的 server-client 架构,在服务器上,由 PHP、Python、Ruby 等后端语言,输出一个 HTML 页面,由客户端主动请求,发送到客户端并在客户端浏览器上运行。

这种 Web 架构一般也称为 B/S 架构,其中 B 指 Browser,S 是 Server;另一种与 B/S 相对的架构是 C/S 架构,其中指 Client。

如果向 HTML 页面内添加 JS 代码?

内部

在页面内部直接使用 script 标签添加:

代码语言:javascript
复制
<script>
  // 在此编写 JS 代码
</script>

这和使用 style 标签在页面内添加样式代码是类似的:

代码语言:javascript
复制
<style>
  // 在此编写CSS代码
</style>
外部

对于外部的 js 文件,这样引入:

代码语言:javascript
复制
<script src="https://.../js-url.js" async></script>

async 标记表示这个网络资源不需阻塞主线程,因为是布尔标记,所以可以直接书写属性名称,而不必写值。对于布尔属性,标记即为 true,不标即为 false。

对于外部的样式代码,对比一下,可以这样引入:

代码语言:javascript
复制
<link rel="stylesheet" type="text/css" href="https://.../style-url.css"/>
内嵌

有一些简单的代码,可以直接写在 HTML 元素的属性上:

代码语言:javascript
复制
<button onclick="alert('hi')">按钮</button>

相对地,CSS 样式代码也可以直接写在 style 属性上:

代码语言:javascript
复制
<div style="background-color:#66CC99; color:#993300; height:30px; line-height:30px;">yishulun.com</div>

安全执行 JS 代码的时机

JS 代码一般要通过 DOM API 操作页面元素,有一个事件——DOMContentLoaded 可以帮助开发者确定 DOM API 百分百可用:

代码语言:javascript
复制
document.addEventListener("DOMContentLoaded", function({
  // JS代码
});

另一种简单的,但通常不被采纳的作法是:将 js 文件放在页面底部</body>标签前,这种方法是不可靠的,解析走到这里的时候,并不代表所有外网资源(js、style)已经加载完毕并且可用了。

这里有一个问题:DOMContentLoaded 是何时触发的,它在上面的浏览器解析流程中,是在哪个节点触发的?在 Render 树构建时触发的吗?

DOMContentLoaded 事件是 HTML 文档(包括 CSS、JS,但不包括多媒体资源例如图片、音频、视频、字体等)被加载以及解析完成之后触发。该事件的触发,与浏览器解析流程走到哪个节点,没有必要的关系,它有可能会触发在 First Paint(首次渲染)之前,也可能发生在它后面。

async 与 defer 的不同

默认情况下,script 标签加载外网 js 文件,是会阻塞页面解析的。

但如果添加了 async 标记,js 文件便不会阻塞 HTML 的解析,js 文件开始异步加载(async 是异步的意思),同时 HTML 继续向后解析,待 js 文件加载完成后,js 文件执行,这个时候 HTML 有可能解析完,也有可能没有解析完。

如果页面中有三个外网 js 文件:

代码语言:javascript
复制
<script async src="https://.../js/script1.js"></script>
<script async src="https://.../js/script2.js"></script>
<script async src="https://.../js/script3.js"></script>

它们都使用了 async 异步标记,但它们加载完成的时间点和执行的先后是无法确定的。

为了解决这个问题,defer 标记诞生了,该标记会按出现的顺序依次延迟脚本的执行,并且会在页面解析完成后执行,但仍然不会阻塞页面的解析。例如:

代码语言:javascript
复制
<script defer src="https://.../js/script1.js"></script>
<script defer src="https://.../js/script2.js"></script>
<script defer src="https://.../js/script3.js"></script>

这三个文件会先执行 script1,最后执行的是 script3。

脚本调用策略小结:

  • 如果脚本无需等待页面解析,且无依赖独立运行,那么应使用 async。(async 加载完就会执行,不会管 DOM API 是否可用。)
  • 如果脚本需要等待页面解析,且依赖于其他脚本,调用这些脚本时应使用 defer,将关联的脚本按所需顺序置于 HTML 中。

补充一条:使用 DOMContentLoaded 事件检测 DOM 树是否可用,是一个好习惯,但并不是在所有情况下都需要这样做。实现开发中,许多程序员懒惰,统一都是在.ready()中写起始代码的。(注:.ready()是 jQuery 类库中的一个方法,代表页面 DOM 树可用。)

JS 代码中的注释

分为两类,单行注释与多行注释:

代码语言:javascript
复制
// 单行注释
/*
  多行
  注释
*/

JS 的多行注释并不要求在中间每行都写一个星号,这一点还是比较友好的。

- End -

小步快跑,正向反馈;面向未来,不求完美。

与时间做朋友,一同成长。

声明:本文纯人工编写

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2023-06-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 艺述论 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 如何理解“结构化”?
  • 如何理解“样式规则”?
  • JS 能干什么事?
  • 当浏览器加载一个 URL 地址时发生了什么事?
  • JS 是一种编译型语言,还是一种解释型语言?
  • 服务器端代码与客户端代码
  • 如果向 HTML 页面内添加 JS 代码?
    • 内部
      • 外部
        • 内嵌
        • 安全执行 JS 代码的时机
        • async 与 defer 的不同
        • JS 代码中的注释
        相关产品与服务
        云开发 CloudBase
        云开发(Tencent CloudBase,TCB)是腾讯云提供的云原生一体化开发环境和工具平台,为200万+企业和开发者提供高可用、自动弹性扩缩的后端云服务,可用于云端一体化开发多种端应用(小程序、公众号、Web 应用等),避免了应用开发过程中繁琐的服务器搭建及运维,开发者可以专注于业务逻辑的实现,开发门槛更低,效率更高。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档