JavaScript基础复习2-运算符

10种算术运算符

  • 加法运算符x + y
  • 减法运算符x - y
  • 乘法运算符x * y
  • 除法运算符x / y
  • 指数运算符x ** y
  • 余数运算符x % y
  • 自增运算符++x 或者 x++
  • 自减运算符--x 或者 x--
  • 数值运算符+x
  • 负数值运算符-x

加法

  • JavaScript 允许非数值的相加

  • 两个字符串相加,这时加法运算符会变成连接运算符,返回一个新的字符串,将两个原字符串连接在一起。

  • 一个运算子是字符串,另一个运算子是非字符串,这时非字符串会转成字符串,再连接在一起。

  • 加法运算符是在运行时决定,到底是执行相加,还是执行连接。根据不同的运算子导致不一样的语法行为叫重载

  • '3' + 4 + 5 // "345"
    3 + 4 + '5' // "75"
  • 除了加法运算符,其他算术运算符(比如减法、除法和乘法)都不会发生重载。它们的规则是:所有运算子一律转为数值,再进行相应的数学运算。

对象的相加

如果运算子是对象, 必须先转为原始类型的值,再相加, 对象转原始值规则:

  1. 先调用对象的valueOf, 对象的valueOf方法总是返回对象自身

  2. 这时再自动调用对象的toString方法,将其转为字符串。

  3. var obj = { p: 1 };
    obj.valueOf() // { p: 1 }
    obj.valueOf().toString() // "[object Object]"

知道了这个规则以后,就可以自己定义valueOf方法或toString方法,得到想要的结果。

var obj = {
  valueOf: function () {
    return 1;
  }
};

obj + 2 // 3

余数 (%)

运算结果的正负号由第一个运算子的正负号决定。

所以,为了得到负数的正确余数值,可以先使用绝对值函数。

// 错误的写法
function isOdd(n) {
  return n % 2 === 1;
}
isOdd(-5) // false
isOdd(-4) // false

// 正确的写法
function isOdd(n) {
  return Math.abs(n % 2) === 1;
}
isOdd(-5) // true
isOdd(-4) // false      

自增自减

  • 自增和自减运算符,是一元运算符,只需要一个运算子。它们的作用是将运算子首先转为数值,然后加上1或者减去1。它们会修改原始变量。

  • 运算之后,变量的值发生变化,这种效应叫做运算的副作用(side effect)。自增和自减运算符是仅有的两个具有副作用的运算符,其他运算符都不会改变变量的值。

自增和自减运算符有一个需要注意的地方,就是放在变量之后,会先返回变量操作前的值,再进行自增/自减操作;放在变量之前,会先进行自增/自减操作,再返回变量操作后的值。

var x = 1;
var y = 1;

x++ // 1
++y // 2

数值运算符/负值运算符

数值运算符号和负数值运算符,都会返回一个新的值,而不会改变原始变量的值。

数值运算符(+)同样使用加号,但它是一元运算符(只需要一个操作数),而加法运算符是二元运算符(需要两个操作数)。

数值运算符的作用在于可以将任何值转为数值(与Number函数的作用相同)

+true // 1
+[] // 0
+{} // NaN

负数值运算符(-),也同样具有将一个值转为数值的功能,只不过得到的值正负相反。连用两个负数值运算符(需要用括号, 不然是自减运算符),等同于数值运算符。

指数运算符 (**)

指数运算符(**)完成指数运算,前一个运算子是底数,后一个运算子是指数。

指数运算符是右结合, 即多个指数运算符连用时,先进行最右边的计算.

// 相当于 2 ** (3 ** 2)
2 ** 3 ** 2   // 512

赋值运算符 (=)

下面是与算术运算符的结合。

// 等同于 x = x + y
x += y

// 等同于 x = x - y
x -= y

// 等同于 x = x * y
x *= y

// 等同于 x = x / y
x /= y

// 等同于 x = x % y
x %= y

// 等同于 x = x ** y
x **= y

比较运算符

