作用域
- 变量在某个范围内起作用,目的是提高程序的可靠性并减少命名冲突
- js作用域分为全局作用域和局部作用域
- 全局作用域 : 直接写在< script>中的js代码都在全局作用域
- 全局作用域在页面打卡时创建,页面关闭时销毁
- 全局对象window代表一个浏览器窗口
- 在全局作用域中,创建的属性都会作为window对象的属性,即变量a等价于window.a
- 特殊情况:函数中为使用var声明的变量默认为全局变量
- 局部作用域 :在函数中定义的变量
- 函数执行时创建,执行完成后销毁
- 特殊情况:函数的形参
预解析
- JavaScript代码是由浏览器中的JavaScript解析器来解析的
- 解析器执行时分为两步:①预解析 ②代码执行
- 代码执行:按代码书写顺序从上到下执行
- 预解析:js引擎会吧js中所有用var声明的变量和用function声明的函数声明提前
- 预解析分为:变量提升和函数提升
- 变量提升:使用var关键字声明的变量会在所有代码执行之前被声明,但不会赋值
- 若为var声明,则声明不会被提前
- 使用函数声明形式创建的函数 function 函数名(){函数体}会被提前,会在所有代码执行之前被创建,可在声明函数的代码之前运行不报错,但使用函数表达式创建的函数不会被提前 var 变量名 = function(){函数体}
- var的创建和初始化被提升,赋值不会被提升。
let的创建被提升,初始化和赋值不会被提升。
function的创建、初始化和赋值均会被提升。
下面有一个例子可以自己理解一下
fn();
console.log(a);
console.log(b);
console.log(c);
function fn(){
var a=b=c=9;
console.log(a);
console.log(b);
console.log(c);
}
执行结果是:999报错99
分析过程如下:
//声明提升后的代码
function fn(){
var a;
a=b=c=9;//这里b和c都未用var声明
console.log(a);//9
console.log(b);//9
console.log(c);//9
}
fn();
console.log(a);//为在全局作用域中声明,报错后面的代码不执行
console.log(b);//9
console.log(c);//9
JS执行机制
- js语言的一大特点就是单线程
- js的执行分为同步和异步
- 同步:前一个任务执行结束后再执行下一个任务
- 异步:不按代码顺序执行
举个例子理解一下:
console.log(a);
setTimeout(function(){
console.log(c);
},3000);
console.log(b);
执行结果为abc,因为延时器的回调函数是异步任务,后面将详细讲述
- 同步任务:在住线上执行,形成一个执行栈
- 异步任务:通过回调函数实现,有以下三种类型①普通事件,如click、resize等②资源加载,如load、error等③定时器,如setTimeout和setInterval
- 异步任务相关回调函数添加到任务队列(消息队列)中
console.log(1);
setTimeout(function(){
console.log(3);
},0);
console.log(2);
这里明明演示器并没有延时,单输出结果仍为abc,是由于setTimeout的回调函数进了消息队列
JS执行机制
- 先执行执行栈中的同步任务
- 异步任务放入任务队列
- 一旦执行栈的所有同步任务都执行完毕了之后,系统会按照顺序读取任务队列中的异步任务,于是读取到的异步任务结束等待状态进入执行栈,开始执行;重复
下面举一个列子:
console.log(1);
document.onclick=function(){
console.log('click');
};
console.log(2);
setTimeout(function(){
console(3);
},3000);
这个例子有两个异步任务,代码执行到点击事件时,进行异步进程处理,若发生了点击事件就进入消息队列,若未发生点击事件就不进消息队列;代码执行到延时器时,过了3秒后就进入消息队列,等到执行栈中的同步任务执行后从消息队列中读取任务,然后事件循环(这里事件循环主要指的是点击一次点击事件回调函数进入一次消息队列,然后被推入执行栈执行)