思维导图
变量晋升机制
一.什么是变量晋升?
- 变量晋升示例
/* 你应该见过上面的相似代码,那你晓得这是为什么*/
console.log(a) // undefined
var a = 10
定义:变量晋升是当栈内存作用域造成时,JS代码执行前,浏览器会将带有
var, function
关键字的变量提前进行申明 declare(值默认就是 undefined),定义 defined(就是赋值操作),这种事后解决的机制就叫做变量晋升机制也叫预约义。
在变量晋升阶段:带var
的只申明还没有被定义,带function
的曾经申明和定义。所以在代码执行前有带var
的就提前申明,比方这里的a
就赋值成undefined
,在代码执行过程中遇到创立函数的代码
浏览器会间接跳过。不思考变量晋升阶段的 js 运行机制相干参考 JS 运行机制根底版
解说示例
var a =12
var b = a
b = 1
function sum(x, y) {
var total = x + y
return total
}
sum(1, 2)
PS: 函数在调用时创立执行上下文对象还有其余要害的步骤作用域创立,this指向等这些内容放在前面文章讲,这样的机制有点相似变量晋升。上面的函数创立过程都会被按作相似于变量晋升来了解。
变量晋升只产生在以后作用域。比方:在页面开始加载时,只有全局作用域产生变量晋升,这时候的函数中存储的都是代码字符串。
二. 带 var 和不带 var 的区别
- 全局作用域中不带
var
申明变量尽管也能够然而倡议带上var
申明变量,不带var
的相当于给window对象设置一个属性罢了。 - 公有作用域(函数作用域),带
var
的是公有变量。不带var
的是会向下级作用域查找,如果下级作用域也没有那么就始终找到 window 为止,这个查找过程叫作用域链
。 - 全局作用域中应用
var
申明的变量会映射到 window 下成为属性。
a = 12 // == window.a
console.log(a) // 12
console.log(window.a) // 12
var a = b =12 // 这里的 b 也是不带 var 的。
/* 相当于*/
var a = 12;
b = 12
思考题
-
- 问上面别离输入什么?
// 1
console.log(a, b)
var a =12, b ='林一一'
function foo(){
// 2
console.log(a, b)
// 3
var a = b =13
console.log(a, b)
}
foo()
console.log(a, b)
/* 输入:
undefined undefined
undefined "林一一"
13 13
12 13
*/
- 2.. 问上面的后果和下面的有何不同?
console.log(a, b)
var a =12, b = '林一一'
function foo(){
console.log(a, b)
// var a =b =13
console.log(a, b)
}
foo()
// 4
console.log(a, b)
/* 输入:
undefined undefined
12 "林一一"
12 "林一一"
12 "林一一
*/
解答
下面的思考题不晓得你都对了没,上面让我来解答,详情看图
思路:1处的 a, b 其实就是window上面的属性为 undefined。在函数外部因为变量晋升机制
a
带var
一开始就是 undefined,b
不带var
将向下级作用域查找,找到全局作用域下的林一一
所以2处打印进去的就是undefined "林一一"
。随后a =13,window.b =13
,即原来b='林一一'
变成了b=13
,打印出13, 13
,最初第4处打印处12, 13
。所以联合流程图,很显著晓得答案
- 问题3,再来看一道,问上面答案是什么?
a = 0
function foo(){
var a =12;
b = '林一一'
console.log('b' in window)
console.log(a, b)
}
foo()
console.log(b)
console.log(a)
/* 输入
true
12 "林一一"
林一一
0
/
思路:这是比较简单的一道题,须要留神的是函数内的 b 没有带
var
,b 会始终向上查找到 window 下,发现 window 下也没有就间接给 window 设置了一个属性window.b = '林一一'
,同理全局下的a
也一样。
- 问题4,问上面答案是什么?和问题3有什么区别
function foo(){
console.log(a)
a =12;
b = '林一一'
console.log('b' in window)
console.log(a, b)
}
foo()
/* 输入
Uncaught ReferenceError: a is not defined
/
思路:问题4和问题3的次要区别在于第一个
console.log(a)
处,因为a
不在函数作用域内,就会向上找window
下的作用域,发现也没有就会间接抛出援用谬误 ReferenceError
- 经典面试题
fn();
console.log(v1);
console.log(v2);
console.log(v3);
function fn(){
var v1 = v2 = v3 = 2019;
console.log(v1);
console.log(v2);
console.log(v3);
}
/*输入
2019
2019
2019
Uncaught ReferenceError: v1 is not defined
/
思路:和问题4相似,不做剖析
三. 等号右边下的变量晋升
- 函数右边的变量晋升
print()
function print(){
console.log('林一一')
}
print()
很显然下面都输入了
林一一
,因为带 function 的曾经进行了变量晋升
- 匿名函数下的带
=
的变量晋升
print()
var print = function() {
console.log('林一一')
}
print()
/*输入
Uncaught TypeError: print is not a function
/
思路:同样因为变量晋升机制带
var
的 print 是一开始值是undefined
,所以 print() 这时还不是一个函数,所以报出 类型谬误TypeError
四. 条件判断下的变量晋升
- if else 条件判断下的变量晋升
console.log(a)
if(false){
var a = '林一一'
}
console.log(a)
/* 输入
undefined
undefinedN
/
在以后作用域中不论条件是否成立都会进行变量晋升
-
if else 条件判断下函数变量晋升的坑
-
新版浏览器中,在条件判断块级作用域之外应用条件内函数
console.log(print()) if(true){ function print() { console.log('林一一') } } console.log(print()) /* 输入 undefined 林一一 undefined /
- 新版浏览器中,在条件判断块级作用域中应用条件内函数
if(true) { console.log(print()) // ??? function print() { console.log('林一一') } } console.log(print()) /* 输入 林一一 undefined 林一一 /
-
思路:
{}
大括号属于块级作用域,在if else
中带function
的函数同样也会先被申明和定义所以条件判断中的print()
能够间接应用
思考题
- 题目1,if判断语句中的变量晋升
if(!("value" in window)){
var value = 2019;
}
console.log(value);
console.log('value' in window);
/* 输入
undefined
true
/
思路:和下面所说的一样,不论条件是否成立带
var
的变量晋升,以后在全局作用域value
就是window
的属性,所以后果不言而喻输入undefined 和 true
五. 重名问题下的变量晋升
- 函数名和
var
申明的变量重名
var fn = 12
function fn() {
console.log('林一一')
}
console.log(window.fn)
fn()
/* 输入
* 12
* Uncaught TypeError: fn is not a function
/
思路:带
var
申明的和带function
申明的其实都是在 window 下的属性,也就是重名了,依据变量晋升的机制,JS 代码自上而下执行时此时的fn
还只是fn = 12
,所以fn() == 12()
又是一个类型谬误 TypeError
- 变量重名在变量晋升阶段会从新定义也就是从新赋值
console.log('1',fn())
function fn(){
console.log(1)
}
console.log('2',fn())
function fn(){
console.log(2)
}
console.log('3',fn())
var fn = '林一一'
console.log('4',fn())
function fn(){
console.log(3)
}
/* 输入
* 3
* 1 undefined
* 3
* 2 undefined
* 3
* 3 undefined
* Uncaught TypeError: fn is not a function
/
思路:同样因为变量晋升机制,
fn
会被屡次从新赋值最初赋值的地址值(假如为oxfffee)为最初一个函数,所以调用fn
都只是在调用最初一个函数输入都是3
, 代码执行到var fn = '林一一'
,所以fn() 其实 == 林一一()
导致类型谬误 TypeError
思考题
-
- 腾讯的一道变量晋升的面试题
var a=2;
function a() {
console.log(3);
}
console.log(typeof a);
/* 输入
* number
/
思路:这是一道比较简单的变量晋升题,JS 代码自上而下执行时,
a
被赋值成 2,输入就是number
型
- 2.. 再来一道面试题
console.log(fn);
var fn = 2019;
console.log(fn);
function fn(){}
/* 输入
fn(){}
2019
/
思路:这也是重名下的一道面试题,在变量晋升阶段
fn
由变量值申明为undefined
被批改定义为fn函数自身 fn(){}
,所以第一个输入就是fn(){}
,第二个输入fn
由被赋值成fn=12
输入12
参考
JavaScript面试题剖析之变量晋升和执行上下文
举荐浏览地址 掘金
感激浏览,我是林一一,下次见
发表回复