JavaScript 一共提供了8个比较运算符。

  • > 大于运算符
  • < 小于运算符
  • <= 小于或等于运算符
  • >= 大于或等于运算符
  • == 相等运算符
  • === 严格相等运算符
  • != 不相等运算符
  • !== 严格不相等运算符

字符串的比较

按照字典顺序进行比较( 实际上是比较Unicode码点)

非字符串的比较

如果运算子都不是字符串

  1. 都是原始类型的值, 则先转成数值在比较

  2. 5 > '4' // true
    // 等同于 5 > Number('4')
    // 即 5 > 4
    
    true > false // true
    // 等同于 Number(true) > Number(false)
    // 即 1 > 0
    
    2 > true // true
    // 等同于 2 > Number(true)
    // 即 2 > 1
  3. NaN 和 任何值比较都 返回 false

对象

如果运算子是对象,会转为原始类型的值,再进行比较。

对象转换成原始类型的值,算法是先调用valueOf方法;如果返回的还是对象,再接着调用toString方法

严格相等运算符 (===)

JavaScript有提供了两种相等运算符: =====

相等运算符(==)是比较两个值是否相等,严格相等运算符(===)比较的是他们是否为’同一个值’, 不是同一类型, === 返回false ,==会先转为同一类型,在比较

  • NaN和任何值都不相等(包括自身)

  • 0等于负0

  • 符合类型(对象, 数组, 函数)比较是, 不是比它们值是否相等, 而是比较它们是否是同一个地址

  • {} === {} // false
    [] === []  // false
    (function (){} === function(){}) // false
  • 如果两个变量引用同一个对象,则它们相等。

  • var v1 = {};
    var v2 = v1;
    v1 === v2 // true
  • undefinednull与自身严格相等

  • 由于变量声明后默认值是undefined,因此两个只声明未赋值的变量是相等的。

相等运算符 (==)

它遇到相同类型的数据时, 与===完全一样, 比较不同类型的数据时,相等运算符会先将数据进行类型转换,然后再用严格相等运算符比较。

下面分成四种情况,讨论不同类型的值互相比较的规则

  1. 原始类型的值会转换成数值再进行比较

  2. 对象与原始类型值比较 对象转换成原始类型的值,再比较

  3. undefined 和 null 与其他类型数值比较返回 false,互与自身则返回true

  4. 相等运算符的缺点

  5. 0 == ''             // true
    0 == '0'            // true
    
    2 == true           // false
    2 == false          // false
    
    false == 'false'    // false
    false == '0'        // true
    
    false == undefined  // false
    false == null       // false
    null == undefined   // true
    
    ' \t\r\n ' == 0     // true

    因此建议不要使用相等运算符, 最好只使用严格相等运算符

布尔运算符

布尔运算符用于将表达式转为布尔值,一共包含四个运算符。

  • 取反运算符:!
  • 且运算符:&&
  • 或运算符:||
  • 三元运算符:?:

取反运算符 (!)

