javascript语句和表达式

JavaScript 语句和表达式

1. 表达式和语句的区分

  • 表达式 是 JavaScript 中的一个短语,JavaScript 解释器会将其计算出一个结果;语句就是 JavaScript 整句或者命令,表达式计算出一个值,但语句用来执行以使某件事件发生。
  • 一个表达式会产生一个值,在任何需要为值的地方都可以放置;语句代表着行为,一条语句中可以包含多个表达式,一个程序是由一系列可执行语句组成的
  • JavaScript 中某些需要语句的地方,可以使用表达式代替,称之为表达式语句;但是不能在一个需要表达式的地方放置一个语句
  • 语句以 ; 结尾,一个 ; 就表示语句结束,一行内可以有多个语句,; 前如果没有内容则视为空语句;表达式不需要 ; 结尾,如果加了 ; javascript 会将其视为语句

2. 表达式组成

1. 基本的表达式

    /*
        1. 原始表达式, Javascript 中的原始表达式包含常量/直接量、关键字、变量
            直接量就是直接出现的常数值
    */ 
    1.23 // 数字直接量 
    'hello' // 字符串直接量
    true null this // 保留字、关键字
    sum undefined // undefined 是全局变量,不是一个关键字

    /*
        2. 对象和数组初始化表达式
            实际上是一个新创建的对象或者数组,因为他们所包含的成员或者元素都是子表达式,所以他们本身不是原始的表达式。
    */
    [] [2 * 7, 3 + 4]     // 数组初始化表达式
    {x: 'xxx', y: {yx: 'yxyx'}}  // 对象初始化表达式

    /*
        3. 函数定义表达式
            定义一个函数,表达式的值是这个新定义的函数
    */
    var fn = function () {};

    /*
        4. 属性访问表达式
            运算得到一个对象属性或一个数组元素的值
    */
    var arr = [12, 33];
    var obj = {name: 'obj'};
    arr[0] // 数组arr索引为0 的元素
    obj.name // 表达式obj 的 name 属性

    /*
        5. 调用表达式    
            是一种调用或者执行函数的语法表示
    */
    fn(0)
    Math.max(x, y, z)

    /*
        6. 对象创建表达式
            会创建一个对象并调用一个函数(构造函数)
    */
    var a = new Parent('name') // 通过 new 关键字创建
    var b = new Parent // 如果不需要传递参数则括号可以省略

2. 使用运算符的表达式

1. 算术表达式

以数值作为其操作数,并返回一个单个数值

    1+ 2 // 3 加法
    true + 2 // 3 隐式转换
    1 + 'a' // '1a' 字符串拼接

    5 - 2 // 3 减法
    'a' - 4 // NaN

    1 / 2 // 0.5 除法
    2 / 0 // Infinity

    2 * 2 // 乘法
    Infinity * 0 // NaN 

    12 % 5 // 2 求余

    2 ** 3 // 8 幂
    -(2 ** 3) // -8
    -2 ** 3 // 报错 

    var x = 3;
    x-- // 表达式 = 3; x = 2 递减
    --x // 表达式 = 2;x = 2 
    x++ // 表达式 = 3;x = 4 递增
    ++x // 表达式 = 4;x = 4  

    -3 // -3 一元负号
    +3 // 3 一元正号
    +'3' // 3 转换类型为 number
    +true // 1 '+' 是类型转换推荐做法
    +function () {} // NaN 无法转换
2. 关系表达式

测试两个值之间的关系

JavaScript 中有两种比较方式,严格比较运算符和转换类型比较运算符

  • 严格比较运算符===,仅当两个操作数的类型相同且值相等为 true
  • 转换类型比较运算符==,会在进行比较之前,将两个操作数转换成相同的类型
    1 == 1 // true 相等运算符
    '1' == 1 // 类型装换
    0 = false 

    1 != 2 // true 不相等运算
    1 != '1' // false 

    3 === 3 // true 严格相等运算
    3 === '3' // false 

    3 !== '3' // true 严格不相等运算

    4 > 3 // true 大于运算符
    4 >= 3 // true  大于等于运算符
    3 < 4 // true 小于运算符
    3 <= 4 // true 小于等于运算符
3. 逻辑表达式

