关于JS变量提升的一些坑

1 function log(str) {
2    // 本篇文章所有的打印都将调用此方法
3    console.log(str);
4 }

函数声明和变量声明总是会被解释器悄悄地被“提升”到方法体的最顶部

变量声明、命名、提升

在JS中, 变量有4种基本方式进入作用域:

  • 语言内置: 所有的作用域里都有this和arguments;(需要注意的是arguments在全局作用域是不可见的)
  • 形式参数: 函数的形式参数会作为函数体作用域的一部分;
  • 函数声明: 像这种形式: function foo() {};
  • 变量声明: 像这样: var foo;

变量提升

function test1() {
      a = 5;
      log(a);
      log(window.a);
      var a = 10;
      log(a);
    }
    test1();

依次会输出 5 、undefined 、10   因为在解析时候是等价于

1 var a;
2 a=5;
3 log(a);
4 log(window.a);
5 a=10;
6 log(a);

接着看另外一个例子:

 1 function test2() {
 2    var a = 1;
 3    var b = 2;
 4    var c = 3;
 5 }
 6 /*test2中的语句,是这样被执行的  这个时候就把变量提升了
 7      8     function test2(){
 9       var a,b,c;
10       var a = 1;
11       var b = 2;
12       var c = 3;
13     }
14      */

只有函数级作用域,if语句不会有:test3():

