我是靠谱客的博主 内向樱桃,这篇文章主要介绍js中的声明提前,现在分享给大家,希望可以做个参考。

只要是写过点JS代码,很简单一个var 就完事了。那对于JS编译器背后它又发生了什么呢?那就一步步通过代码来讲起。


x = 1;

alert(x);
var y = function() {
  alert(x);
  var x = 2;
  alert(x);
}

y();

上面的代码也会你答对了它会分别输出:1,undefined,2。对于我来说,第一反应它会输出:1,1,2。为什么第二个会输出undefined?在上面我明确定义了一个全局变量x,为何找不到?

那是因为:js编译器在执行这个y函数的时候,会把把它body里面的声明变量提前到最前面进行声明。比如:var x=2; 编译器先会在body最前面进行var x 声明。其实上面的代码等同于下面的这段代码:

x = 1;
alert(x);
var y = function() {
  var x; //此时x还未赋值,所以为undefined。
  alert(x);
  x = 2;
  alert(x);
}
y();

所以也就不难理解x=undefined的了.但是如果把var x = 2;这段代码给删掉,在内部它没有进行var声明。它会一直沿着作用域向上找,此时的x 就为全局x.

接下来再看一个更有趣的例子。

var a = 1;
function b() {
    a = 10;
    return;
}
b();
alert(a);
///
var a = 1;
function b() {
    a = 10;
    return;
function a() {}

b(); 
alert(a);

注意 : 1. 在函数b()中将去掉var声明,则变量a就会从局部变量升级为全局变量。

例子很简单。第一个例子为输出10,第二个会输出1。这是为什么呢?况且第二个例子我都return 了。按理都应当输出10才对呀!那是因为JS编译器在背后作怪。

其实JS编译器在背后会把function a() {}编译成 var a=function (){}。那么函数内局部变量a没有升级为全局变量, 外面的a些也还是1

最张alert(a) 就会显示1;

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var a=1; function fun(){console.log(0)} function test(){ console.log(a) //输出undefined console.log(fun) //输出undefined console.log(f) //输出f(){} if(false){ var a=2; function fun(){} } function f(){} } test()
注意
复制代码
1
if(){}结构中内的语句被认为是函数表达式(expression)而不是函数声明(declaration)。而提前(hoisting)只对声明起作用,表达式不行。
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
转载一下优秀的解答:
作者:黄一君 链接:https://www.zhihu.com/question/52098661/answer/145533650 来源:知乎 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

在控制语句块中直接使用函数申明而不是函数表达式的方式一直都是错误的使用方式,你的问题可以分成两块来解释:

一. var定义的变量声明都会被提升至本作用域的顶部,而函数申明整体都会提升至本作用于顶部,且函数申明整体提升的优先级高于var定义的变量提升优先级。最后考虑到你的例子中使用了var而不是let定义,所以if的块级作用域并不生效,所以你的代码去除if块中声明的fun函数后实际变成了这样:

复制代码
var a = 1;
function fun(){console.log(0)}
function test() {
function f() {}
var a;
console.log(a)
//输出undefined
console.log(f)
//输出[Function: f]
if (false) {
a = 2;
}
}
test();

所以这样打印a和f的结果就比较明显了。


二.在try{}或者if(){}块中声明函数而不是函数表达式,首先这是规范禁止大家的做法,其次很多JS引擎并没有遵守规范(这么写也不会报错),但是执行的结果会有所不同:IE10以下的版本一些老旧浏览器函数会整体提升,即你的例子中console.log(fun)会输出:[Function: fun],提升方式和一中的一致:

复制代码
function fun(){console.log(0)}
function test() {
function fun() {}
function fun1(){}
console.log(fun)
//输出[Function: fun]
console.log(fun1);
//输出[Function: fun1]
if (false) {}
try{}catch (e){}
}
test();

但是在最新的浏览器和Node环境下,if或者try块中采用这种错误的写法,只会提升函数声明,函数体定义不会提升,类似于:

复制代码
function fun(){console.log(0)}
function test() {
var fun;
var fun1;
console.log(fun);
//输出undefined
console.log(fun1);
//输出undefined
if (false) {
fun
= function fun() {};
}
try{
fun1 = function fun1(){}
}catch (e){}
}
test();

这种不确定的结果,必然会造成隐患,因此在if或者try等块中请使用函数表达式而不是直接的函数声明~


最后

以上就是内向樱桃最近收集整理的关于js中的声明提前的全部内容,更多相关js中内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(57)

评论列表共有 0 条评论

立即
投稿
返回
顶部