从本篇博客起,小编将会不断的更新这个新的专栏 — 面试集合
更新一些常见的面试题,感兴趣的小伙伴点个订阅。
接下来的内容将会围绕下面这个表格进行讲解。
关键字 | 块级作用域 | 变量提升 | 重新赋值 | 声明同名变量 | 是否推荐使用 |
---|---|---|---|---|---|
var | ✖ | ✔ | ✔ | ✔ | ✖ |
let | ✔ | ✖ | ✔ | ✖ | ✔ |
const | ✔ | ✖ | ✖ | ✖ | ✔ |
使用var声明变量会自动被添加到最接近的环境中。在函数内部,最接近的环境就是函数的局部环境;如果初始化变量时没有使用var声明,该变量就会自动被添加到全局作用域,如下案例。
function add(num1,num2){
// 函数作用域
var sum = num1+num2;
return sum ;
}
var result =add(10,20); // 30
alert(sum); // 由于不是有效的变脸因此会发生报错
以上代码的函数定义了一个名为sum的局部变量,该变量包含加法操作的结果。虽然结果值从函数中返回了,但变量sum在函数的外部是访问不到的,如果省略这个例子中的var关键字,那么add()执行完毕后,sum将可以被访问到。
function add(num1,num2){
// 函数作用域
sum = num1+num2;
return sum ;
}
var result =add(10,20); // 30
alert(sum); // 输出 30
javascrpit没有块级作用域常常会导致理解上面的困惑。在其它一些语言中由花括号“{}”封闭的代码都有自己的作用域,因而支持根据业务条件来定义变量。
// 全局作用域
var hello = "hello"
function fn(){
// 函数作用域
}
{
// 块级作用域
var world = "world"
// 按照常规外部是无法访问这个块级作用域的 和外界是隔离的
// 但是 var 是没有块级作用域的 所以外部也能访问
}
console.log(world); // 输出 world
// 常见场景
for(var i=0; i<5; i++){
console.log('循环内部-->', i);
// 这里是一个块级作用域
// 也是一个块级作用域 上面是var声明的证明循环外部也能访问 相当于一个全局变量
// 这里使用let 声明的话外面就无法访问
}
console.log(i); // 输出 5
// 包括在if{}
if(true){
// 这也是一个块级作用域
// 表达式是true的话这个代码块是会执行的 而var没有块级作用域所以外部能访问到
// 如果是false的话这个代码块是不会执行的,但是由于var没有块级作用域下面还是会输出undefined
// 不执行只是不会进行初始化 但是变量是已经声明了的
var b="牛马"
}
console.log(b); // 输出 牛马
变量提升是指无论 var 出现在一个作用域的哪个位置,这个声明都属于当前的整个作用域,在其中到处都可以访问到。注意只有变量声明才会提升,对变量赋值并不会提升。如下例所示
console.log(a);//在这之前根本没有声明过变量但是由于变量提升还是输出 undefined
var a = 1;
var b;
console.log(b);//变量声明了但是未进行初始化输出 undefined
b = 1;
// 而如果对未声明过的变量进行操作,就会报错
console.log(c);//c未声明过发生报错,Uncaught ReferenceError: b is not defined
var关键字并不像 const 关键字,声明的变量初始化之后就不可以重新赋值了,var声明的变量是可以重新进行赋值的。
var hello = 2;
hello = 3;
alert(hello); // 3
为什么var可以重复声明,因为编辑器会在判断有已经声明的同名变量时忽略var,然后直接进行赋值。
//var 关键字可以声明同名变量,实际第二次声明是对第一次声明的变量重新赋值
var num = 10;
var num = 20;
console.log(num); // 20
// 声明变量时也可先不对其进行初始化
var num1
num1=30
console.log(num1); // 输出 30
当执行上面的代码时,我们可以简单的理解为新变量分配一块儿内存,命名为num并赋值为1,但在运行的时候编译器与引擎还会进行两项额外的操作,判断变量是否已经声明
如果重复声明
,则首先编译器会对代码进行分析拆解,从左至右遇见var a,则编译器会询问作用域是否已经存在叫a的变量了。如果不存在,则在作用域声明一个新的变量a,若已经存在,则忽略 var 继续向下编译,这时 num = 20(相当于重新赋值)被编译成可执行的代码供引擎使用。
// 值得注意的是
//var关键字可以重复声明同名变量,但是之前的变量时let或者const关键字声明的还是会发生报错
let num = 20 // 发出语法错误
var num = 20 // 发出语法错误
console.log(num); // 强行执行还是会发生报错
const num = 20 // 发出语法错误
var num = 20 // 发出语法错误
console.log(num); // 强行执行还是会发生报错
let是ES6新增的关键字,存在块级作用域,且声明的变量可以重新赋值,但是是不能使用let声明同名的变量的关于一些其他细节下面会介绍到,还是比较推荐使用。
let是存在块级作用域的,即let 声明的变量只在 let 命令所在的代码块内有效,还是以上面的一个例子来演示。
// 全局作用域
let hello = "hello"
function fn(){
// 函数作用域
}
{
// 块级作用域
let let_world ="world"
}
console.log(let_world); // 结果发生报错 因为let有块级作用域外部无法访问
// 常见场景
for(let i=0; i<5; i++){
console.log('循环内部-->', i);
// 也是一个块级作用域
}
console.log(i); // 发生报错
// 包括在if{}
if(true){
// 这也是一个块级作用域
// 表达式是true的话这个代码块是会执行的 而var没有块级作用域所以外部能访问到
// 如果表达式是false的话这个代码块是不会执行的 由于let有块级作用域下面会直接报错
let b="牛马"
}
console.log(b); // 发生报错 因为let存在块级作用域 外部无法访问
let并不存在变量提升,即只有变量在当前作用域内声明后才可以访问,也并没有赋值提升。
console.log(a);//变量未声明 发生报错 ReferenceError
let a = 1;
var b;
console.log(b);// 声明了但是未初始化输出 undefined
b = 1;
let关键字和var关键字一样,声明的变量都是可以进行重新赋值的
let a =1
a=2
console.log(a); // 输出 2
// 声明时也可以先不用对其初始化
let b
b = 2
console.log(b); // 输出 2
虽然let关键字声明的变量可以重新赋值但是,并不能声明同名的变量否则会发生报错
let a = 1;
// 会直接报出语法错误
let a = 2;//Uncaught SyntaxError: Identifier 'a' has already been declared
//let 关键字不能重复声明同名变量,即使之前是用var声明的也会报错
var num2 = 10;
let num2 = 20; // Uncaught SyntaxError: Identifier 'num2' has already been declared
const 是ES6新增的关键字,是用来声明一个常量的,其声明变量时必须对其进行初始化,标识符一般为大写,且初始化后值不允许修改,比较常用,关于其他细节下面会介绍到。
const关键字和let关键字一样都有块级作用域,还是用上面的一个案例来演示
// 全局作用域
var HELLO = "hello"
function fn(){
// 函数作用域
}
{
// 块级作用域
// const 没有块级作用域所以外部无法访问
const CONST_WORLD="world"
}
console.log(CONST_WORLD); // 结果发生报错
// 包括在if{}
if(true){
// 这也是一个块级作用域
// 表达式是true的话这个代码块是会执行的 而var没有块级作用域所以外部能访问到
// 如果表达式是false的话这个代码块是不会执行的 因为const声明的变量没有块级作用域所以外部无法访问
const B="牛马"
}
console.log(B); // 发生报错 当前作用域并没有这个变量
和let关键字一样const关键字是没有变量提升的,只有在当前作用域声明了才可以进行访问,否则将会发生报错,但是不同的是const关键字声明变量时必须对其进行初始化,且初始化后就不能对其值进行修改了。
console.log(A);//变量未声明 发生报错 ReferenceError
const A = 1;
const b; // 爆出语法错误
console.log(b); // 强行执行发生报错,声明变量时必须对其进行初始化
b = 1;
重新赋值的特性感觉都不用过多介绍了,let,var都是用来声明变量的显然都是可以进行重新赋值的,而关键字const是用来定义一个常量或者若干个常量的,且在定于的时候必须进行初始化,且初始化完成后就不能够被修改了
// 错误写法 定义常量时必须进行初始化
const PI;
PI = "world";
// 常量值无法被修改(或者说是重新赋值)
cnost HELLO = "hello"
HELLO = "world" // 爆出语法错误
consoel.log(hello) // 强行执行后发生报错
但是并不是说常量的值就不能够被改变了,准确的说,是 const 声明创建一个值的只读引用。但这并不意味着它所持有的值是不可变的,只是变量标识符不能重新分配。
// 下面代码都是可以正常执行的
// 创建常量对象
const CAR = {name:"小明", age:"180", hobby:"喝酒"};
// 修改属性:
CAR.hobby = "敲代码";
// 添加属性
CAR.like = "小红";
// 创建常量数组
const CARS = ["js", "html", "css"];
// 修改元素
CARS[0] = "java";
// 添加元素
CARS.push("go");
const 声明的变量如果是基本类型,那么不允许改变,如果是引用类型,那么只要不改变引用的地址就是可以的。也就是说其实const保证的并不是变量的值不动,而是变量指向的内存地址不得改动。
const关键字和let关键字一样是不允许声明同名的变量的
const X = 2; // 发生语法错误
const x = 3; // 发生语法错误
//const 关键字不能重复声明同名变量,即使之前是用var声明的也会报错
var Y = 2;
const Y = 2;
console.log(Y); // 发生报错
// 如果之前是let关键词定义的变量,也会发生报错
let Y1 = 2; // 发生语法错误
const Y1 = 2; // 发生语法错误
console.log(Y1); // 强行执行会发生报错
那么本篇博客的内容就到此结束了,不经感叹小编真是个够细的男人,如果有需要补充或者错误的地方还请各位读者姥爷们在评论区提出,小编一定及时对其进行修改,后续本专栏也将会推出更多的面试常考的知识点讲解,期待的小伙伴不妨点个订阅。