逻辑运算符通常用于布尔型值

    /* 
        逻辑与 && ,常用来链接两个关系表达式,两个表达式的值转化为布尔值后,都为 真值 表达式的值才为 真,实际上运算符会首先计算左侧表达式,如果计算结果是 假值,那么 '&&' 简单的返回左侧表达式的值,而不会对右侧表达式进行计算;如果左侧表达式值为 真,'&&' 将计算右侧表达式的值并将其返回
    */
    true && true // true
    fasle && true // false
    '' && true // ''
    true && 88 // 88

    /*
        逻辑或 || ,与 && 类似,会先计算左侧表达式,为真,则返回真值,为假,则计算右侧表达式,并返回右侧表达式的结果
    */    
    true || true // true 
    false || true // true
    '' || null // null

    /*
        逻辑非 ! ,目的是将操作数的布尔值取反,'!' 会首先将操作数转换为布尔值,然后在对布尔值求反
    */
    !false // true
    !null // true
    !!null // false
    !![] // true // 空对象、空数组的等价布尔值都为 true
4. 赋值表达式

JavaScript 使用 = 运算符来给变量或者属性赋值

  • = 运算符左侧为左值: 一个变量或者对象属性
  • = 运算符右侧为右值:可以是任意类型的值
  • 赋值表达式的值就是右侧表达式的值
  • 赋值表达式具有副作用,右侧的值赋值给了左侧的变量或者属性
    var b = a = 7; // 'a = 7' 是一个赋值表达式,这个表达式的值为 右侧表达式为 7,然后在将其赋值给变量 b
    (a = 7) == 6 // false 
    let c = b = d = a = 3; // 四个变量都赋值为 3

    // 代操作的赋值运算
    var a = 2;
    a += 1; // 3 加赋值
    a -= 1; // 1 减赋值
    a *= 2; // 4 乘赋值
    a /= 2; // 1 除赋值
    a %= 3; // 2 模赋值
5. 条件运算符

条件运算符是 Javascript 中唯一一个三元运算符,经常作为 if 语句的简短形式来使用 condition ? expr1 : expr2

  • condition: 计算结果为true或false的表达式。
  • expr1、expr2: 任何类型的表达式

如果条件值为真,运算符就会返回 expr1 的值,否则返回 expr2 的值

    var a = true ? 'success' : 'fail'; // success

    var c = false 
        ? 'a-success'
        : true ? 'b-success' : 'a-b-fail'; //  'b-success' 多个三元操作符

    var a = null, b = null;
    false ? a : b = 'value'; // a = null , b = 'value' 三元操作符用在等式的左边

    const a = false ? ( // expr1、expr2 中可以有多个操作
        alert('success'),
        'success'
    ) : (
        alert('fail'),
        'fail'
    );
    console.log(a);
6. 逗号运算符

对它的每个操作数求值(从左到右),并返回最后一个操作数的值

    var a = (12, 23, 45); // 45
7. 解构赋值

解构赋值语法是一个 Javascript 表达式,这使得可以将值从数组或属性从对象提取到不同的变量中

    var foo = ["one", "two", "three"];
    var [one, two, three] = foo; // 变量声明并赋值 时的解构
    var a, b;
    [a, b] = [1, 2]; // 变量先声明后赋值 时的解构
8. 圆括号运算符

用来控制表达式中的运算优先级

    (1 + 2) * 3 // 9
    (1 + 2, 10) * 3 // 30 结合逗号运算符 ()返回值为最后一个操作数的值 10
9. delete 运算符

delete 用来删除对象的属性或者数组元素,delete 具有副作用,它是用来删除一个值的,虽然会有返回值,但是这不是他的目的,删除一个属性时,这个属性将不会存在,而不是简单的设置为 undefined

对于所有情况 delete 操作的返回值都是true,除非属性是一个自己的不可配置属性,在这种情况下,非严格模式返回 false。

    var obj = {name: 'obj'};
    var a = delete obj.name; // a = true, obj = {}    
10. in 运算符

in 运算符的左操作数是一个字符串或者可以转换为字符串,他的右操作数是一个对象,如果右侧的对象拥有一个名为左操作数值的属性名,那么表达式返回 true

    var obj = {name: 'obj'};
    var a = 'name' in obj; // true
    var b = 'age' in obj; // false

    var arr = [12, 23, 34];
    var a = 2 in arr; // true
    var b = 'length' in arr; // true

如果你只是将一个属性的值赋值为undefined,而没有删除它,则 in 运算仍然会返回true

如果一个属性是从原型链上继承来的,in 运算符也会返回 true。

11. instanceof 运算符

instanceof 运算符希望做操作数是一个对象,右操作数标识对象的类。如果左侧的对象是右侧类的实例,则表达式返回 true 否则返回 false ,用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性

    function A(){}
    var a = new A();

    console.log(a instanceof A); // true
    console.log(a instanceof Object); // true
