JS当中的变量提升(预解析)
函数和变量声明的提升
在JS中存在一个很重要的特性,函数和变量声明的提升,理解这一点对于理解我们编写的代码非常有帮助,那么什么是声明的提升呢?我们通过下面的代码来分析。
console.log(a);
//①
var a = 123;
console.log(a);
//②console.log(f);
//③
f();
//④
function f() {
console.log("函数声明提升");
}
①处的代码如果按照我们以前的理解,代码从上而下执行,那么在执行这行代码的时候,a还没有被声明,所以直接访问一个没有被声明的变量,程序应该报错。
但是结果却大出所料,这里得到的结果是undefined。
③处的结果也和我们最初的认识是不一样的,结果为f对应的函数对象。
造成这个结果是因为变量和函数的作用域提升的原因,什么意思呢?
JS是解释性语言,JS引擎对代码的处理分为两步:
? 预解析处理:在代码执行之前,对代码做全局扫描,对代码中出现的变量或者函数提前声明处理;
? 解析之后我们的代码:
var a;
//提前声明,但不初始化
console.log(a);
//undefined
a = 123;
console.log(a);
//123//提前声明
function f() {
console.log("函数声明提升");
}
console.log(f);
//函数对象
f();
//函数声明提升
? 调用执行:自上而下的执行代码
变量提升和作用域的关系 题1:
f();
function f() {
console.log("1");
}
f();
function f() {
console.log("2");
}
f();
function f() {
console.log("3");
}
根据前面对函数声明提升的认识,结果三次都是 “3”。
预解析之后的代码:
function f() {
console.log("3");
}
f();
f();
f();
为什么解析之后只剩下一个函数,而且是最后那一个?
因为三个函数的名称一样,后面的函数会将前面的覆盖,所以最后只剩下最后一个函数了。
题2:
console.log(a);
var a = 123;
console.log(a);
function f1() {
console.log(a);
var a = 456;
console.log(a);
}
f1();
console.log(a);
直接先对代码做预解析,然后再做分析。
var a;
//变量声明提升
function f1() {//函数声明提升
var a;
//变量声明提升
console.log(a);
a = 456;
console.log(a);
}
console.log(a);
a = 123;
console.log(a);
f1();
console.log(a);
解析得到上面的代码结果就非常明显了,分别是:undefined 123 undefined 456 123
由于在函数内部有变量a,所以在函数中访问到的是这个局部变量,如果在函数作用域中没有变量a,那么就会跳出函数作用域来到全局作用域来查找。
声明提升的规则 声明提升是将变量或者函数的声明提升到当前作用域的最顶端。在具体使用的过程中存在以下需要注意的细节。
- 变量和变量同名,解析之后只存在一个当前变量的声明
console.log(a);
var a = 123;
console.log(a);
var a = 456;
console.log(a);
解析之后:
var a;
console.log(a);
//undefined
a = 123;
console.log(a);
//123
a = 456;
console.log(a);
//456
- 函数和函数同名,后面的声明将前面的覆盖
f();
function f() {
console.log("1");
}
f();
function f() {
console.log("2");
}
f();
function f() {
console.log("3");
}
解析之后:
function f() {
console.log("3");
}
f();
//3
f();
//3
f();
//3
- 函数和变量同名,函数声明提升,忽略变量的声明
console.log(a);
var a = 123;
console.log(a);
function a() {}
console.log(a);
function a() {}
console.log(a);
解析之后:
function a() {}
console.log(a);
//函数a
var a = 123;
//将前面的函数覆盖,a的值变为123
console.log(a);
//123
console.log(a);
//123
console.log(a);
//123
- 如果是命名函数,则只将前面的变量声明提升,函数不动。
console.log(fn1);
function fn1() {
}
console.log(fn1);
console.log(fn2);
var fn2 = function () {
}
console.log(fn2);
解析之后:
function fn1() {
}
var fn2;
console.log(fn1);
//fn1函数
console.log(fn2);
//undefined
fn2 = function () {
}
console.log(fn2);
//fn2函数
面试题1:
console.log(a,b);
//undefined undefined
var a=12;
var b=13;
sum();
//1
function sum(){
console.log(1);
}
面试题2:
console.log(a);
//undefined
var a=12;
function fn(){
console.log(a);
//undefined
var a=13;
}
fn();
console.log(a);
//12
面试题3:
console.log(a);
//undefined
var a=12;
function fn(){
console.log(a);
//12
a=13;
}
fn();
console.log(a)//13
面试题4:
console.log(a);
//这个就直接报错了,因为没有变量提升 a is not defined
a=12;
function fn(){
console.log(a);
var a = 13;
}
fn();
console.log(a)
面试题5:
var foo=1;
function bar(){
//不管条件是否成立,都要进行变量提升
//这时的foo属于私有变量 给的默认值是undefined,undefined取反就为真
if(!foo){
var foo=10;
}
console.log(foo);
}
bar();
//10
面试题6:
var n=13;
function fn(n) {
alert(n);
// 13
var n=14;
//有形参赋值了,就不在走变量提升了
alert(n);
// 14
}
fn(n);
console.log(n);
//13
面试题7:
console.log(a);
// undefined
a=12;
function fn(a) {
console.log(a);
//undefined
a=13;
}
fn();
//注意这里没有传值
var a;
console.log(a);
//12
面试题8:
function f1() {
if("a" in window){//带var的变量提升时不看条件成立不成立的都会提升。
var a = 10;
//函数体中声明的变量是局部变量 所以不在window
}
console.log(a);
//undefined
}
f1();
面试题9:
if(!"a" in window){//使用var声明的全局变量会变成window成员。
var a = 10;
}
console.log(a);
//undefined
面试题10:
console.log(a, b, c);
// undefined undefined undefined
var a=10,b=20,c=30;
function f(a) {
console.log(a, b, c);
// 10 undefined 30
var b=a=c=100;
//a 和 b 是局部变量,只有c是全局变量
console.log(a, b, c);
//100 100 100
}
f(10,20);
console.log(a, b, c);
// 10,20,100
面试题11:
function foo() {
var num = 123;
console.log(num);
//123
}
foo();
console.log(num);
//报错num is not defined
面试题12:
var scope = "global";
foo();
function foo() {
console.log(scope);
//undefined
var scope = "local";
console.log(scope);
//local
}
面试题13:
var foo = 1;
function bar() {
if(!foo){//foo变量提升完是undefined取反条件成立
var foo = 10;
}
console.log(foo);
//10
}
bar();
console.log(foo);
//1
【JS当中的变量提升(预解析)】面试题14:
var arr = [1,2,3,4];
function fun(arr) {
arr[0] = 5;
arr = [0];
//arr开辟了一个新的地址,指针指向改变
arr[0] = 6;
console.log(arr);
//[6]
return arr
}
var res = fun(arr);
console.log(res);
//[6]
console.log(arr);
//[5,2,3,4]
推荐阅读
- 热闹中的孤独
- Shell-Bash变量与运算符
- JS中的各种宽高度定义及其应用
- 我眼中的佛系经纪人
- 《魔法科高中的劣等生》第26卷(Invasion篇)发售
- Android中的AES加密-下
- (二)ES6第一节变量(let|(二)ES6第一节变量(let,const)
- 放下心中的偶像包袱吧
- C语言字符函数中的isalnum()和iscntrl()你都知道吗
- C语言浮点函数中的modf和fmod详解