今天看到两道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
总结
以上是个人拙见,如有问题请各位大佬提点