1、变量提升与函数提升
<!--
1. 变量声明提升
* 通过var定义(声明)的变量, 在定义语句之前就可以访问到
* 值: undefined
2. 函数声明提升
* 通过function声明的函数, 在之前就可以直接调用
* 值: 函数定义(对象)
3. 问题: 变量提升和函数提升是如何产生的?
-->
<script type="text/javascript">
console.log('-----')
/*
面试题 : 输出 undefined
*/
var a = 3
function fn () {
console.log(a)
var a = 4
}
fn() // undefined
console.log(b) //undefined 变量提升
fn2() //可调用 函数提升
fn3() //不能(会报错) 它属于变量提升
var b = 3
function fn2() {
console.log('fn2()')
}
var fn3 = function () {
console.log('fn3()')
}
</script>
2、执行上下文
<!--
1. 代码分类(位置)
* 全局代码
* 函数(局部)代码
2. 全局执行上下文
* 在执行全局代码前将window确定为全局执行上下文
* 对全局数据进行预处理
* var定义的全局变量==>undefined, 添加为window的属性
* function声明的全局函数==>赋值(fun), 添加为window的方法
* this==>赋值(window)
* 开始执行全局代码
3. 函数执行上下文
* 在调用函数, 准备执行函数体之前, 创建对应的函数执行上下文对象(虚拟的, 存在于栈中)
* 对局部数据进行预处理
* 形参变量==>赋值(实参)==>添加为执行上下文的属性
* arguments==>赋值(实参列表), 添加为执行上下文的属性
* var定义的局部变量==>undefined, 添加为执行上下文的属性
* function声明的函数 ==>赋值(fun), 添加为执行上下文的方法
* this==>赋值(调用函数的对象)
* 开始执行函数体代码
-->
<script type="text/javascript">
// 全局执行上下文
console.log(a1, window.a1) // undefined undefined
window.a2() // a2()
console.log(this) //window
var a1 = 3
function a2() {
console.log('a2()')
}
console.log(a1) // 3
console.log("-------------------");
// 函数执行上下文
function fn(a1){
console.log(a1); // 2
console.log(a2); // undefined
a3(); // a()
console.log(this); // Window
console.log(arguments); // Arguments --自己运行看一下,它是一个伪数组[2, 3]
var a2 = 3;
function a3(){
console.log("a3()");
}
}
fn(2,3)
</script>
3、执行上下文栈
<!--
1. 在全局代码执行前, JS引擎就会创建一个栈来存储管理所有的执行上下文对象
2. 在全局执行上下文(window)确定后, 将其添加到栈中(压栈)
3. 在函数执行上下文创建后, 将其添加到栈中(压栈)
4. 在当前函数执行完后,将栈顶的对象移除(出栈)
5. 当所有的代码执行完后, 栈中只剩下window
-->
<script type="text/javascript">
//1. 进入全局执行上下文
var a = 10
var bar = function (x) {
var b = 5
foo(x + b) //3. 进入 foo 执行上下文
}
var foo = function (y) {
var c = 5
console.log(a + c + y)
}
bar(10) //30 //2. 进入bar函数执行上下文
</script>
4、指向上下文栈(面试题)
<!--
1. 依次输出什么?
gb: undefined
fb: 1
fb: 2
fb: 3
fe: 3
fe: 2
fe: 1
ge: 1
2. 整个过程中产生了几个执行上下文? 5
-->
<script type="text/javascript">
console.log('gb: '+ i)
var i = 1
foo(1)
function foo(i) {
if (i == 4) {
return
}
console.log('fb:' + i)
foo(i + 1) //递归调用: 在函数内部调用自己
console.log('fe:' + i)
}
console.log('ge: ' + i)
</script>
5、面试题
<script>
/*
测试题1: 函数提升要比变量提升的优先级要高一些,且不会被变量声明覆盖,
但是会被变量赋值之后覆盖
*/
function a() {}
var a;
console.log(typeof a) // 'function'
function n() {}
var n=1;
console.log(typeof n) // 'number'
/*
测试题2:
*/
if (!(b in window)) {
var b = 1
}
console.log(b) // undefined
/*
面试题3 : 输出 undefined
*/
var a = 3
function fn () {
console.log(a)
var a = 4
}
fn() // undefined
/*
测试题4:
*/
// var c = 1
// function c(c) {
// console.log(c)
// var c = 3
// }
// c(2) // 报错 c is not a function
console.log("-----------------");
console.log(m); // f m() {console.log(10)}
console.log(m() + " hahahhah"); // undefined
var m = 3;
function m() {
console.log(10) //10
}
console.log(a) //3
m = 6;
console.log(m()); //m is not a function;
</script>