1.什么情况下会输出undefined
通常以下四种情况会出现undefined.
<script>
let num;
let person=new Object();
//第一种情况:输出未初始化的变量num
console.log(num);
//第二种情况:获取未定义的变量a的类型
console.log(typeof(a));
function fn(){
}
//第三种情况:获取没有返回值的函数的结果
console.log(fn());
//第四种情况:获取对象未定义的属性。
console.log(person.age);
</script>
2.什么是提升(Hosting)?
Javascript引擎会在解释JavaScript代码之前首先对齐进行编译,编译过程中的一部分工作就是找到所有的声明,并用合适的作用域将他们关联起来,这也正是词法作用域的核心内容。简单说就是在js代码执行前引擎会先进行预编译,预编译期间会将变量声明与函数声明提升至其对应作用域的最顶端。
看下面实例:
<script>
console.log(a);
var a = "a";
var foo = () => {
console.log(a);
var a = "a1";
}
foo();
</script>
输出结果: undefined undefined
1)变量提升
变量声明的提升是以变量所处的第一层词法作用域为“单位”的,即全局作用域中声明的变量会提升至全局最顶层,函数内声明的变量只会提升至该函数作用域最顶层。那么开始的一段代码经过预编译则变为:
<script>
var a;
console.log(a); //undefined
var a = "a";
var foo = () => {
var a; //全局变量会被局部作用域中的同名变量覆盖
console.log(a); //undefined
var a = "a1";
}
foo();
</script>
ES6新增了let和const关键字,使得js也有了“块”级作用域,而且使用let和const 声明的变量和函数是不存在提升现象的,比较有利于我们养成良好的编程习惯。比如,上例改写如下:
<script>
console.log(a);
let a = "a";
var foo = () => {
console.log(a);
let a = "a1";
}
foo();
</script>
运行结果: Uncaught ReferenceError: Cannot access 'a' before initialization
2)函数提升
<script>
console.log(foo1); // [Function: foo1]
foo1(); // foo1
console.log(foo2); // undefined
foo2(); // TypeError: foo2 is not a function
function foo1 () {
console.log("foo1");
};
var foo2 = function () {
console.log("foo2");
};
</script>
运行结果: ƒ foo1 () { console.log("foo1"); } foo1 undefined Uncaught TypeError: foo2 is not a function
这段代码经过函数提升后经过预编译则变为:
<script>
//函数声明被提升到顶端
function foo1 () {
console.log("foo1");
};
console.log(foo1); // [Function: foo1]
foo1(); // foo1
var foo2; //foo2 本质是变量提升。
console.log(foo2); // undefined
foo2(); // TypeError: foo2 is not a function
var foo2 = function () {
console.log("foo2");
};
</script>
运行结果: ƒ foo1 () { console.log("foo1"); } foo1 undefined Uncaught TypeError: foo2 is not a function 所以说函数提升只会提升函数声明,而不会提升函数表达式。函数表达式本质还是变量提升。