1. var、let区别
1.1 在JavaScript中定义变量有两种方式
ES6之前: var 变量名称
ES6开始: let 变量名称
注意点:只要出现了let, 在相同的作用域内, 就不能出现同名的变量
let num = 123
var num = 456
var num = 123
let num = 456
1.2 var和let的区别:
1. 是否能够定义同名变量
通过var定义变量,可以重复定义同名的变量,并且后定义的会覆盖先定义的
var num = 123
var num = 456
console.log(num)
如果通过let定义变量, "相同作用域内"不可以重复定义同名的变量
let num = 123
let num = 456
2. 是否能够先使用后定义
通过var定义变量, 可以先使用后定义(预解析)
console.log(num)
var num = 123
通过let定义变量, 不可以先使用再定义(不会预解析)
console.log(num)
let num = 123
3 是否能被{}限制作用域
无论是var还是let定义在{}外面都是全局变量
var num = 123
let num = 123
将var定义的变量放到一个单独的{}里面, 还是一个全局变量
{
//块级作用域
var num = 123
}
console.log(num)
将let定义的变量放到一个单独的{}里面, 是一个局部变量
{
//块级作用域
let num = 123
}
console.log(num)
2. 作用域
2.1 在JavaScript中{}外面的作用域, 我们称之为全局作用域。
var num = 456;
console.log(num);
2.2 在JavaScript中函数后面{}中的的作用域, 我们称之为"局部作用域"。
function say() {
}
2.3 在ES6中只要{}没有和函数结合在一起, 那么称之为"块级作用域"。
for(;;){
}
2.4 块级作用域和局部作用域区别:
1. 在块级作用域中通过var定义的变量是全局变量
2. 在局部作用域中通过var定义的变量是局部变量
2.5 无论是在块级作用域还是在局部作用域, 省略变量前面的let或者var就会变成一个全局变量
function test() {
var num1 = 123;
let num2 = 123;
num3 = 123;
}
test();
console.log(num1);
console.log(num2);
console.log(num3);
{
var num1 = 123;
let num2 = 123;
num3 = 123;
}
console.log(num1);
console.log(num2);
console.log(num3);
2.6 注意点: 在不同的作用域范围内, 是可以出现同名的变量的
{
let num = 123;
{
let num = 456;
}
}
3. 作用域链
3.1 注意点: 初学者在研究"作用域链"的时候最好将ES6之前和ES6分开研究。
3.2 ES6之前需要明确:
1. ES6之前定义变量通过var
2. ES6之前没有块级作用域, 只有全局作用域和局部作用域
3. ES6之前函数大括号外的都是全局作用域
4. ES6之前函数大括号中的都是局部作用域
3.3 ES6之前作用域链
1. 全局作用域我们又称之为0级作用域
2. 定义函数开启的作用域就是1级/2级/3级/...作用域
3. JavaScript会将这些作用域链接在一起形成一个链条, 这个链条就是作用域链
0 ---> 1 ----> 2 ----> 3 ----> 4
4. 除0级作用域以外, 当前作用域级别等于上一级+1
3.4 变量在作用域链查找规则:
1. 先在当前找, 找到就使用当前作用域找到的
2. 如果当前作用域中没有找到, 就去上一级作用域中查找
3. 以此类推直到0级为止, 如果0级作用域还没找到, 就报错
3.5
var num = 123;
function demo() {
var num = 456;
function test() {
var num = 789;
console.log(num);
}
test();
}
demo();
3.6 ES6需要明确:
1. ES6定义变量通过let
2. ES6除了全局作用域、局部作用域以外, 还新增了块级作用域
3. ES6虽然新增了块级作用域, 但是通过let定义变量并无差异(都是局部变量)
3.7 ES6作用域链
1. 全局作用域我们又称之为0级作用域
2. 定义函数或者代码块都会开启的作用域就是1级/2级/3级/...作用域
3. JavaScript会将这些作用域链接在一起形成一个链条, 这个链条就是作用域链
0 ---> 1 ----> 2 ----> 3 ----> 4
4. 除0级作用域以外, 当前作用域级别等于上一级+1
3.8 变量在作用域链查找规则
1. 先在当前找, 找到就使用当前作用域找到的
2. 如果当前作用域中没有找到, 就去上一级作用域中查找
3. 以此类推直到0级为止, 如果0级作用域还没找到, 就报错
3.9
let num = 123;
{
let num = 456;
function test() {
let num = 789;
console.log(num);
}
test();
}
4. 预解析
4.1 什么是预解析?
浏览器在执行JS代码的时候会分成两部分操作:
预解析以及逐行执行代码也就是说浏览器不会直接执行代码, 而是加工处理之后再执行,
这个加工处理的过程, 我们就称之为预解析。
4.2 预解析规则:
1. 将变量声明和函数声明提升到当前作用域最前面
2. 将剩余代码按照书写顺序依次放到后面
4.3 注意点:
通过let定义的变量不会被提升(不会被预解析)
4.4 函数预解析
注意点: 1. 如果变量名称和函数名称同名, 那么函数的优先级高于变量,
一定要记住, 在企业开发中千万不要让变量名称和函数名称重名。
2. 在高级浏览器中, 不会对{}中定义的函数进行提升
3. 只有在低级浏览器中, 才会按照正常的方式解析
1. es6之前函数:
//函数是可以预解析的
demo()
function demo(){
console.log(123)
}
say()
var say = function(){
console.log(456)
}
3. es6函数
test()
let test = () =>{
console.log(789)
}
例子:1.
if(true){
function demo() {
console.log("hello demo1111111111");
}
}else{
function demo() {
console.log("hello demo2222222222");
}
}
demo();
预解析后:
function demo() {
console.log("hello demo1111111111");
}
function demo() {
console.log("hello demo2222222222");
}
if(true){}else{}
demo();
2.
console.log(value);
var value = 123;
function value() {
console.log("fn value");
}
console.log(value);
预解析后:
function value() {
console.log("fn value");
}
console.log(value);
var value;
value = 123;
console.log(value);