今天看到两道js题,查了资料和自己的理解写下个人的见解
var name = 'World!';
(function () {if (typeof name === 'undefined') {var name = 'Jack';console.log('Goodbye ' + name);} else {console.log('Hello ' + name);}
})(); // Goodbye Jack
var foo = 1;(function foo(){foo = 100;console.log(foo);}())console.log(foo);// ? foo(){// foo = 100;// console.log(foo);// }// 1
在解决问题前先理解一下函数的命名方式:函数声明式、函数表达式
函数声明式
语法形式:
function name(){......
}
函数声明式会使得函数声明提升,意思是在执行代码之前会先读取函数声明,在函数声明前调用也不会出错
sayName(); // my name is bonnie
function sayName(){console.log('my name is bonnie');
}
函数表达式
语法形式:
var fun = function(){.......
}//IIFE立即调用函数表达式
(function(){//变量和function的声明作用域只能在这个匿名闭包里......
}())
//同下
(function(){......
})()
函数表达式不会函数声明提升,只有执行到它时才会执行。函数表达式与其他表达式一样,在使用前必须先赋值。否则报错
sayName(); // Uncaught TypeError: sayName is not a function
var sayName = function(){console.log('my name is bonnie');
}
函数表达式的函数名不可修改,如修改则在非严格模式下不起效,在严格模式下报错:Uncaught TypeError: Assignment to constant variable.
(function sayHi(){sayHi = 'hello';
})(); // Uncaught TypeError: Assignment to constant variable.
接下来分析问题:
var name = 'World!'; //外部声明变量name
//IIFE立即调用函数表达式
(function () {if (typeof name === 'undefined') {var name = 'Jack'; // var声明变量name,变量提升到IIFE作用域前面console.log('Goodbye ' + name);} else {console.log('Hello ' + name);}
})(); //等同于
(function () {var name;if (typeof name === 'undefined') { //因为变量name虽已声明但还未被初始化,所以为'undefined'name = 'Jack';console.log('Goodbye ' + name);} else {console.log('Hello ' + name);}
})();
这个问题所在是变量提升的原因,如果把IIFE里面的name声明改为let则输出‘Hello World!’
var name = 'World!';
(function () {if (typeof name === 'undefined') {let name = 'Jack';console.log('Goodbye ' + name);} else {console.log('Hello ' + name);}
})(); // Hello World!
另一道题的分析
var foo = 1;
(function foo(){foo = 100; // 修改函数表达式的函数名不符合规范,不报错也不起效console.log(foo); // 输出函数本身
}())
console.log(foo); //由于IIFE声明的函数或者变量只在那个作用域,所以这里的foo是外部作用域的foo,输出1
总结
以上是个人拙见,如有问题请各位大佬提点