Skip to content

JS 中的变量提升和函数提升

变量提升

  • 在作用域中,javascript 从下往上依次执行,会把 var/function 关键字进行提前声明或定义,var 关键字只会声明,function 声明和定义一起完成

var 变量声明

  • 使用 var 关键字声明的会进行变量提升
  • 在定义之前访问结果是 undefined
js
console.log(a); // undefined
var a = 10;

function 变量声明

  • 因为 function 声明和定义一起完成,所以在当前的作用域任何位置都可以访问到
js
console.log(a); // a() {}
function a() {}

函数声明 Vs 变量声明

  • 函数声明的优先级高于变量声明,并且不会被变量声明覆盖掉
  • 虽然提升不会被覆盖,但是赋值会被覆盖掉
js
// 函数声明的优先级高于变量声明,并且不会被变量声明覆盖掉
console.log(a); // a() {}
var a;
function a() {}

// ---------------
//虽然提升不会被覆盖,但是赋值会被覆盖掉
var a = 10;
console.log(a); // 10
function a() {}

if代码块函数

  • if代码块中的函数,会提前声明
  • if代码块中修改定义的函数,不会影响到全局
  • if代码块中,不能同时var、function声明同样的变量
js
console.log(a) // undefined
if (true) {
  console.log(a) // ƒ a () {}
  function a () {} 
}
console.log(a) // ƒ a () {}

验证if代码块中的函数,会提前声明

  • 如果if代码块的函数被注释,直接会报错为定义的变量a
  • 如果取消注释,打印的就是undefined
js
// 注释
console.log(a) // Uncaught ReferenceError: a is not defined
if (true) {
  // function a () {} 
}

// 取消注释
console.log(a) // undefined
if (true) {
  function a () {} 
}

验证if代码块中修改定义的函数,不会影响到全局

js
console.log(a) // undefined
var a;
if (true) {
  console.log(a) // // ƒ a () {}
  a = 10
  function a () {}
  // 只会影响if代码块内部的
  a = 20
  console.log(a) // 20
}
console.log(a) // 10

验证if代码块中,不能同时var、function声明同样的变量

js
// Uncaught SyntaxError: Identifier 'a' has already been declared 
if (true) {
  function a () {}
  var a
}

立即执行函数表达式(IIFE)

js
var a = 10;
(function a() {
  // 内部作用域,去查找变量声明,发现有了具明函数a
  // 因为IIFE中的函数是不能修改的,所以a=20,无效
  a = 20;
  console.log(a); // [Function a]
})();
console.log(a); // 10

let 变量

  • let 关键字声明的不会进行变量提升,提前访问会出异常
js
console.log(a); // ReferenceError: Cannot access 'a' before initialization
let a = 10

var变量提升和函数提升案例

  • var只会提前提示声明,function声明定义一起完成
  • 这里function同一个函数多次声明,后面的会覆盖前面的
  • 当代码执行到var时,会覆盖函数的定义
js
fn(); // 5
function fn () { console.log( 1 ); }
fn(); // 5
function fn () { console.log( 2 ); }
fn(); // 5
var fn = function () { console.log( 3 ); }
fn(); // 3
function fn () { console.log( 4 ); } // 执行到这里,因为函数已经提前声明定义了,这里并不会有操作
fn(); // 3
function fn () { console.log( 5 ); }
fn(); // 3

函数调用变量提升(形参)

js
console.log(a, b, c);  // undefined  undefined undefined
var a = 12,
  b = 13,
  c = 14;
function fn(a) {
  // 形参相当于var a = 10(私有)
  console.log(a, b, c); // 10  13 14
  a = 100;
  c = 200;
  console.log(a, b, c); // 100  13 200
}
b = fn(10); // 函数没有返回值undefined

console.log(a, b, c); // 12  undefined 200

函数调用变量提升(形参,函数)

  • 函数声明和定义都是一起的,并且优先级比var声明的要高
js
function fn(a) {
  // 函数声明优先级高
  console.log(a);
   // 形参相当于var a = 1(私有)
  var a = 2;
  function a(){}
}
fn(1); // [Function: a]

函数参数为函数

js
var x =100
function func(x,y=function(){x=10}){
  x= 3; // 私有
  y() // 找上级作用域,修改x=10
  console.log(x) // 10
}
func()
console.log(x) // 100

函数参数arguments

js
function func(a,b,c){
  console.log(c) // 3 
  arguments[2] = 100
  console.log(c)  // 100
}
func(1,2,3)

// 函数调用只传了2个参数,arguments=[a,b]
function func(a,b,c){
  console.log(c) // undefined
  arguments[2] = 100
  console.log(c) // undefined
}
func(1,2)