12. typeof 运算符

typeof操作符返回一个字符串,指示未经计算的操作数的类型

Undefined “undefined”
Null “object”
Boolean “boolean”
Number “number”
String “string”
Symbol “symbol”
函数对象 “function”
任何其他对象 “object”

3. 语句分类

1. 表达式语句

具有副作用的表达式是javascript 中最简单的语句,例如 赋值语句、函数调用语句

    var a = 'a'; // 赋值语句
    window.close(); // 函数调用语句

2. 复合语句和空语句

块语句,也称为复合语句,用于组合多个语句,块由一对大括号界定

  • 语句块的结尾不需要分号,块内的原始语句要使用分号结束
  • 使用 let 或者 const 声明的变量是有块级作用域的

空语句是一个分号(;),表示不会执行任何语句

    // 块语句
    let x = 1;
    {
      let x = 2;
      alert(x); // 2
    }
    console.log(x); // 输出 1
    // 空语句
    ;

3. 声明语句

  1. var 语句用来声明一个或者多个变量,如果出现在函数体内,那么他定义的是一个局部变量,作用域就是这个函数,

  2. let 语句声明一个块级作用域的本地变量,并且可选的将其初始化为一个值,它声明的变量只能是全局或者整个函数块的

  3. const 与使用 let 语句定义的变量类似, 但是它声明的是常量,不能通过重新赋值更改,并且不能重复声明

  4. function 函数声明定义一个具有指定参数的函数,一个被函数声明创建的函数是一个 Function 对象,具有 Function 对象的所有属性、方法和行为

  5. function* 这种声明方式(function关键字后跟一个星号)会定义一个生成器函数,它返回一个 Generator 对象, 生成器函数在执行时能中途退出,后面又能重新进入继续执行。而且在函数内定义的变量的状态都会保留,不受中途退出的影响。更多查看

  6. async function 函数声明将定义一个异步函数,返回 AsyncFunction 对象。调用 async 函数时会返回一个 Promise 对象。当这个 async 函数返回一个值时,Promise 的 resolve 方法将会处理这个值;当 async 函数抛出异常时,Promise 的 reject 方法将处理这个异常值。async 函数中可能会有 await 表达式,这将会使 async 函数暂停执行,等待 Promise 正常解决后继续执行 async 函数并返回解决结果。更多查看

    var a = 'sss';
    let a = 'sss';
    const a = 'sss';
    function fn () {}

    function* idMaker(){
      var index = 0;
      while(index<3)
        yield index++;
    }
    var gen = idMaker(); 
    console.log(gen.next().value); // 0
    console.log(gen.next().value); // 1

    async function add2(x) {
      var a = await resolveAfter2Seconds(20);
      var b = await resolveAfter2Seconds(30);
      return x + a + b;
    }

4. 条件语句

  1. if () {} else if () {} else {}条件语句是通过判断指定表达式的值来决定是执行还是跳过某些语句
    let status = 'a';
    if (status === 'a') {
        doingA();
    } else if (status === 'b') {
        doingB();
    } else {
        doingElse();
    }
  1. switch () {case: ...} switch 语句评估一个表达式,将表达式的值与case子句匹配,并执行与该情况相关联的语句,如果你忘记添加break,那么代码将会从值所匹配的 case 语句开始运行,然后持续执行下一个 case 语句而不论值是否匹配
    let status = 'a';
    switch (status) {
        case 'a': 
            doingA();
            break;
        default: 
            doingElse();
    }

5. 循环语句

循环语句就是程序路径的一个回路,可以让一部分代码重复执行

  1. while 属于前测试循环语句,也就是说在循环体内的代码执行之前,就会对出口条件求值,因此循环体内代码可能永远不会执行
    var i = 0;

    while (i < 100) {
      console.log('i当前为:' + i);
      i += 1;
    }

    while(true) { // 无限循环
        console,log(true);
    }
  1. do-while 是一种后测试循环语句,即只有在循环体中代码执行之后,才会测试出口条件,换句话说,在对表达式求值之前,循环体内的代码至少会被执行一次
    var x = 3;
    var i = 0;

    do {
        console.log(i);
        i++;
    } while (i < x); // 注意,这里的分号不要省略
  1. for 是一种前测试循环语句,但它具有在执行循环之前初始化变量和定义循环后要执行代码的能力,for 语句对常用的循环模式做了一些简化,大部分的循环都具有特定的计数器变量,循环开始之前要初始化这个变量,然后每次循环都要检测一下他的值,最后计数器变量做自增操作,在这一类循环中,计数器的三个关键操作是初始化、检测和更新。for 语句就将这三步操作明确声明为循环语法的一部分,各自使用一个表达式来表示
    for(initialize; test; increment) {
        /*
            initialize: 初始话操作
            test: 循环条件判断
            increment: 计数器变量的更新
        */
    }

