JavaScript 预解析

223 阅读2分钟
函数的预解析
  • 正统函数的预解析
 // ES6之前定义函数的格式
say(); 
// ES6之前的这种定义函数的格式, 是会被预解析的, 所以可以提前调用
function say() {
    console.log("hello 996");
}

// 预解析之后的代码
function say() {
    console.log("hello 996");
}
say();

/*
在其它语言中, 函数的声明是:
function say()

在 Javascript 中, 函数的声明是
function say() {
    console.log("hello 996");
}
*/
  • 将函数赋给 var 变量的方式不预解析 (let 更不会啦)
console.log(say); // undefined
say(); // say is not a function
var say = function() {
    console.log("hello itzb");
}

// 预解析之后的代码
console.log(say); // undefined
var say;
say(); // say is not a function
say = function() {
    console.log("hello itzb");
}
  • 箭头函数也不预解析 (都是报错, 这个和 var 报的还不一样, 魔鬼在细节中)
say(); // say is not defined
let say = () => {
    console.log("hello itzb");
}
狗题目

注意点: 浏览器执行的是预解析之后的代码

  • 预解析规则很简单, 搞顺顺
var num = 123;
fun(); // undefined
function fun() {
    console.log(num);
    var num = 666;
}

/*
预解析之后:
var num;
function fun() {
var num;
console.log(num);
num = 666;
}
num = 123;
fun(); // undefined
*/
var a = 666;
test();
function test() {
    var b = 777;
    console.log(a); // 作用域链的就近原则
    console.log(b);
    console.log(c); // 虽然这里会报错, 但前面该输出的也会输出	
    var a = 888;
    let c = 999;
}
/*
预解析之后:
var a;
function test() {
var b;
var a;
b = 777;
console.log(a); // undefined
console.log(b); // 777
console.log(c); // 报错
a = 888;
let c = 999;
}
a = 666;
test();
*/
  • 高级浏览器不会对 {} 中定义的函数进行提升
 if(true){
     function demo() {
         console.log("1");
     }
 }else{
     function demo() {
         console.log("2");
     }
 }
demo(); // 1

/*
纯逻辑: 预解析, 函数提升, 后写覆盖先写, 于是输出 2

实际中:
高级浏览器不会对 {} 中定义的函数进行提升,
于是顺序执行, 输出 1
*/
  • 如果同级作用域 var 变量名与函数名同名, 函数的优先级高于变量 (淦! 居然没一以贯之用‘覆盖’的逻辑)
  • 一定要记住, 在企业开发中千万不要让变量名称和函数名称重名
console.log(value); // 输出函数的定义
var value = 123;
function value() {
    console.log("fn value");
}
console.log(value); // 123

/*
预解析之后
function value() {
    console.log("fn value");
}
console.log(value);
var value;
value = 123;
console.log(value);
*/