前言

Javascript中的变量定义方式有以下三种方式:
1、直接定义变量,var与let均不写;

a = 10;

2、使用var关键字定义变量

var a = 10;

3、使用let关键字定义变量

let a = 10;

这三种方式有什么区别呢?
JavaScript全局变量和局部变量又是什么呢?
可以带着这两个问题往下看。

变量的作用域

变量是有作用域的,大多数语言中的变量的作用域都有全局变量和局部变量之分。
首先我们建立一个文件test1.html,从中输入以下代码:

<script type="text/javascript">
    //在函数外使用var关键字声明变量test_var1
    var test_var1 = "变量1";
    //定义函数testFun
    function testFun(){
        //在函数中定义变量没加任何关键字的变量test_var2
        test_var2 = "变量2";
        //函数内使用var关键字定义的test_var3
        var test_var3 = "变量3";
    }
    //函数执行
    testFun();
    alert(test_var1 + "\n" + test_var2);
    alert(test_var3);
</script>

在浏览器打开我们的html页面,可以看到只弹出了一个弹窗:

第二个弹窗为什么没有成功弹出呢?
我们按F12,看一下报错内容:

由此可以看出 test_var3 在函数执行后是没有被定义的。说明在函数体内用 var 关键字声明的变量 test_var3 是局部变量;
在函数体外使用 var 关键字定义的变量test_var1 和在函数体内未用任何关键字定义的变量 test_var2 是全局变量。

得出结论:
在函数体外使用var关键字定义的变量和在函数体内未用任何关键字声明的变量是全局变量,在函数体内使用var关键字声明的变量是局部变量。

var声明的全局变量和局部变量同名

我们建立一个文件test2.html,从中输入以下代码:

<script type="text/javascript">
    //在函数外使用var关键字声明变量test_var
    var test_var = "函数体外的变量";
    //定义函数testFun
    function testFun(){
        //函数内使用var关键字声明变量test_var
        var test_var = "函数体内的变量";
        //弹窗弹出test_var
        alert(test_var);
    }
    //函数执行
    testFun();
    alert(test_var);
</script>

打开该文件,会弹出两次弹窗,分别是:


点击确定后还会弹窗一次:

在函数体外定义的全局变量test_var,但是在函数体内又定义了局部变量test_var ,在函数中弹出的test_var是函数体内的局部变量覆盖函数体外的全局变量的结果,当离开函数后,局部变量失效,将会看到全局变量。

JavaScript中的变量有块范围吗?

JavaCC++等语言中,在 if块循环块中定义的变量,出了该块之后将,不能继续访问。那JavaScript中是否也如此呢?

我们建立一个文件test3.html,从中输入以下代码:

<script type="text/javascript">
    //定义函数testFun
    function testFun(){
        //函数内使用var关键字声明变量test_var
        var test_var1 = "1";
        //if代码块
        if(test_var1 == "1"){
            //定义变量test_var2
            var test_var2 = 10;
            //for代码块
            for(var i = 0; i < 5; i++){
                //打印输出i
                document.write(i);
            }
        }
        //在if块外访问test_var2
        alert(test_var2);
        //在循环体外访问i
        alert(i);
    }
    //函数执行
    testFun();
</script>

我们可以看到两个弹窗:


并且能看到页面上的输出

由此我们可以知道:
在函数体内中的 if 块和循环体内定义的变量,在函数内都是可以访问的。

变量提升

前面介绍中已经知道:局部变量和全局变量同名时,局部变量会覆盖全局变量。
我们定义test4.html,输入以下代码:

<script type="text/javascript">
    //在函数外使用var关键字声明变量test_var
    var test_var = "函数外的test_var";
    //定义函数testFun
    function testFun(){
        //打印输出test_var
        document.writeln(test_var + "<br>");
        //函数内使用var关键字定义的test_var
        var test_var = "函数内的test_var";
        //再次打印输出test_var
        document.writeln(test_var + "<br>");
    }
    //函数执行
    testFun();
</script>

输出如下:

