JavaScript基础(一)

1. js在浏览器中的执行过程

我们首先要知道的是,浏览器内核包含以下两部分:
渲染引擎:解析HTML和CSS,渲染网页代码,页面生成以后的脚本操作和样式表操作会触发“重流”和“重绘”。
js引擎:又叫“js解释器”,读取js代码并处理运行,具体做了什么我们后面会说。
注:两个引擎各自的运行都是单线程的,同时浏览器中两个引擎也具有互斥性,在同一时刻只有一个引擎运行。

· 浏览器的渲染过程

  简单概括,浏览器先读取并解析HTML,生成DOM树,在这一过程中,如果遇到外部资源,就加载并解析外部资源,包括CSS和JS等资源。但是外部资源又分为阻塞资源非阻塞资源,在请求和解析非阻塞资源(CSS、图片)的时候,浏览器不会停止原本HTML的解析,但会组织页面渲染;而当遇到阻塞资源(js)的时候,便会阻塞页面渲染,暂停HTML的解析。

然后我们来看

· 浏览器的渲染过程浏览器请求和解析js资源

请求到js资源之后,浏览器本身不会执行js代码,而是通过js引擎来执行。js引擎对js语言逐句进行识别、解释、转换、执行,也因此js是一种脚本语言。不过这种逐句解释执行的方式速度相对较慢,如今大部分浏览器为了提高运行速度,都会对js进行一定程度的编译,生成类似于字节码的中间代码,然后运行在虚拟机上。
(可以理解为,js引擎并不是一个简单的解释器,还担任了一个虚拟机的角色)

2. js脚本调用策略

   脚本的调用时机很重要,为什么这么说?
   要知道,HTML是顺序执行的。如果我们使用DOM操作元素,就要特别注意javascript的调用顺序了,否则一不小心就会出现 Uncaught TypeError,提示找不到目标元素,因为在我们操作元素的时候它还没有被加载。
   那么解决办法都有哪些呢?
   如果是调用内部js,即js代码写在当前html文档中:

  1. 可以将js代码写在文档底部,body的结束标签之前,这样就可以在整个页面加载完成之后才加载js代码;
  2. js代码也可以写在头部,通过事件监听器,监听页面文档加载完成,举个例子:
<head>
    <meta charset="utf-8">
    <title>使用 JavaScript 的示例</title>
    <script>
      document.addEventListener("DOMContentLoaded", function() {
        function createParagraph() {
          let para = document.createElement('p');
          para.textContent = '你点击了这个按钮!';
          document.body.appendChild(para);
        }

        let button = document.getElementById('btn')
        button.addEventListener('click', createParagraph)
      });
    </script>
  </head>
  <body>
    <button id="btn">点我呀</button>
  </body>

上边这段代码,如果不监听DOMContentLoaded事件,就会报错,原因前边已经说过了。
   如果是调用外部js,正常情况下也是按照顺序加载,不过我们还可以通过JavaScript的async和defer关键字来控制调用顺序。

  1. async:异步调用外部js文件,遇到即下载,下载完即运行,不会阻塞页面渲染进程,但是运行顺序不确定。适用于多个外部js文件互相独立,且不依赖本页面其它任何脚本的情况。
  2. defer:应用该属性的js文件会自动等待页面解析完成之后按照顺序进行调用。如果脚本需要等待页面解析,且依赖于其它脚本,调用这些脚本时应使用 defer,将关联的脚本按所需顺序置于 HTML 中。

3.js变量

变量又叫标识符,是值的一个符号名,或者说是一个容器。其本质就是在内存开辟一块空间来存储数据,变量本身不是数据。

·数据类型

最新的ECMAScript规定了七种基本数据类型和一种复杂数据类型。
基本数据类型: null,undefined,Number,String,Boolean,BigInt,Symbol
复杂数据类型:Object

·变量的声明

var:声明全局变量和局部变量
let:声明块作用域的局部变量
const:声明一个只读变量(常量)

·变量的作用域

全局变量: 在函数之外声明的变量,可被文档中任何其他代码访问
局部变量: 在函数内部声明的变量,只能在当前函数内部使用

·变量提升

什么是变量提升?
js中可以先使用变量再声明变量,这样并不会发生异常。但是,提升的只是变量的声明,不包括赋值,怎么理解呢?举个栗子~

var foo = 1;
function func() {
    console.log(foo);
    var foo = 2;
}
func();

以上这段代码的执行结果是 undefined,它就可以等同于:

var foo = 1;
 function func() {
    var foo;
    console.log(foo);
    foo = 2;
}
func();

注:let和const声明的变量也有变量提升,不过并不会给默认的undefined值,而是会抛出引用错误(ReferenceError)

·函数提升

对于函数来说,只有函数声明可以提升,函数表达式不可以提升,首先要分清函数声明和函数表达式。

// 函数声明
func();
function func() {
   console.log(2); //输出2
}
// 函数表达式
func();
var func = function() {
   console.log(2); //Uncaught TypeError: func is not a function
}

其实很容易理解,函数表达式中,后声明的函数只会提升声明部分,func返回值不是定义的function而是undefined。


2023-01-17 增加

console.log(a) //打印结果1:ƒ a() {console.log('a')}
function a() {
  console.log('a')
}
var a = 1
console.log(a) //打印结果2:ƒ a() {console.log('b')}
function a() {
  console.log('a')
}
var a = 1
function a() {
  console.log('b')
}

分析上面两段变量提升的代码,比较两个打印结果,发现了什么?
结合js的解析流程深入了解一下这个变量提升的过程:

  1. 遇到函数声明 function a ,放入 VO(variable object,全局执行上下文中的变量对象) ,并且让其初始值为 undefined。
  2. 遇到 var a ,准备放入 VO ,结果发现 VO 已经存在同名变量,跳过。
  3. 再次遇到 function a,准备放入 VO ,结果发现 VO 已经存在同名变量,覆盖。

由此可见,当存在同名的var声明和function声明的变量时,存在一个优先级,函数声明优先级要高一些。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值