0


js进阶语法---变量提升,函数提升,以及参数的命名冲突问题

前言

预处理阶段:js在编译代码时有一个预处理阶段,这个过程会将原本的代码进行分割处理;

源程序 ---> 预处理块+ 剩余代码块

预处理块中的代码会优先于剩余代码块中的代码执行

什么是变量提升,函数提升

变量提升:当声明一个变量时,这个声明过程会被预处理机制塞入到预处理块中优先执行,这就是变量提升,使用var定义的变量拥有变量提升

函数提升:当声明一个函数时,这个声明过程会被预处理机制塞入到预处理块中优先执行,这就是函数提升,使用function定义的函数拥有函数提升

提升的判断:当一个变量和函数在正常的顺序中没有声明但被调用时就可能产生“提升”

变量提升

变量提升,将变量名放入预编译的词法环境 var a(undefined)

  1. console.log(a);
  2. var a = 1;

以上的代码会产生变量提升,它等价于下面的代码,

  1. {// 模拟预处理块
  2. var a;
  3. }
  4. // 正常执行的剩余代码块
  5. console.log(a); // undefined
  6. a = 1;

因为变量提升的缘故,a会在打印执行前被声明,所以会打印成undefined

函数提升

函数提升,将函数体放入预编译的词法环境 function b(){}

  1. console.log(b);
  2. function b(){
  3. console.log('b')
  4. };

以上的代码会产生函数提升,它等价于下面的代码,

  1. {// 模拟预处理块
  2. function b(){
  3. console.log('b')
  4. };
  5. }
  6. // 正常执行的剩余代码块
  7. console.log(b);

function声明的函数都存在函数提升,所以可以在声明函数之前使用函数(先写出函数的用法,在完成函数的实现)

关于变量提升和函数提升的判断

了解了基本的变量提升和函数提升,接下来开始区分一些二者的区别和同时在场的优先级

1.变量赋值的函数

  1. console.log(a);
  2. var a = function(){
  3. console.log('a')
  4. };

很显然这是由var声明的变量,拥有变量提升,只不过它的值是一个函数体

  1. {// 模拟预处理块
  2. var a;
  3. }
  4. // 正常执行的剩余代码块
  5. console.log(a); // undefined
  6. a = function(){
  7. console.log('a')
  8. };

所以这个a会打印成undefined

2.优先级判断

  1. console.log(b);
  2. var b = function(){
  3. console.log('b1')
  4. };
  5. function b(){
  6. console.log('b2')
  7. };
  8. console.log(b);

函数提升的优先级是比变量提升的优先级大的,当出现声明同名的变量和函数时,在预处理块中最终都会变成函数,

  1. {// 模拟预处理块
  2. var b;
  3. function b(){
  4. console.log('b2')
  5. };
  6. }
  7. // 正常执行的剩余代码块
  8. console.log(b);// 能打印'b2'的函数
  9. b = function(){
  10. console.log('b1')
  11. };
  12. console.log(b);// 能打印'b1'的函数

除了上面这种优先级的理解方式,还有下面这种,将function声明拆成了两个部分,先声明函数名,在赋值函数体,而变量的声明在它们之间

  1. {// 模拟预处理块
  2. function b
  3. var b;
  4. b = function(){
  5. console.log('b2')
  6. };
  7. }
  8. // 正常执行的剩余代码块
  9. console.log(b);// 能打印'b2'的函数
  10. b = function(){
  11. console.log('b1')
  12. };
  13. console.log(b);// 能打印'b1'的函数

tips:以上两种方式的结果是一样的,采用哪种分析方式都可以

3.同名参数名,变量名,函数名的优先级判断

同名参数名,变量名的判断

  1. var foo = 'hello';
  2. (function(foo){
  3. console.log(foo);
  4. var foo = foo || 'world';
  5. console.log(foo);
  6. })(foo);
  7. console.log(foo);

