js 表达式和运算符

JavaScript 解释器会将表达式计算出一个结果,程序中最常见的变量就是一种表达式。变量名也是一种表达式。复杂表达式是由简单表达式组成的,最常用的方法是使用运算符。

表达式

原始表达式

原始表达式是表达式的最小单位,通常包含:

  • 常量
  • 直接量
  • 关键字
  • 变量

对象和数组的初始化表达式

  • 数组表达式
    • []
    • [1+2,3+1]
    • var matrix = [[1,2,3],[1,2,2],[2,3,1]];
    • [0,,,1]
  • 对象表达式
    • var p = {name: "Hiraku", age: 17};
    • var q = {};
    • q.x = 2.3
    • var data = {casData:{cas: canvas, ctx: context}, lineData{lineStyle:"red",lineWidth:2}}
  • 函数定义表达式
    • var square = function(x){ return x * x};
  • 访问对象属性的方式
    • obj.key;
    • obj[key];
  • 调用表达式: 函数表达式开始,这个函数表达式指代了要调用的函数,函数表达式后是一对圆括号,括号内是以逗号隔开的参数;
    • f(0);
    • Math.max(1,2,3);
  • 对象创建表达式
    • new Object()
    • new Point(1,3)
    • 无参数时()可以省略: new Object

运算符

ECMAScript 描述了一组用于操作数组的操作符,分为算术操作符、位操作符、关系操作符合相等操作符。对于对象,相应的操作符通常都会调用对象的 valueOf() 方法或者 toString() 方法。

比较、typeof、+、-、*、/、%、=、==、===、三元、逻辑运算符

  • 比较运算符
    • <
    • >
    • =

    • <=
    • !=
  • 判断数据类型
    • typeof(变量名);
  • 算术运算符
    • 加运算:
      • 两个数据类型都为数字类型变量相加,得到的是数字类型。
      • 一个为数字类型的变量和一个为字符串类型的变量相加,得到的是一个字符串类型,加号起一个连接的作用。
    • 减运算
      • 如果两个变量都为数字类型相减,得到的是数字类型。
      • 如果一个为数字类型的变量,一个为数字字符串,相减得到的是数字类型。
      • 如果一个为数字类型的变量,一个为非数字字符串,相减得到的NaN,数字类型。
    • * 乘运算
      • Inifinity 与 0 相乘, undefined。
    • / 除运算
      • 两个都为数字类型的变量,相除得到的是数字类型。
      • 如果一个为数字类型的变量,一个为数字字符串变量,相除得到的是数字类型。
      • 如果一个为数字类型的变量,一个为非数字字符串,相除得到的NaN,数字类型。
      • 如果0作为除数,得到的是infinity(无限大),是一个数字类型。
      • 0 / 0 是 undefined。
      • Infinity / Infinity 结果是 NaN。
    • % 取余数
  • ()优先级
    • 先计算()括号里边的值。
  • 等号运算符
    • “=” 赋值预算符
    • “==” 比较运算符: 只判断内容是否相同,不判断数据类型。
    • “===” 比较运算符: 不仅判断内容是否相同,还判断数据类型是否相同。
    • “!=” 不等于: 只判断内容是否不相同,不判断数据类型。
    • “!==” 不等于: 不仅判断内容是否不相同,还判断数据类型是否相同。
  • 三元运算符
    • 语法:
      • 表达式?如果表达式的值为true,执行表达式后边的代码,如果值为false,执行冒号后边的值。
      • 三元运算符可以理解为if..else的另外一种写法。
  • 逻辑运算符:逻辑运算的前提是参与运算的变量结果为Boolean类型。
    • 或(||)
      • 参与运算,只要满足一个为true,或运算最后的值为true.
      • 参与运算的值都为false,或运算最后的值为false.
    • 且(&&)
      • 参与运算,只要满足一个为false,或运算最后的值为false.
      • 参与运算,都为true的时候,且运算最后的值为true.
    • 非(!)
      • 如果运算结果为true,非运算结果为false
      • 如果运算结果为false,非运算结果为true.

  • 如果操作数是一个对象,返回 false
  • 如果操作数是一个空字符串,返回 true
  • 如果操作数是一个非空字符串,返回 false
  • 如果操作数是数值 0 ,返回 true
  • 如果操作数是任意非 0 数值,包括 Infinity ,返回 true
  • 如果操作数是 null ,返回 true
  • 如果操作数是 NaN ,返回 true
  • 如果操作数是 undefined ,返回 true

  • 如果第一个操作数是对象,返回第二个操作数;
  • 如果第二个操作数是对象,只有第二个数求值结果为 true 是,返回该对象
  • 如果两个都是对象,返回第二个;
  • 如果有一个操作数是 null ,返回 null
  • 如果有一个操作数是 NaN ,返回 NaN
  • 如果有一个操作数是 undefined ,返回 undefined

  • 如果第一个操作数是对象,返回第一个;
  • 如果第一个操作数求值结果 false ,返回第二个
  • 如果两个都是对象,返回第一个;
  • 如果两个操作数是 null ,返回 null
  • 如果两个操作数是 NaN ,返回 NaN
  • 如果两个操作数是 undefined ,返回 undefined

