面试-搬砖到城堡3:变量提升(Hositing)

147 阅读3分钟

变量提升(hositing)

1. 变量提升

  • 变量提升简单来说就是,先声明再赋值 先来用一个简单的栗子来说明
console.log(a); // undefined
var a = 0;

你没有看错,没有报错并且打印了undefined。

为什么在定义变量之前使用了变量还没有报错?这就是使用var声明的变量被提升到了代码的顶部,并且JS的代码执行是由上到下的,所以以上的代码可以被分解为:

var a;
console.log(a); // undefined
a = 0; 

了解基本原理了吗?可以试着看一道面试题

var a=1;

(function(){
  alert(a);
  var a=2;
}())

是不是以为弹出了:1

弹窗执行结果是:undefined

这里有作用域的知识点,在js中,只有函数才会创建新的作用域,所以以上的代码可以分解为。

var a = 1;  // 跟这个没关系了
// 此处构成了独自的作用域
(function(){
    var a; // 优先自己作用域内的变量
    alert(a); // undefined
    a = 2;
}())

2. 函数提升

f();
function f() {
    console.log('fff');
}
// 会正常打印 fff

其实和变量提升是一个道理,声明的函数会被直接提升到头部,上面的代码可以分解为:

function f() {
    console.log('fff');
}
f();

那如果当var声明的变量和函数命名相同的时候会怎么样呢?看一个栗子:

console.log(a);
var a = 1;
function a() {}
console.log(a);

打印结果: f a() {} 和 1 ,虽然看起来有点绕,但是分解下代码就可以很清晰

var a; // 先出现先被提升到头部
function a() {}; // 覆盖变量a变为函数
console.log(a); // 此时a已经变成了 function a() {}
a = 1; // a 被重新赋值
console.log(a); // 1

变量提升也是有顺序的,按代码的执行顺序一个个提升到头部,就形成了上面的代码

2.2 函数表达式

函数表达式其实可以照做变量提升来看,并不会直接将函数提升到的顶部,相当于直接给变量赋值一个匿名函数。

// 可以这样实验一下
console.log(a);
var a = function() {}
// 拆解一下就是
var a;
console.log(a); // 打印了 undefined, 是不是与上面的变量提升一致
a = function(){}

经过上面的学习,最后用一到面试题校验自己的成果吧。

var global='global context';
var inner='global inner context';
function box(num){
    console.log(global);
    console.log(inner);
    var inner='inner context';
    console.log(inner);  
    num+=10;
    return num;
}
var num=5; 
var result=box(num);
console.log(result);
console.log(num);

来一起动手动脑分析和分解下:

var global='global context';
var inner='global inner context';
function box(num){
    var inner;
    console.log(global); //函数内部无global变量,向上级查找global变量
    console.log(inner);  //函数内部有inner变量,undefined
    inner='inner context';
    console.log(inner);  // 局部变量inner被赋值,打印 inner context
    num+=10; // 这里对函数的传参num进行计算,相当于被声明了局部变量,而不是全局变量num被重新赋值
    return num; 
}
var num=5; 
var result=box(num); // 传入函数里的是num的副本而不是全局变量num本身,因此在函数里面修改参数值并不会对实参num造成影响
console.log(result); // 返回15;
console.log(num); // 依然是5