这里只分析了立即执行函数内的预处理

  1. var foo = 'hello';
  2. (function(foo){
  3. // 模拟立即执行函数内的预处理块
  4. {
  5. var foo;
  6. foo = foo; //传入的参数('hello')
  7. }
  8. // 正常执行的剩余代码块
  9. console.log(foo);
  10. foo = foo || 'world';
  11. console.log(foo);
  12. })(foo);
  13. console.log(foo);

所以最后连续打印了3个hello,传入的参数会在预处理中声明后赋值给同名变量,foo不为undefined,后面的赋值就不会变成world

当同名参数名,变量名,函数名同时存在

  1. function fn (m){
  2. console.log(m);
  3. var m = 1;
  4. function m(){
  5. }
  6. console.log(m);
  7. }
  8. fn(10)

同样有两种理解方式

  1. function fn (m){
  2. // 模拟预处理块
  3. {
  4. var m;
  5. m = m;// 传入的参数(10)
  6. function m(){
  7. }
  8. };
  9. }
  10. // 正常执行的剩余代码块
  11. console.log(m);// function(){}
  12. m = 1;
  13. console.log(m);// 1
  14. }
  15. fn(10)
  1. function fn (m){
  2. // 模拟预处理块
  3. {
  4. function m
  5. var m;
  6. m = m;// 传入的参数(10)
  7. m = function(){
  8. }
  9. };
  10. }
  11. // 正常执行的剩余代码块
  12. console.log(m);// function(){}
  13. m = 1;
  14. console.log(m);// 1
  15. }
  16. fn(10)

可以看到这个函数的输出和传入的参数没有任何关系,因为传入的参数会在函数提升的前面(函数体赋值的前面),导致传入的参数被覆盖

总结

所以可以得出同名参数名,变量名,函数名的预处理顺序为:

变量提升---参数传递---函数提升 (声明函数名---变量提升---参数传递---函数体赋值)

所以最终这个名称会被函数夺取,这就是函数提升优先级最高的原因

完整代码和运行结果展示

  1. // 变量提升,将变量名放入预编译的词法环境 var a(undefined)
  2. console.log(a);
  3. var a = function(){
  4. console.log('a')
  5. };
  6. console.log(a);
  7. // 函数提升,将函数体放入预编译的词法环境 function b(){}
  8. console.log(b);
  9. var b = function(){
  10. console.log('b1')
  11. };
  12. function b(){
  13. console.log('b2')
  14. };
  15. console.log(b);
  16. // function b 函数名提升
  17. // var b 变量名提升
  18. // b = (){} 函数体初始化
  19. // 因为函数体初始化总在变量名之后,所以每次都是优先预编译成函数
  20. // 结合自执行函数
  21. var foo = 'hello';
  22. (function(foo){
  23. console.log(foo);
  24. var foo = foo || 'world';
  25. console.log(foo);
  26. })(foo);
  27. console.log(foo);
  28. // 依次输出 hello hello hello
  29. // 预编译后
  30. var foo = 'hello';
  31. (function (foo) {
  32. var foo; // undefined;
  33. foo= 'hello'; //传入的foo的值
  34. console.log(foo); // hello
  35. foo = foo || 'world';// 因为foo有值所以没有赋值world
  36. console.log(foo); //hello
  37. })(foo);
  38. console.log(foo);// hello,打印的是var foo = 'hello' 的值(变量作用域)
  39. // function m(){
  40. // console.log('m');
  41. // };
  42. // var m;
  43. // m =1;
  44. // function m(){
  45. // }
  46. // console.log(m)
  47. function fn (m){
  48. console.log(m);
  49. var m = 1;
  50. function m(){
  51. }
  52. console.log(m);
  53. }
  54. fn(10)
  55. // function m
  56. // var m
  57. // 参数m
  58. // m = (){}
  59. // m = 1
  60. // function > parmas > var


本文转载自: https://blog.csdn.net/I_am_shy/article/details/140715639
版权归原作者 I_am_shy 所有, 如有侵权,请联系我们删除。

“js进阶语法---变量提升,函数提升,以及参数的命名冲突问题”的评论:

还没有评论