总结逻辑运算符:

  1. &&和||都采取短路运算,即第一个能够决定结果就不再看第二个了
  2. && 的要求比较宽松 要两个都是true才是true 所以看到第一个是false就没有必要继续完后看了
  3. || 的要求比较严格,要两个都是false才是false,所以看到第一个是true就没有必要继续完后看了
  4. &&和||不但可以操作布尔类型的值,对其他类型的值也可以进行操作,并返回可以决定表达式结果的那个值。

自增自减

  • ++i,i++
    • 在没有参加运算的情况下,++i i++都是在变量的基础上加1。
    • 在参加运算的情况下:
1
2
3
var n1=123;
var n2=n1++; // 先把n1的值赋给n2,然后n1执行加1的操作。
Var n2=++n1; // 先执行n1加1的操作,再赋值给n2.

总的来说:

  • 递增++ 递减–
  • a++ 先参与运算 后自加
  • ++a 先自加 后参与运算

注意:

  • 在应用于一个包含有效数字字符串是,先将其转换为数字值再执行加减1的操作。
  • 在应用于一个不包含有效数字字符的字符串时,将变量的值设置为 NaN。
  • 在应用于布尔值 false 时,先将其转换为 0 再执行加减 1 的操作。
  • 在应用于布尔值 true 时,先将其转换为 1 再执行加减 1 的操作。
  • 在应用于对象时,先抵用对象的 valueOf 方法以取得一个可供操作的值,然后对该值应用前面的规则。如果结果是NaN,则调用 toString() 方法后再应用前述的规则。

带操作的赋值运算符

带操作的赋值运算符

位操作符

0 正 1 负,最高位表示符号位。正数和负数都是以二进制码来存储,但负数使用的格式是二进制补码。计算过程如下:

  • 求这个数绝对值的二进制码;
  • 求二进制反码;
  • 得到的反码加 1。

ECMAScript 中,对 NaN, Infinity 值应用位操作时,这两个值都当做 0 来处理。

  • 按位非(~)
  • 按位与(&)
  • 按位或(|)
  • 按位异或(^)
  • 左移(<<)
  • 有符号右移(>>)
  • 无符号右移(>>>)

instanceof 操作符

测试对象类,左操作数是一个对象,右操作数是标识对象的类。如果左侧的对象是右侧类的实例,则表达式返回true,否则返回false。

in 操作符

判断属性是否存在, in 运算符希望它的左操作数是一个字符串或可以转换为字符串,希望它的右操作数是一个对象,如果右侧的对象拥有一个名为左侧操作数值的属性名,那么表达式返回true。

操作符优先级

操作符优先级

eval()

eval() 是一个函数,但它已经被当做运算符来对待了。

eval()

eval() 只有一个参数。如果传入的不是字符串,直接返回这个参数,如果是字符串,会把字符串当成 JavaScript 代码进行编译,如果便以失败抛出异常,编译成功则执行这段代码。返回字符串中最后一个表达式或语句的值,如果最后一个表达式中没有返回值,则返回 undefined。

eval() 它使用了调用它的变量作用域环境。它查找变量的值和定义新变量和函数的操作和局部作用域中的代码完全一样。

全局的 eval()

eval() 具有改变局部变量的能力。当直接使用 “eval” 名称来调用 eval() 函数时,通常称为”直接 eval”.直接调用 eval() 时,它总是调用它的上下文作用域内执行。其它间接调用使用全局对象作为其上下文作用域,并且无法读、写、定义局部变量和函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var geval = eval;
var x = "global", y = "global";
function f(){
var x = "local";
eval ("x += 'changed'");
return x;
}
function g(){
var y = "local";
geval ("y += 'changed'");
return y;
}
console.log(f(),x);
console.log(g(),y);

严格的 eval()

ECMAScript 5 严格模式中,eval() 是私有上下文环境中的局部 eval(),eval() 执行的代码段可以查询或更改局部变量,但不能在局部作用域中定义新变量。

eval总结

  • 函数是封装了一段可以重复执行的代码
  • eval方法的功能:执行一段JS代码(封装了代码)
  • 在eval方法中没有作用域的概念(ES5严格模式有了独立的作用域)——>声明的变量都是全局变量,函数都是全局函数

eval和函数的比较

  1. eval封装了一段代码(只能执行一次);函数封装了一段代码(可以重复执行)
  2. eval中没有独立作用域的——>声明的变量和函数都是全局的; 函数中是有独立作用域 ——>函数内声明的变量和函数只能在当前函数内部所访问

delete 运算符

delete 运算符时一元运算符,用来删除对象属性或者数组元素。删除属性或者删除数组元素不仅仅是设置了一个 undefined 的值。当删除一个属性时,这个属性将不再存在。读取一个不存在的属性将返回 undefined,但是可以通过 in 运算符来检测这个属性是否在对象中存在。

void 运算符

void 运算符是一元运算符,在操作数之前,操作数可以使任意类型。通常用在客户端的URL–javascript: URL 中,在 URL 中可以写带有副作用的表达式,而 void 则让浏览器不比显示这个表达式的计算结果。

例如:

1
<a href="javascript:void window.open();">打开一个新窗口</a>

通过给 <a> 标签的onclick 绑定一个事件处理程序要比在 href 中写 “javascript:URL” 要更加清晰,这种情况下 void 可有可无。

逗号运算符

逗号运算符是二元操作符,操作数可以是任意类型,先计算左边操作数后计算右边操作数,最后返回右操作数的值。

感谢您的支持!