Skip to content

Latest commit

 

History

History
179 lines (169 loc) · 3.53 KB

File metadata and controls

179 lines (169 loc) · 3.53 KB

变量提升、函数作用域、块级作用域

  1. 所有javascript代码执行的时候都默认包裹在一个匿名函数里执行

📚JS模块化的原因,export导出,import引用可以使每个变量在自己的模块的作用域里,如果不用模块化,直接用 script标签引入的话,会导致引入的变量都在全局环境里,造成页面卡顿

在浏览器运行以下代码:

function test() {
  debugger;
}
test();

查看调用栈可发现外面默认包裹了一个匿名函数

2.带var的变量提升

if (false) {
  var a = 20;
}
console.log(a);  //undefined

打印undefined而不是报错,默认把a的声明提升到了作用域顶端,等同如下

var a;
if (false) {
  a = 20;
}
console.log(a);  //undefined

3.函数提升优先级高于var变量提升
例1:

function fun() { }
var fun;
console.log(f);  //ƒ fun() { }

例2:

alert(a); // 弹出a的函数定义
a();  //10
var a = 3;

function a() {
  alert(10);
}
alert(a);  //3
a = 6;
a();  // a is not a function

例3:

function fun() {
    console.log(1);
}
function init() {
    console.log(fun);//undefined
    if (false) {
        function fun() {
            console.log(2);
        }
    }
    console.log(fun); //undefined 提升了fun的声明,但是函数体不会提升
}
fun();//1
init();

例4

var x = 1,
  y = 0,
  z = 0;
function add(x) {
  return (x = x + 1);
}
y = add(x);
console.log(y); //4

function add(x) {
  return (x = x + 3);
}
z = add(x);
console.log(z);  //4
console.log(x)  //1  只改变形参,外部的x不会变,函数的参数是按值传递的

例5

var x = 1,
  y = 0,
  z = 0;
function add(x) {
  return (x = x + 1);
}
y = add(x);
console.log(y); //2  //这里下面那个add不会提升到外部
{
  function add(x) {
    return (x = x + 3);
  }
}
z = add(x);
console.log(z);  //4
console.log(x)  //1  只改变形参,外部的x 不会变

4.函数作用域
在ES6之前,js的作用域只有两种:函数作用域和全局作用域。使用var声明的变量,都存在变量提升的过程
🌰 例1

console.log(a); //undefined
console.log(c); //undefined
console.log(d); //function d() {}
console.log(b); //报错,b is not defined

var a = 0;
let b = 1;
var c = function () {
};
function d() {
}

由此可见使用let声明的变量不会提升,函数声明会完全提升,上面的代码等价于:

var a;
var c;
function d() {}

console.log(a);
console.log(c);
console.log(d);
console.log(b);

a = 0;
let b = 1;
c = function () {

    };

🌰 例2

var a;
console.log(a);  //undefined
a = 20;
function init() {
  //js private 私有变量
  var a = 30;
  console.log(a) //30  函数作用域:a的声明只能提升到init函数内部的顶端
}
init();
console.log(a);  //20

5.块级作用域
ES6中定义了块级作用域,使用let声明的变量只能在块级作用域里访问,有“暂时性死区”的特性(也就是说声明前不可用)
🌰例1

var test = 1;
function func(){
  //打印test的值
  console.log(test); //报错,Cannot access 'test' before initialization
  let test = 2;
};
func();

🌰例2

{
  var a = 1
  let b = 2
}
function test() {
  var c = 1
}
console.log(a)  // 1
console.log(b)  //b is not defined
console.log(c) //c is not defined  
// 这里a和c的区别是a定义在ES6的块级作用域里,c定义在函数作用域里,
// 而块级作用域对var是无效的,函数作用域会阻挡var的变量提升