initialize; test; increment 放在循环的第一行会更容易理解 for 循环正在做什么,而且也可以防止忘记初始化或者递增计数器变量

  • initialize 表达式只在循环开始前执行一次,初始化表达式应当具有副作用(通常是一个赋值语句)
  • 每次循环执行之前都会执行 test 表达式,并判断表达式的结果来决定是否执行循环体
  • 如果 test 执行结果为真值,则最后执行 increment 表达式,他也须要具有副作用
    // 一般的 for 循环
    for (var count = 0; count < 10; count++) {
        console.log(count);
    }
    // 需要多个变量的 循环
    for (var i = 0, j = 10; i < j; i++, j--) { // 使用逗号操作符将多个表达式隔开
        console.log({i, j});
    }
    // 无线循环
    for (;;) {
        console.log('');
    }
  1. for-in 语句也使用 for 关键字,但是它和常规的 for 循环是完全不同的一类循环,通常用来遍历一个对象的可枚举属性,因为迭代的顺序是依赖于执行环境的,所以数组遍历不一定按次序访问元素。因此当迭代访问顺序很重要的数组时,最好用整数索引去进行for循环
    var obj = {a:1, b:2, c:3};

    for (var prop in obj) {
      console.log("obj." + prop + " = " + obj[prop]);
    }
    // 一下方法可以将对象的属性赋值到数组中
    var obj = {a: 1, b: 2, c: 3};
    var arr = [], i = 0;
    for (arr[i++] in obj);

    console.log(arr); //  ["a", "b", "c"]

for-of 循环,在可迭代对象上创建一个迭代循环,调用自定义迭代钩子,并为每个不同属性的值执行语句

    // 迭代 数组
    let iterable = [10, 20, 30];

    for (let value of iterable) {
        value += 1;
        console.log(value);
    }

    // 迭代 字符串
    let iterable = "boo";

    for (let value of iterable) {
      console.log(value);
    }

6. break 和 continue 语句

break语句和continue语句都具有跳转作用,用于在循环中精确的控制代码的执行,

  • break 语句会立即退出循环,强制继续执行循环后面的语句。
  • continuen 语句虽然也是立即退出循环,但退出循环后会从循环的顶部继续执行
    // break;
    var num = 0;
    for (var i = 0; i < 10; i++) {
        if (i === 5) break;
        num++;
    }
    console.log(num, i); // 5, 5 

    // continue;
    var num = 0;
    for (var i = 0; i < 10; i++) {
        if (i === 5) continue;
        num++;
    }
    console.log(num, i); // 9, 10

7. label 语句

标签语句,通过给语句定义标签,就可以在程序中通过标签引用这条语句,通常与 循环中的 break 语句 和 continue 语句配合使用,跳出特定的循环

    // 没有标签 break 只能跳出内层循环,跳出后还需要进行外层循环
    for (var i = 0; i < 4; i++) {
        for (var j = 0; j < 4; j++) {
            if(i + j > 3) break; 
            console.log(i, j, i + j);
        }
    }

    // label : for... 给 for 循环语句定义了标签, 这时候 break 就可以直接跳出外层循环了
    label : for (var i = 0; i < 4; i++) {
        for (var j = 0; j < 4; j++) {
            if(i + j > 3) break label;
            console.log(i, j, i + j);
        }
    }

8. throw 语句

用于抛出一个用户自定义的异常, 出现这个语句,当前函数的执行将被停止,之后的语句不会执行

    if (status === 401) {
        throw 401;
    }

9. try…catch…finally语句

将可能引发错误的代码放在 try 块中。catch 子句中包含 try 块中抛出异常时的执行语句, finally 在 try 和 catch 后执行,无论是否有异常抛出都会执行

    try {
        throw 'error';
    } catch (e) {
        console.log(e); // error
    } finally {
        console.log('finally'); // finally
    }

参考

  1. JavaScript 标准参考教程
  2. MDN JavaScript
  3. javascript高级程序设计
  4. JavaScript权威指南

你可能感兴趣的:(JavaScript)