在输出全局变量时,居然输出的是underfined,这是什么情况呢?
这便是JavaScript的变量提升机制起了”作用“。下面介绍一下变量提升:
在函数体内变量声明总会被解释器”提升“到函数体的顶部,
那么上面的代码,会变成如下情况:

<script type="text/javascript">
    //在函数外使用var关键字声明变量test_var
    var test_var = "函数外的test_var";
    //定义函数testFun
    function testFun(){
        //声明被提升到顶部,但是未被赋值
        var test_var;
        //打印输出test_var
        document.writeln(test_var + "<br>");
        //给test_var赋值
        test_var = "函数内的test_var";
        //再次打印输出test_var
        document.writeln(test_var + "<br>");
    }
    //函数执行
    testFun();
</script>

由此可见,变量提升只提升声明部分,不提示赋值部分。

我们定义test5.html,输入以下代码:

<script type="text/javascript">
    //在函数外使用var关键字声明变量test_var1
    var test_var1 = "函数外的test_var1";
    //在函数外使用var关键字声明变量test_var2
    var test_var2 = "函数外的test_var2";
    //定义函数testFun
    function testFun(){
        //打印输出test_var1
        document.writeln(test_var1 + "<br>");
        //打印输出test_var2
        document.writeln(test_var2 + "<br>");
        //for循环的条件为假不会被执行
        for(;-1>5;){
            //在函数内使用var关键字声明变量test_var1
            var test_var1 = "函数内的test_var1";
        }
        return;
        //return后面的语句不会被执行
        //在函数内使用var关键字声明变量test_var2
        var test_var2 = "函数内的test_var2";
    }
    //函数执行
    testFun();
</script>

输出如下:


在函数内的test_var1test_var2 的变量定义根本不会被执行,为何还是输出undefined呢?
这也是变量提升起的”作用“。

let关键字定义变量

从前面我们可以看到,var定义的变量没有块作用域,还有变量提升机制,为了克服这些问题,便引入了let关键字。

我们定义test6.html,输入以下代码:

<script type="text/javascript">
    //循环体
    for(let v = 0;v < 5;v++){
    //在循环体内输出v
        console.log(v);
    }
    //在循环体外输出v
    console.log(v);
</script>

按F12,打开console,看到输出如下:

可以看到在循环体外不能访问循环体内定义的变量。

我们定义test7.html,输入以下代码:

<script type="text/javascript">
    //在函数外使用let关键字声明变量test_var
    let test_var = "函数外的test_var";
    //定义函数testFun
    function testFun(){
        //打印输出test_var
        console.log(test_var);
        //在函数内使用let关键字声明变量test_var
        let test_var = "函数内的test_var"
        //打印输出test_var
        console.log(test_var);   
    }
    //函数执行
    testFun();
</script>

按F12,打开console,看到输出如下:


这是因为函数内有和全局变量同名的局部变量,会覆盖掉全局变量,但是let关键字声明的变量并没有提升机制,所以会报错。

小结

本文介绍了JavaScript中的局部变量和全局变量的知识和var,let声明变量的区别。给我们的启示是如果浏览器支持let关键字,那么就尽量用let来避免变量提升机制等情况。

欢迎关注

扫下方二维码即可关注,微信公众号:code随笔