对于非布尔值, 取反会将其 转为布尔值, 以下6个值取反后为 true, 其他值都为false:

  • undefined
  • null
  • false
  • 0
  • NaN
  • 空字符串(''

如果对一个值连续做两次取反运算,等于将其转为对应的布尔值,与Boolean函数的作用相同。这是一种常用的类型转换的写法。

且运算符 (&&)

规则: 如果一个运算子的布尔值为 true, 则返回第二个运算子的值(注意是值, 不是布尔值); 如果第一个运算子的布尔值为false, 则直接返回一第一个子运算符的值, 不再对第二个运算子求值

't' && '' // ""
't' && 'f' // "f"
't' && (1 + 2) // 3
'' && 'f' // ""
'' && '' // ""

var x = 1;
(1 - 1) && ( x += 1) // 0
x // 1

这种只通过第一个表达式的值,控制是否运行第二个表达式的机制,就称为“短路”(short-cut)。有些程序员喜欢用它取代if结构,比如下面是一段if结构的代码,就可以用且运算符改写。

if (i) {
  doSomething();
}

// 等价于

i && doSomething();

且运算符可以多个连用,这时返回第一个布尔值为false的表达式的值。如果所有表达式的布尔值都为true,则返回最后一个表达式的值。

true && 'foo' && '' && 4 && 'foo' && true
// ''

1 && 2 && 3
// 3

或运算符 (||)

规则 : 如果第一个运算子的布尔值为 true , 则返回第一个运算子的值, 且不再对第二个运算子求值; 如果第一个运算子的布尔值为 false , 则返回第二个运算子的值;

't' || '' // "t"
't' || 'f' // "t"
'' || 'f' // "f"
'' || '' // ""

短路规则也适用:

var x = 1;
true || (x = 2) // true
x // 1

或运算符可以多个连用,这时返回第一个布尔值为true的表达式的值。如果所有表达式都为false,则返回最后一个表达式的值。

false || 0 || '' || 4 || 'foo' || true
// 4

false || 0 || ''
// ''

或运算符常用于为一个变量设置默认值。

function saveText(text) {
  text = text || '';
  // ...
}

// 或者写成
saveText(this.text || '')

三元运算符 (? :)

三元条件运算符由问号(?)和冒号(:)组成,分隔三个表达式。它是 JavaScript 语言唯一一个需要三个运算子的运算符。

  • 通常来说,三元条件表达式与if...else语句具有同样表达效果,前者可以表达的,后者也能表达。但是两者具有一个重大差别,if...else是语句,没有返回值;三元条件表达式是表达式,具有返回值。
console.log(true ? 'T' : 'F');

上面代码中,console.log方法的参数必须是一个表达式,这时就只能使用三元条件表达式。如果要用if...else语句,就必须改变整个代码写法了。

二进制运算符 (没看)

其他运算符和运算顺序

  1. void运算符: 主要用途是在浏览器的书签工具, 以及在超链接中插入代码防止网页跳转

  2. <script>
    function f() {
      console.log('Hello World');
    }
    </script>
    <a href="http://example.com" onclick="f(); return false;">点击</a>
    
    // void运算符可以取代上面的写法。
    <a href="javascript: void(f())">文字</a>

    下面是一个更实际的例子,用户点击链接提交表单,但是不产生页面跳转。

    <a href="javascript: void(document.form.submit())">
      提交
    </a>
  3. 逗号运算符: 用于对两个表达式求值, 并返回后一个表达式;

    • 逗号运算符的一个用途是,在返回一个值之前,进行一些辅助操作

    • 'a', 'b' // "b"
      
      var x = 0;
      var y = (x++, 10);
      x // 1
      y // 10

运算优先级

这五个运算符的优先级从高到低依次为:小于等于(<=)、严格相等(===)、或(||)、三元(?:)、等号(=

圆括号的作用

圆括号 ()用来提高运算的优先级, 它的优先级最高;

圆括号不是运算符,而是一种语法结构。

它一共有两种用法:

  • 一种是把表达式放在圆括号之中,提升运算的优先级;
  • 另一种是跟在函数的后面,作用是调用函数。

   转载规则


《JavaScript基础复习2-运算符》 lttztt 采用 知识共享署名 4.0 国际许可协议 进行许可。
 上一篇
JavaScript基础复习3-语法 JavaScript基础复习3-语法
表达式和语句的区别 表达式一般都有值,语句可能有也可能没有 语句一般会改变环境(声明、赋值) 标识符规则 第一个字符可以是Unicode字母或$和____符号或者中文 后面的自身除了这些还能是数字。 if else语句 {}在语句只有
2018-10-29
下一篇 
JavaScript基础复习1-前言+数据类型 JavaScript基础复习1-前言+数据类型
要点前言和基础语法 脚本语言:不具备编写操作系统的能力 JavaScript 也是一种嵌入式(embedded)语言。 变量就是给值起名 JavaScript引擎的工作方式是:先解释代码.在一行行执行. var a; console
2018-10-28
  目录