• Javascript浅谈之表达式和语句的区别


    简介

      表达式(expressions)和语句(statements)在javascript非常常见,但是就是这些常见的元素,有时候我们也未必能够正确的领会其要表示的含义和用法。这是因为我们总是对常见的东西本能的表示默认,好像它天生就该如此,为很少去考虑其背后所代表的含义。比如:if的条件中为什么能有赋值,立即执行函数为什么要用小括号给括起来调用等。

      在区分表达式和语句之前,我们先分别对他们进行介绍:

      1.表达式(expressions)

        表达式是由运算符构成,并运算产生结果的语法结构。每个表达式都会产生一个值,它可以放在任何需要一个值的地方,比如,作为一个函数调用的参数.下面的每行代码都是一个表达式:

    var a = (5 + 6) / 2; //表达式:(5 + 6) / 2
    var b = (function(){ return 25;})(); //表达式: (function(){ return 25;})()
    foo(a*b); //表达式:a*b

      2.语句(statements)

        语句则是由“;(分号)”分隔的句子或命令如果在表达式后面加上一个“;”分隔符,这就被称为“表达式语句”。它表明“只有表达式,而没有其他语法元素的语句”。

    var a = (5 + 6) / 2; //整行,赋值语句
    if(a>12) { statements} //条件语句
    var o = {}; //赋值语句
    (function(obj){ obj.b = 23;})(o||{}); //表达式语句

      一般的javascript中的语句分为下面几种:

      (1)声明语句:变量声明和函数声明

      (2)赋值语句

      (3)控制语句:能够对语句执行顺序产生改变,包括条件语句和循环语句,当然还有比较特殊的标签语句。

      (4)表达式语句:这些语句去掉最后分号,都也可当表达式用的。常见的有:对象操作(new、delete)、函数调用(函数执行,必有返回值)等。

    var num = 9; //声明、赋值语句
    vloop: //标签语句
    {    //其实这里大括号可以不需要的,在这里我只想向大家展示一下这种代码块结构而已
         for(var i=1; i<10; i++) { //循环语句
                if(i==num){ //条件语句
                      break vloop;
                }else{
                      num = num - 1; 
                }      
         }  
    }     
    console.log(num); //表达式语句,输出:5 

      由上面可以看出,表达式和语句还是存在很大区别的,可也说表达式是语句的构成部分,而语句则又可以组成可执行代码块。一般而已,我们都可以很直观的看出两者的区别,但是,一些特殊情况就不太好区别。

    难以区分的表达式和语句

     1.对象字面量和代码块

    var o = {
         a : {},
         b : "string"    
    }

          上面是一个简单至极的对象字面量,但是我们单单从代码的直观层面来看,这个字面量其实跟代码块非常相似,由两个标签语句组成的感觉。复杂些上,还有上面之前我在语句最后举得那个例子,例子中代码块位于标签语句下面,里面包含有个for循环。这时候,你说这个由{}构建的代码块是表达式呢还是语句

      2.命名函数表达式

      javascript中有三种函数类型:函数声明,函数表达式和函数构造器创建的函数。

      (1)函数声明(FD)

      function foo(){ statements; }

      (2)函数表达式(FE)

      var foo = function(){ statements;}

      还有一种比较特殊点的:var foo = function _foo() { statements;} ,这是时候,给函数一个供内部使用的名字_foo,所有,此时,这种类型又称:命名函数表达式(NFE)。

      (3)函数构造器创建

      var foo = new Function(expressions);

      其实上面说了函数的三种类型并不是我们这章的主要重点,这这我们也是探讨一下FD和NFE的一些区别而已,关于其他函数内容后面我单独在细说。

      是不是看到FD和NFE的形式之后,又有点点迷糊了,NFE除了前面多了一个var和变量名之外,其他和FD的结构一模一样,这样的话,那是不是说明FD既可以作声明语句,也同时可以作赋值表达式呢

      解答之前两个疑惑

      鉴于上面两个比较让人迷惑的语法点,javascript它自己也认识到不足,之后果断改进,做出了如下声明:JavaScript语法禁止表达式语句以大括号或关键字"function"开头

    知错能改善莫大焉,当知道javascript做出如此强制的规约时,就一下子对前面两个疑惑有了答案。

      在这之前,我们还要想提下三个概念:语句上下文、表达式上下文和表达式语句。

      语句上下文:在这个环境中,这这句代码(表达式或者语句)应该理解成一个语句。

      表达式上下文:在这个环境中,这句代码(表达式或者语句)应该理解成一个表达式。

      表达式语句:这个表达式既可以看作是一个表达式(因为它能产生一个值),又可以看作是一个执行语句(因为它能执行某些功能,比如执行一个函数等)。表达式语句可以是javascript链式编程的基础。

      上面这个概念起辅助理解作用,不用做过深追究。

      我们再来看之前的那两个疑惑:

      第一个,vloop的冒号后面由大括号中那一段代码,里面都有循环和赋值等操作,那说明它都不是一个表达式语句,所以它不必遵循上面的规定。在这其实它只是一个代码块语句而已。不过对于对象字面量而言,它确实一个货真价实的表达式语句,根据规约,它就只能乖乖的做表达式,不能做语句。

      第二个,对于NFE类型函数来说,你可以将它看作是一个函数申明语句,同时也可以将之看成一个表达式,但是根据javascript的规定,表达式语句不能以function开头,所有在这,NFE中的肯定是表达式了。当然,对于FD,这个很明显,是函数声明语句,不用怀疑。

      其实,还有另一种判定方法,根据上下文判断,利用之前我们说过语句上下文和函数上下文。对于一个表达式语句,当你无法区分它是表达式还是语句,你参照上下文,判断程序在这需要做什么,是变量赋值?还是语句执行?看到前面由“=”(赋值)或者用“()”(小括号,在这时分组符,里面只能包含表达式),你就可以肯定,这是一个表达式上下文。javascript的解释器就是这个干的。

    var foo = function _foo(index){ 
        console.log("传入的参数是:"+index||"空值")
    }(1);  //输出:传入的参数是:1
    console.log(foo);  //输出:undefined
    //根据上下文判断,"var foo = "后面是表达式上下文,所有解释器自动将后面看成一个立即执行函数,虽然没有小括号。
    
    function foo(index){ console.log("传入的参数是:"+index||"空值") }(1) //输出:1 console.log(foo); //function foo(index){...} //解释器判断此为语句上下文,所以讲语句拆分为两段。前一段为函数声明,后一段“(1)”为一个简单的分组语句。

      看到上面,你是不是灵机一动,发现你居然可以强制将表达式语句转换成表达式了!

      转换方法:

      (1)利用小括号,也就是分组符号(分组符内只允许表达式),进行转换。

    var o;
    
    o = eval("{obj:'this is a object'}")
    console.log(o); //this is a object
    
    o = eval("({obj:'this is a object'})")
    console.log(o); //Object {obj: "this is a object"}

    前者eval中没有加小括号,运行时被认为是一条语句执行,所以o被赋值成义字符串了;而后者,被认为是加上小括号,被认为是在表达式上下文中执行,所有返回一个对象。

      (2)利用运算符,因为javascript引擎会认为这是参与运算的必须是表达式。

    +function(index){ 
        console.log("传入的参数是:"+index||"空值");
         return index;
    }(1)
    //输出:传入的参数是:1
    //表达式结果是:1

      记得上面我也运行过这个句代码,不过当时前面少了个加号(“+”)。比较一下两者的结果。

    总结

      通过以上分析,不知道大家对表达式和语句是不是有点豁然开朗的感觉,反正我觉得我是通过写blog加深了对javascript的理解。我总是渴望把我所领会到的知识尽我之力,分享出来,可能会有不对,但是自己感觉到的是收获与成长,希望大家看过之后有问题可以交流一下。我会继续努力。

  • 相关阅读:
    leetcode 75 颜色分类 A
    leetcode525连续数组 A
    WCF无身份验证配置
    三读设计模式
    EntityFrameWork+Oracle学习笔记搭配环境(一)
    EntityFrameWork+Oracle学习笔记DBfirst(二)
    用Python解答百度测试开发算法面试题
    Python实现采集wordpress整站数据的爬虫
    吾八哥学Python(六):运算符与表达式
    吾八哥学Python(四):了解Python基础语法(下)
  • 原文地址:https://www.cnblogs.com/jink/p/3481112.html
Copyright © 2020-2023  润新知