Javascript中的局部变量、全局变量的详解与var、let的使用区别的更多相关文章

  1. JavaScript中的鼠标滚轮事件详解

    JavaScript中的鼠标滚轮事件详解/*Firefox注册事件*/ ~~~Firefox: addEventListener('DOMMouseScroll', handler, false)if ...

  2. JavaScript中typeof和instanceof深入详解

    这次主要说说javascript的类型判断函数typeof和判断构造函数原型instanceof的用法和注意的地方. typeof 先来说说typeof吧.首先需要注意的是,typeof方法返回一个字 ...

  3. JavaScript 中 apply 、call 的详解

    apply 和 call 的区别 ECMAScript 规范给所有函数都定义了 call 与 apply 两个方法,它们的应用非常广泛,它们的作用也是一模一样,只是传参的形式有区别而已. 原文作者:林 ...

  4. Javascript中的this关键字用法详解

    在javascript里面,this是一个特殊的对象,它不像其他编程语言那样,是存储在实例中的值,直接指向此实例. 而是作为一个单独的指针,在不同的情况之下,指向不同的位置,这也是为什么我们会将它搞混 ...

  5. JavaScript中事件委托(事件代理)详解

    在JavaScript的事件中,存在事件委托(事件代理),那么什么是事件委托呢? 事件委托在生活中的例子: 有三个同事预计会在周一收到快递.为签收快递,有两种办法:一是三个人在公司门口等快递:二是委托 ...

  6. javascript中6种基本数据类型详解

    javascript中有5中数据类型(也称为基本数据类型):Undefined.Null.Boolean.Number和String,还有一种复杂数据类型——object,object本质是由一组键值 ...

  7. JavaScript中继承的实现方法--详解

    最近看<JavaScript王者归来>中关于实现继承的方法,做了一些小总结: JavaScript中要实现继承,其实就是实现三层含义:1.子类的实例可以共享父类的方法:2.子类可以覆盖父类 ...

  8. JavaScript中定义类的方式详解

    本文实例讲述了JavaScript中定义类的方式.分享给大家供大家参考,具体如下: Javascript本身并不支持面向对象,它没有访问控制符,它没有定义类的关键字class,它没有支持继承的exte ...

  9. Javascript中的apply与call详解

    JavaScript中有一个call和apply方法,其作用基本相同,但也有略微的区别. 一.方法定义 1.call 方法 语法:call([thisObj[,arg1[, arg2[, [,.arg ...

随机推荐

  1. codeforce 1188A1 Add on a Tree 树

    题意:给你一个树,有一种操作,选择两个叶子节点,然后把这两个叶子节点间的路径全部加或减一个值.问你给出的树上的每一条边经过若干次操作是否可以为任意值. 分析:画几个图后可以发现,如果树中存在一个点的度 ...

  2. linux操作提示:“Can't open file for writing”或“operation not permitted”的解决办法

    在linux上使用vi命令修改一个文件内容的时候,发现无法保存,每次写完使用":q!"命令可以正常退出但是使用":wq!"命令保存文件并退出时出现一下信息提示: ...

  3. SAP PM:参考维护工单创建测量凭证

    (1)使用FM:CO_BC_ORDER_POST获取工单资料(Aufnr, aufpo and materials etc): (2)使用FM:MEASUREM_DOCUM_RFC_SINGLE_00 ...

  4. 线程中start与run方法的主要区别

    区别一:                在于当程序调用start方法一个新线程将会被创建,并且在run方法中的代码将会在新线程上运行,                然而在你直接调用run方法的时候, ...

  5. H5的localStorage使用总结

    一.localstorage 的优缺点 优点: 1.localStorage 的存储大小是5M,而cookie的存储大小只有4K,解决了cookie存储空间不足的问题 2.localStorage 可 ...

  6. mysql命令运行sql文件

    navicat转储sql,cmd 打开运行 切换到mysql目录下:mysql -uroot -p  回车输入密码 创建数据库语句:  CREATE DATABASE `tcc` CHARACTER  ...

  7. iOS仿抖音节拍界面、Swift,MVVM架构完整项目、日历demo、滚动切换分类等源码

    iOS精选源码 在Object-C中学习数据结构与算法之排序算法 日历-基本功能都有的日历 选择日期 上下月 动画 仿抖音卡节拍界面 垂直.水平方向皆可滚动.header悬浮的列表视图 Auto La ...

  8. spring-boot jpa mysql emoji utfmb4 异常处理

    spring-boot jpa mysql utf8mb4 emoji 写入失败 mysql database,table,column 默认为utf8mb4 Caused by: java.sql. ...

  9. Linux文件与目录管理,常用命令总结

    绝对路径:  以根目录 / 开始的相对路径:  相对于当前路径的写法 $PATH:  可执行文件路径的变量(出现在该变量下的文件可以在系统的任何目录下都可以执行) 获取路径的文件名:    basen ...

  10. 树剖裸题——BZOJ1036 树的统计

    #include<cstring> #include<cmath> #include<algorithm> #include<cstdio> #defi ...