1. 原始表达式(primary expression)
    • 原始表达式是表达式的最小单位,包括:
      • 常量(直接量):直接在程序中出现的常数值
      • 变量
        • 代码中的标识符会被JavaScript当做变量,变量名不存在将返回undefined,ES5严格模式中将抛出一个引用异常错误;
      • 关键字
        • 与其他关键字不同,this不是一个常量,在程序不同地方返回不同的值,方法体内的this返回调用方法的对象;
  2. 对象和数组的初始化表达式
    • 对象初始化表达式(对象直接量)
      • 形式:{属性名1:属性值1,属性名2:属性值2,……}
      • 对象可以嵌套;
      • 属性名可以是字符串;
    • 数组初始化表达式(数组直接量)
      • 形式:[元素1,元素2,元素3,……]
      • 逗号之间的元素省略时,省略的空位会填充undefined;
      • 数组可以嵌套;
  3. 函数定义表达式(函数直接量)
    • 形式:function(参数列表){        函数体        }
      1 var square = function(x){return x*x;}        //返回x的平方给变量square

       

  4. 属性访问表达式
    • 形式1:对象名.属性名
    • 形式2:对象名(或数组名)[属性名(或索引)]
    • 不论哪种形式,若属性不存在,整个属性访问表达式的值式undefined;
    • 当属性名是通过计算得出而不是固定值时,必须使用形式2这种写法;
      1 var a = {x:1,y:{z:2}};
      2 var b = [0,4,[5,6]];
      3 a.x                                    //返回1
      4 a.y.z                                 // 返回2
      5 a["x"]                              //返回1
      6 b[1]                                  //返回4
      7 b[2]["1"]                          //返回6
      8 b[a].x                             //返回1

       

  5. 调用表达式(invocation expression)
    • 用于调用(或执行)函数或方法
    • 函数调用
      • 形式:函数名(参数列表)
      • 通常使用全局对象作为this的值,ES5严格模式中使用undefined作为this的值;
    • 方法调用
      • 形式:属性访问表达式(参数列表)
      • 执行方法时,函数体里面的this指向其访问的对象或数组;
  6. 对象创建表达式(object creation expression)
    • 创建一个对象并调用一个函数(构造函数)来初始化新对象的属性
    • 形式:new 对象名(参数列表)
    • 若不需要传入任何参数给构造函数,参数列表及圆括号都可以省略:new 对象名
  7. 运算符概述
    • JavaScript运算符
      • 表4-1按照运算符优先顺序从高到低排序,被水平线分割的运算符具有不同的优先级,A表示运算符的结合性:L(从左至右结合)或R(从右至左结合);N表示操作数的个数;“类型”列表示期望的操作数类型以及运算符的结果类型("→"之后)
    • 运算符可分为两类:标点符号表示的运算符(如"+"和"=")和关键字运算符(如"delete"和"instanceof");
    • 根据操作数的个数分为:一元运算符(unary operatro),如"-"、二元运算符(binary operator),如"*"、三元运算符(ternary operator),如"?:";
    • 求余运算符计算第一个操作数对第二个操作数的模,结果的符号和第一个操作数的符号一致,整数,浮点数都有求余运算;
    • JavaScript通常会根据需要对操作数进行类型转换;
    • JavaScript中的所有值不是真值就是假值,因此对于希望操作数是布尔类型的操作符来说,其操作数可以是任何类型(any);
    • 运算符的优先级可以通过显示使用圆括号来重写;
    • 属性访问表达式和调用表达式的优先级比表4-1中的所有运算符都高;
    • 结合性指定了具有同样优先级的运算符(表4-1中同一水平线内)的运算顺序;
    • 运算符的副作用
      • 普通的运算符执行后的运算结果不会对程序的运行状态和后续执行的计算产生影响,如2*3;
      • 在函数体或构造函数内部使用了有副作用的运算符并产生副作用时,我们说函数调用表达式或对象创建表达式是有副作用的;
      • 有的运算符执行的运算有副作用:
        • 赋值运算符("="):给一个变量或属性赋值,使用这个变量或属性的表达式的值就会改变,类似的还有"++"、"--";
        • delete运算符:删除一个属性就像给这个属性赋值undefined;
    • 左值(lvalue)
      • 指的是:“表达式只能出现在赋值运算符的左边”
      • JavaScript中的变量、对象属性和数组元素均是左值;
      • ES规范允许内置函数返回一个左值,自定义的函数不能返回左值;
  8. 算术表达式
    • "+"运算符
      • 可对两个数字作加法,也可连接两个字符串;
      • 对于其他情况:
        • 简单来讲,优先考虑字符串连接,如果两个操作数都不是类字符串的,将进行加法运算;
        • 具体来说,"+"的行为表现为:
      • 结合性对最终的运算结果也有影响
    • 一元算术运算符("+"、"-"、"++"、"--")
      • 结合性:右结合(right-associative);
      • "+"、"-"是一元运算符,又是二元运算符
      • 一元加法(+)
        • 把操作数转换为数字(或NaN)并返回,若操作数是数字,直接返回这个数字;
      • 一元减法(-)
        • 把操作数转换为数字,然后改变运算结果的符号;
      • 递增(++)
        • 将操作数转换为数字,数字加1,并将加1后的数值重新赋值给变量、数组元素或对象属性;
        • 表达式++x并不总是和x=x+1完全一样,"++"不进行字符串连接,它总是会把操作数转换为数字并加1;
        • 前增量(pre-increment)运算符:对操作数进行增量操作,并返回增量计算后的值;
        • 后增量(post-increment)运算符:对操作数进行增量操作,返回未做增量计算的值;
      • 递减(--)
        • 与递增运算符类似,不再赘述;
    • 位运算符
      • 对二进制数据(补码表示)进行运算,返回数字;
      • 操作对象是32位整数,若操作数不是32位整数,先转为32位整数(忽略原格式中的小数部分和超过32位的部分);
        • 按位与(&)
          • 逐位执行布尔与(AND)运算
        • 按位或(|)
          • 逐位执行布尔或(OR)运算    
        • 按位异或(^)
          • 逐位执行布尔异或(XOR)运算
        • 按位非(~)
          • 一元运算符,位于操作数之前,将操作数逐位取反。在JS中,对一个值使用"~"相当于将其改变符号并减1,如~0x0F=0xFFFFFFF0或-16;
      • 移位运算符要求右操作数在0~31之间,在将其操作数转换位无符号32位整数后,舍弃第5位之后的二进制位,以便最终生成一个位数正确的数字;
      • 位运算符会将NaN、Infinity和-Infinity都转换为0;
        • 左移(<<)
          • 将第一个操作数的所有二进制位左移第二个操作数个位数,新的位置以0补充,左移一位相当于乘以2,如7<<1=14,-7<<1=-14;
        • 带符号右移(>>)
          • 将第一个操作数的所有二进制位右移第二个操作数个位数,右边的溢出值忽略,最高位是符号位,由原操作数的符号决定,正数的最高位是0,负数的最高位是1,带符号右移一位相当于除以2(忽略余数),如7>>1=3,-7>>1=-4;
        • 无符号右移(>>>)
          • 同带符号右移(>>),但最高位总是以0填充,与原操作数符号无关,如-1>>4=-1,-1>>>4=0x0FFFFFFF; 
  9. 关系表达式
    • 判断两个值之间的关系(相等、小于或“是……的属性”),根据关系是否存在返回true或false;
    • 通常用于控制语句;
    • 相等和不等运算符
      • 相等(==)↔不等(!=)
        • 相等运算符的比较并不严格,如果两个操作数不是同一类型,会先尝试进行类型转换,然后再进行比较:
      • 严格(或恒等)相等(===)↔不严格相等(!==)
        • 严格相等运算符(strict equality,或恒等运算符(identity operator)),用来检测两个操作数是否严格相等,首先计算其操作数的值,然后比较这两个值,比较过程没有任何类型转换:
    • 比较运算符
      • <、>、<=、>=
      • 比较操作符的对象可能时任何类型,但只有数字和字符串才能执行真正的比较运算,其他的都将进行类型转换:
      • 字符串比较区分大小写,所有大写的ASCII字母都“小于”小写的ASCII字母;
      • String.localCompare()
      • String.toLowerCase()将字符串转为全小写;
      • String.toUpperCase()将字符串转为全大写;
    • in运算符
      • 其左操作数是一个字符串或可以转换为字符串,右操作数是一个对象,如果右侧的对象拥有一个名为左操作数的属性名,表达式将返回true;
    • instanceof运算符
      • 其左操作数是一个对象,右操作数是标识对象的类,如果左侧对象是右侧对象的实例(包含对父类(superclass)的检测),表达式将返回true,否则返回false;
      • 所有对象都是Object的实例;
      • JavaScript中对象的类是通过初始化它们的构造函数来定义的,因此,右操作数应当是一个函数,若instanceof的右操作数不是一个函数,将抛出一个类型错误异常,左操作数不是对象将返回false;
      • 要理解instanceof运算符的工作原理,必须理解“原型链”(prototype chain);
  10. 逻辑表达式
    • 逻辑与(&&)
      • 对"&&"的第一层理解:对两个布尔值进行布尔与(AND)操作,只有在两个操作数都是true时才返回true;
      • 对"&&"的第二层理解:对正值和假值进行布尔与(AND)操作,在两个操作数都是真值时返回一个真值,否则返回一个假值;
      • 对"&&"的第三层理解:首先计算&&左侧的表达式,如果是假值,整个表达式的值为假值,返回左边操组数的值(并不对右操作数进行计算),否则,整个表达式的值依赖于&&右侧的操作数,&&的这种行为有时称为“短路”(short circuiting)。
    • 逻辑或(||)
      • 类逻辑与(&&),不同的是,如果左操作数是真值,返回这个真值(并不对右操作数进行计算),否则整个表达式的值依赖于右操作数的值;
    • 逻辑非(!)
      • 将操作数的布尔值取反(先将操作数转换为布尔值再进行取反);
  11. 赋值表达式
    • 赋值运算符:=
    • 带操作的的赋值运算:+=、-=、*=、/=、%=、<<=、>>=、>>>=、&=、|=、^=
    • 表达式计算
      • eval():
        • eval()查找变量和定义新变量和函数的操作和局部作用域中的代码完全一样;
        • 可通过eval()定义一个局部函数:eval("function f(){return x+1;}");
        • 如果在最顶层中调用eval(),它会作用于全局变量和全局函数;
        • 传递给eval()的字符串必须在语法上讲得通;
      • 全局eval()
        • ECMAScript 3中,规定任何解释器不允许对eval()赋予别名,若通过别名调用eval()函数,会抛出一个EvalError异常;
        • ECMAScript 5中,直接调用eval()时,它总是在调用它的上下文作用域内执行,间接调用则使用全局对象作为其上下文作用域,并且无法读、写、定义局部变量和函数;
           1 var geval = eval;                    //为eval赋予别名geval
           2 var x = "global",y = "global";             //两个全局变量
           3 function f(){
           4   var x = "local";                               //局部变量x
           5   eval("x += 'changed';");              //直接eval改变了局部变量x的值
           6   return x;                                    //返回更改后的局部变量
           7 }
           8 
           9 function g(){
          10   var y = "local";                      //局部变量y
          11   geval("y += 'changed';");                 //间接eval改变了全局变量y的值
          12   return y;                                //返回未更改的局部变量
          13 }    
          14 
          15 console.log(f(),x);                  //更改了局部变量,输出:localchanged global
          16 console.log(g(),y);                 //更改了全局变量,输出:local globalchanged

           

      • 严格eval()
        • ECMAScript 5 严格模式下,eval执行的代码段可以查询或更改局部变量,但不能在局部作用域中定义新的变量或函数;
        • 严格模式下,将eval列为保留字,不能作为标识符,不能用一个别名覆盖eval()函数。
  12. 表达式计算
  13. 其他运算符
    • 条件运算符(?:)
      • JavaScript中唯一的三元运算符
    • typeof运算符
        • 一元运算符,返回表示操作数类型的一个字符串,带不带括号都可,如:
          typeof运算后的返回值
          x type x
          undefined "undefined"
          null "object"
          true或false "boolean"
          任意数字或NaN "number"
          任意字符串 "string"
          任意函数 "function"
          任意内置对象(非函数) "object"
          任意宿主对象 由编译器各自实现的字符串,但不是"undefined"、"boolean"、"number"或"string"
    • delete运算符
      • 删除对象属性或数组元素
      • 一元运算符,操作数要求为左值,删除成功返回true,不是左值时不进行任何操作并返回true
      • 非法删除:通过var声明的变量不可删除,通过function定义的函数及函数参数不可删除
      • ES 5严格模式中非法删除会抛出语法错误异常,删除不可配置的属性时会抛出类型错误异常
    • void运算符
      • 忽略操作数的计算结果并返回undefined
      • 可用于<a>中
        1 <a href="javascript:void window.open();">打开一个新窗口</a>

         

    • 逗号运算符(,)
      • 二元运算符,先计算左操作数,再计算右操作数,最后返回右操作数的值
      • 总是会计算左操作数,但忽略掉
posted on 2021-07-30 14:20  KK的备忘录  阅读(193)  评论(0)    收藏  举报