function test3(){  var a = 1;  log(a);      // 1   if (true) {    var a = 2;    log(a);    //2   }  log(a);      // 2 }

 

函数的提升

我们写JS的时候,通常会有两种写法:

  • 函数表达式 var fn=function fn(){}
  • 函数声明方式 function fn(){}

我们需要重点注意的是,只有函数声明形式才能被提升。
变量赋值并没有被提升,只是声明被提升了。但是,函数的声明有点不一样,函数体也会一同被提升

 1 function test3() {
 2    fn();
 3    function fn() {
 4      log("我来自fn");
 5    }
 6  }
 7  test3();
 8  function test4() {
 9    fn(); // fn is not a function
10    var fn = function fn() {
11      alert("我来自 fn  test4");
12    }
13  }
14  test4();

函数表达式需要注意的

  • 在function内部,fn完全等于fn1
  • 在function外面,fn1则是 not defined
 1 function test5() {
 2       var fn = function fn1() {
 3         log(fn === fn1); // true
 4         log(fn == fn1); // true
 5       }
 6       fn();
 7       log(fn === fn1); // fn1 is not defined
 8       log(fn == fn1);  // fn1 is not defined
 9     }
10     test5();

!兼容
// b();
// var a = function b() {alert(‘this is b‘)};
// 则ie下是可以执行b的. 说明不同浏览器在处理函数表达式细节上是有差别的.

补充一点函数表达式

定义里面的指定的函数名是不是被提升的

 1 function text7() {
 2   a(); // TypeError "a is not a function"
 3   b();
 4   c(); // TypeError "c is not a function"
 5   d(); // ReferenceError "d is not defined"
 6
 7   var a = function() {};    // a指向匿名函数
 8   function b() {};          // 函数声明
 9   var c = function d() {};  // 命名函数,只有c被提升,d不会被提升。
10
11   a();
13   b();
14   c();
15   d(); // ReferenceError "d is not defined"
16 }
17 text7();

大家先看下面一段代码test6,思考一下会打印什么?

 1 function text6() {
 2    var a = 1;
 3    function b() {
 4      a = 10;
 5       return;
 6       function a() {}
 7     }
 8     b();
 9     log(a);         //  ?
10 }
11 text6();

||

||

||

|| 输出在下面

||

||

||

||

||

||

what? 什么鬼?为什么是1?
这里需要注意的是,在function b()中,
var = a // function 类型的
a=10; // 重新把10复制给a,  此时的a是function b()中的内部变量
return;
function a() {} // 不会被执行

所以,外面输出的a 依旧是最开始定义的全局变量

函数的声明比变量的声明的优先级要高

 1 function text6() {
 2   function a() {}
 3   var a;
 4   log(a);                //打印出a的函数体
 5
 6   var b;
 7   function b() {}
 8   log(b);                 //打印出b的函数体
 9
10   // !注意看,一旦变量被赋值后,将会输出变量
11   var c = 12
12   function c() {}
13   log(c);                 //12
14
15   function d() {}
16   var d = 12
17   log(d);                //12
18 }
19 text6();

变量解析的顺序


一般情况下,会按照最开始说的四种方式依次解析

  • 语言内置:
  • 形式参数:
  • 函数声明:
  • 变量声明:

也有例外:

  • 内置的名称arguments表现得很奇怪,看起来应该是声明在形参之后,但是却在声明之前。这是说,如果形参里面有arguments,它会比内置的那个优先级高。所以尽可能不要在形参里面使用arguments;
  • 在任何地方定义this变量都会出语法错误
  • 如果多个形式参数拥有相同的名称,最后的那个优先级高,即便是实际运行的时候它的值是undefined;

CAO!这么多坑,以后肿么写代码?

用var定义变量。对于一个名称,在一个作用域里面永远只有一次var声明。这样就不会遇到作用域和变量提升问题。

ECMAScript参考文档关于作用域和变量提升的部分:
    如果变量在函数体类声明,则它是函数作用域。否则,它是全局作用域(作为global的属性)。变量将会在执行进入作用域的时候被创建。块(比如if(){})不会定义新的作用域,只有函数声明和全局性质的代码(单个JS文件)才会创造新的作用域。变量在创建的时候会被初始化为undefined。如果变量声明语句里面带有赋值操作,则赋值操作只有被执行到的时候才会发生,而不是创建的时候。

最后,

由于时间仓促,demo有很多不足之处,多谅解

时间: 2024-10-12 11:02:33

关于JS变量提升的一些坑的相关文章

js变量提升的坑

关于js变量提升 变量提升 在js函数内部是可以直接修改全局的变量的,个人感觉是不好的设计, 但是确实存在这个概念 原理: 先查看有没有函数变量bb 查看形参有没有bb 查看全局有没有bb 报错, 找不到bb变量 修改函数内部 var bb = 1; function foo(cc){ var bb = 2; // 这里的bb, 其实是函数的局部变量 console.log(cc); } foo(bb); // 1 console.log(bb); // 1 修改的是形参 var bb = 1;

js 变量提升+方法提升

<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> <script type="text/javascript"> var a = 100; function t() { alert(a); var a = 10; } t(); //输出结果为undefine

js变量提升的一个小坑

好久没写博客了,原本想实训结束能对整个实训项目认真总结一下,没想到回到学校一点都不轻松,最近在制作网页版简历,遇到了一个小问题,现在不总结以后肯定忙得顾不上,所以长话短说,抓紧时间写下来. 对js语法比较熟的同学可能都知道:js是没有块级作用域的,有一个新手很容易出错的地方 for(var i = 0 ; i < 10 ; i ++){ setTimeout(function(){ console.log(i) },1000*i) } 这段代码会输出10个10,而不是期望的1,2,...,10,

js变量提升小记

作为世界上最优美的语言javascript的使用者,呵呵,js的魅力是无穷的,今天来聊聊他的魅(dan)力(teng)之一,变量提升. 每种语言所定义的变量基本都会有一定得作用域,而js的作用域则存在着一定的陷阱.首先看一下下面一道题: <script> var str1 = "haha"; var str2 = "hehe"; function t1() { console.log(str1); console.log(str2); var str2

JS 变量提升

1 var a = 1; 2 function foo() { 3 console.log(a); 4 var a = 2; 5 6 } 7 8 foo(); //undefined 根据变量提升机制,最后得出undefined; 变量提升是指在一个作用域中声明的变量,JS解析时会把变量声明提升至作用域内的第一行,也就是说上面那段代码等同于: 1 var a = 1; 2 function foo() { 3 var a; //被提升至作用域内第一行 4 console.log(a); 5 va

js变量提升与函数提升

在es6之前,js语言并没有块级作用域,即{}形成的作用域,只有全局作用域和函数作用域,所谓的提升,即是将该变量的声明或者函数的声明提升,举个例子 console.log(global); //undefined var global = 111; console.log(global);//111 显然,上面代码处于一个全局的作用域中,在该作用域中使用var声明了一个global变量,其实际的声明过程如下: var global; console.log(global); //undefine

js变量提升和函数提升

变量,作为编程语言最基础的部分,每种语言的变量不尽相同,但又大径相庭.大部分编程语言的变量有块级作用域,如if.for.while... 但JavaScript不纯在块级作用域,而是函数作用域,并且有自己独有的特性--变量提升.(ES6新添加的let.const使其可以用块级作用域) 对于函数的变量访问时遵循作用域链的,即当前函数运行时会有一个当前作用域,当饮用某个变量时,会先查找当前作用域内是否存在该变量的定义,如果不存在则根据作用域链向上去查找父函数的作用域,有则拿来使用,没有则继续向上直到

js变量提升

JavaScript的函数定义有个特点,它会先扫描整个函数体的语句,把所有申明的变量“提升”到函数顶部: 'use strict'; function foo() { var x = 'Hello, ' + y; alert(x); var y = 'Bob'; } foo(); 虽然是strict模式,但语句var x = 'Hello, ' + y;并不报错,原因是变量y在稍后申明了.但是alert显示Hello, undefined,说明变量y的值为undefined.这正是因为JavaS

JS变量提升相关总结

关于变量提升这个玩意,你说简单吧,很多人做好几年前端了,仍然会晕掉,例如说我. 前几天笔试遇到一个变量提升的问题,答案是写出来了,然后面试官让我讲,我就讲不出来了. 今天分享一篇看到别人的总结,加上一点自己的理解.希望能有所帮助,自己也能记住. 1.关于声明变量的过程: var a = 1; var b = 2; 其实他的执行过程是这样的: var a; var b; a = 1; b = 2; 先声明变量,后执行赋值. 2.变量提升 function test(){     a=2;