JavaScript的运算符(操作符)和优先级

  最近因为在读 Underscore.js 的源代码,加上重拾之前没有完成 ife 中的 JavaScript 部分的 task2,其中大量简略的语句写法,尤其喜欢 ?: 这个三目运算符和其他运算符连用。因为对于运算符优先级的概念一直很模糊,然后经常被绕进圈子里面。下面整理下常用的运算符和它们的优先级差异。

一、运算符

1. 一元运算符

(1)  递增递减运算符

  主要就是 a++ 和 ++a 的区别,执行前置递增和递减运算时,变量的值都是在语句被求值之前改变的。

var num1 = 10;
var num2 = num1++;
console.log(num1 + ‘  ‘ + num2);  //  ‘11   10‘

var num3 = ++num1;
console.log(num1 + ‘  ‘ + num3);  //  ‘12   12‘

(2) 一元加减运算符

  这个没有什么好说的,因为是作为一元加减运算符的存在,所以主要是用来变化 ± 号的。

2. 位运算符

  理解这个位运算符还是蛮复杂的,需要理解一通诸如:二进制、补码、按位取反等等的概念,这些概念这里就不多说了,读大学的时候这几个概念就够讲个几节课了。

(1) 按位非

  ~ :返回数值的反码,通俗的来说就是取反减1

(2) 按位与

  & :将两个数值的每一位对齐,然后两个数值对应位都是 1 时才返回 1,任何一位是 0,结果都是 0。下面有个应用,还是蛮有趣的:

// DOM .contains() 方法的兼容性写法
// 执行对象是否是参数对象的父节点
function contains(refNode, otherNode){
	if(typeof refNode.contains == "function" &&
		(!client.engine.webkit || client.engine.webkit >= 522)){
		return refNode.contains(otherNode);
	}else if(typeof refNode.compareDocumentPosition == "function"){
		return !!(refNode.compareDocumentPosition(otherNode) & 16);
	}else{
		var node = otherNode.parentNode;
		do{
			if(node == refNode){
				return true;
			}else{
				node = node.parentNode;
			}
		}while(node != null);
		return false;
	}
}
/*
** 支持contains()方法的浏览器有IE、Firefox 9+、Safari、Opera和Chrome
** 支持DOM Level3 compareDocumentPosition()方法的浏览器IE9+、Firefox、Safari、Opera 9.5+和Chrome
** compareDocumentPosition()方法的返回值如下
**  1:无关(给定的节点不在当前的文档中)
**  2:居前(给定的节点在DOM树中位于参考节点之前)
**  4:居后(给定的节点在DOM树中位于参考节点之后)
**  8:包含(给定节点是参考节点的祖先)
** 16:被包含(给定节点是参考节点的后代)
*/

  在上面的代码 else if 分支中,这句代码 return !!(refNode.compareDocumentPosition(otherNode) & 16) 中 compareDocumentPosition() 函数如果返回值小于16,在按位与运算之后值都是 0,如果大于等于,按位与的结果就是16(代码中的返回值是 20 = 4 + 16)。然后这里有个 !! 的运算技巧,因为返回值要求是 true 和 false,所以需要两个逻辑非运算符将该数值转换成布尔值

(3)  按位或

  | :将两个数值的每一位对齐,然后两个数值对应位都是 0 时才返回 0,任何一位是 1,结果都是 1。这个理解了按位与就蛮好理解的。

(4)  按位异或

  ^ :将两个数值的每一位对齐,然后两个数值对应位相同才返回 0,不同结果返回 1。这个理解了按位与/按位或者就蛮好理解的。

(5)  左移 (<<) / 有符号的右移 (>>) / 无符号的右移 (>>>)

  这个说真的我用的比较少,这里就不展开描述,有兴趣可以自己查查。

3. 布尔运算符

(1)  逻辑非

  ! :值得注意的是,逻辑非运算符首先会将它的运算数转换为一个布尔值,然后对其求反。其中最重要的应用就是上面有提到的:同时使用两个逻辑非运算符,实际上就会模拟 Boolean() 转型函数的行为

(2) 逻辑与

  && :逻辑与运算布尔值的情况就不多赘述了,只要有 false 就返回 false,全是 true 就返回 true。这里主要需要讨论的是逻辑与运算符应用于其他类型运算数的情况:

  • 如果第一个运算数是对象,则返回第二个运算数;
  • 如果第二个运算数是对象,则只有在第一个运算数求值结果返回 true 的情况下才会返回该对象;
  • 如果两个运算数都是对象,则返回第二个运算数;
  • 如果有一个运算数是 null / NaN / undefined,则返回 null / NaN / undefined;

  同时值得注意的是,逻辑与是短路运算,第一个运算数返回值是false,就不会再对第二个运算数进行求值(注意,这里是求值)。

(3) 逻辑非

  || :和逻辑与毕竟是兄弟,运算布尔值就是,只要有 true 就返回 true,全是 false 就返回 false。详细看看逻辑非运算符应用于其他类型运算数的情况:

  • 如果第一个运算数是对象,则返回第一个运算数;
  • 如果第一个运算数的求值结果为 false ,则返回第二个运算数;
  • 如果两个运算数都是对象,则返回第一个运算数;
  • 如果两个运算数都是 null / NaN / undefined,则返回 null / NaN / undefined;

  和逻辑与相似的是,逻辑非也是短路运算,这里也有个有趣的应用,在之前写 jQuery 插件的时候,向初始化函数传递参数 options 时,为了避免赋值 undefined 或者 null,常常会在初始化参数的过程中添上这么句代码:

var _options = options || {};

  前面的 options 包含优先赋值给 _options 的值,后面的 {} 空对象负责在前面的 options 中不包含有效值的情况下提供后备值。因为这一句代码之后往往就是用户定义参数和默认参数的拓展,所以要求不能传递 null 值。

  逻辑与和逻辑非在代码编写中的应用往往非常普遍,尤其是运算非布尔值的对象的规则还是很重要的。

  凭借现在自己的水平在应用编写还是用的不够熟悉,还是要不断重构自己当初写的代码,不远总结反思。

4. 乘性运算符 / 加性运算符

  这里主要是 + - * / % 这五种运算符的运算特性,相对而言除了基本的数学运算,还有字符串拼接,在我使用的过程中,其他一些比较 Geek 的用法我也没怎么涉及。下面有些值得注意的地方:

  • JavaScript 里面的 / 运算不像我之前接触的带有整除的运算效果,就是普通的除法运算,除不尽会带有一长串的小数;
  • 因为 JavaScript 是基于 IEEE754 数值的浮点数计算,所以会出现 0.1 + 0.2 ≠ 0.3 的情况,所以尽量使用转化为整数进行运算;解释摸我

  其他数值运算中会遇到的诸如 NaN、Infinity 就不在这里的运算符讨论范围之内了。

5. 关系运算符

  > < >= <= :这个相比之下也会有些少见的技巧。除了我们常见的数值比较,还有一些比较拓展的知识:

  • 比较两个字符串时,实际比较的是两个字符串中对应位置的每个字符的字符编码值。这里就涉及到字符集、字符编码的概念了,这里就不展开阐述。由于大写字母的字符编码全部小于小写字母的字符编码,所以就会出现下面所示的情况:

    var result = "Bob" < "alin";    // true
  • 还有出现 > <= 比较两个相同运算数出现相同结果。根据规则,任何运算数与 NaN 进行比较时,结果都是返回 false ,因为字母不能转化成合理的数值,这样就出现了下面所示的情况:

    var result1 = ‘a‘ > 1;    // false
    var result2 = ‘a‘ <= 1;     // false

6. 相等运算符

  这里主要需要区别的是(不)相等和(不)全等。相等运算符(==)会存在一个类型转换的运算,其中主要的应用是在类似 "5" == 5 这种纯数字字符串和数字的比较判断会返回 true。值得注意的是: null == undefined 返回是 true。而全等(===)要求不仅仅两个运算数本身数值相等,还要求两者的数值类型相同。所以上面的两种情况在全等的情况下都是返回 false 。在实际的代码编写中,还是推荐全等和不全等运算符。

7. 条件运算符

variable = boolean_expression ? true_value : false_value;

  基于对 boolean_expression 求值的结果,决定给变量 variable 的赋值。如果求值结果为 true ,则给 variable 赋值 true_value ,否则则是 false_value。配合上其他运算符,条件(三目)运算符可以发挥出它的灵活、高效。

8. 赋值运算符

  = : 把右侧的值赋给左侧的变量。类似的还有 *= 、 /= 、 %= 、 += 、-= 、 <<= 、 >>= 、 >>>= 。使用这些运算符主要就是为了简化赋值运算,不会带来任何性能的提升。

9. 逗号运算符

  使用逗号运算符可以在一条语句中执行多个运算,例如常见的赋值语句:

var num1 = 1, num2 = 2, num3 = 3;

  除此之外,逗号运算符还可以用于赋值。用于赋值时,逗号运算符总会返回表达式的最后一项,例如下面的例子:

var num = (1, 2, 3, 4, 5, 0);    // num 的值是0

  还有这种面试题:

var num = (key = 12, 0);  // num 的值是0

10. typeof 操作符

  这个操作符主要是用来检测给定变量的数据类型,返回值如下:

  • "undefined"  -  如果这个值未定义;  
  • "boolean"  -  如果这个值是布尔值;
  • "string"  -  如果这个值是字符串;
  • "number"  -  如果这个值是数值;
  • "object"  -  如果这个值是对象或者null
  • "function"  -  如果这个值是函数;

  这里解释下为什么 typeof null 会返回 "object" ,同样也解释下为什么 null == undefined 会返回 true:null 值本身就是表示一个空对象指针,使用 typeof 会返回 "object";实际上,undefined 是派生自 null 值的,因此两者的相等性测试要返回 true。因而,没有必要把一个变量的值显示的设置为 undefined,但是只要意在保存对象的变量还没有真正的保存对象,就应该明确的让该变量保存 null 值。

二、 运算符优先级

  下面的表格按照从高到低的优先级列出 JavaScript 的运算符,具有相同优先级的运算符按照从左到右的顺序求值:

运算符 描述
. [] () 属性访问、数组下标、函数调用以及表达式分组
++ -- ~ ! + - delete new typeof void  一元运算符、返回数据类型、对象创建
* / % 乘法、除法、取模
+ - 加法、减法
>> << >>> 移位运算
< <= > >= instanceof 小于(等于)、大于(等于)、
== != === !== (不)等于、(不)全等
& 按位与
^ 按位异或
| 按位或
&& 逻辑与
|| 逻辑或
?: 条件(三目)运算符
= += 赋值、运算赋值
, 多重求值(逗号运算符)

  这次遇坑的情况就是下面这种情况:

return parts[0] && result[0] ? filterParents(parts, result) : result;

  其中确定 parts 数组中不含有数据对象了,所以我就掉进了死胡同,一直以为返回的是 undefined ,最后才想到可能是运算符优先级的问题,这里因为在条件运算符中判断条件直接返回 undefined,转化为 false ,之后返回结果值是 result 值。以后还是需要注意下运算符的优先级问题。

时间: 2024-10-17 09:23:20

JavaScript的运算符(操作符)和优先级的相关文章

(4)javascript的运算符以及运算符的优先级

                                运算符的使用方法 在javascript的程序中要完成各种各样的运算,是离不开运算符的. 在javascript中,按运算符类型可以分为算术运算符.赋值运算符.比较运算符.逻辑运算符.条件运算符等. ( 图片来自于W3School离线手册) 算术运算符案例: <!doctype html> <head> <meta http-equiv="content-type" content="

javascript(六)运算符

运算符概述 JavaScript中的运算符用于算术表达式. 比较表达式. 逻辑表达式. 赋值表达式等.需要注意的是, 大多数运算符都是由标点符号表示的, 比如 "+" 和"=" . 而另外一些运算符则是由关键字表示的, 比如delete和instanceof. 关键字运算符和标点符号所表示的运算符一样都是正规的运算符. 算术运算符 赋值 y = 5, 以下表格将向你说明算术运算符的使用: 算符 描述 例子 y 值 x 值 + 加法 x = y + 2 y = 5 x

各种操作符及其优先级

优先级 运算符 名称或含义 使用形式 结合方向 说明 1 [] 数组下标 数组名[整型表达式] 左到右   () 圆括号 (表达式)/函数名(形参表)   . 成员选择(对象) 对象.成员名   -> 成员选择(指针) 对象指针->成员名   2 - 负号运算符 -表达式 右到左 单目运算符 (类型) 强制类型转换 (数据类型)表达式   ++ 自增运算符 ++变量名/变量名++ 单目运算符 -- 自减运算符 --变量名/变量名-- 单目运算符 * 取值运算符 *指针表达式 单目运算符 &am

C++操作符的优先级 及其记忆方法

优先级 操作符 描述 例子 结合性 1 ()[]->.::++-- 调节优先级的括号操作符数组下标访问操作符通过指向对象的指针访问成员的操作符通过对象本身访问成员的操作符作用域操作符后置自增操作符后置自减操作符 (a + b) / 4;array[4] = 2;ptr->age = 34;obj.age = 34;Class::age = 2;for( i = 0; i < 10; i++ ) ...for( i = 10; i > 0; i-- ) ... 从左到右 2 !~++

JavaScript的运算符

JavaScript的运算符 算术运算 加法运算符(Addition):x + y 减法运算符(Subtraction): x y 乘法运算符(Multiplication): x * y 除法运算符(Division):x / y 余数运算符(Remainder):x % y 自增运算符(Increment):++x 或者 x++ 自减运算符(Decrement):--x 或者 x-- 求负运算符(Negate):-x 赋值运算 比较运算 字符编码:计算机里所有的数字,字母和其他符号都有编号.

JavaScript instanceof 运算符深入剖析

instanceof 运算符简介 在 JavaScript 中,判断一个变量的类型尝尝会用 typeof 运算符,在使用 typeof 运算符时采用引用类型存储值会出现一个问题,无论引用的是什么类型的对象,它都返回 "object".ECMAScript 引入了另一个 Java 运算符 instanceof 来解决这个问题.instanceof 运算符与 typeof 运算符相似,用于识别正在处理的对象的类型.与 typeof 方法不同的是,instanceof 方法要求开发者明确地确

Javascript实现运算符重载

最近要做数据处理,自定义了一些数据结构,比如Mat,Vector,Point之类的,对于加减乘除之类的四则运算还要重复定义,代码显得不是很直观,javascript没有运算符重载这个像C++.C#之类的功能的确令人不爽,于是想"曲线救国",自动将翻译代码实现运算符重载,实现思路其实很简单,就是编写一个解释器,将代码编译.例如:S = A + B (B - C.fun())/2 + D翻译成`S = replace(replace(A, '+', replace(replace(B,''

javascript中的操作符详解1

好久没有写点什么了,根据博主的技术,仍然写一点javascript新手入门文章,接下来我们一起来探讨javascript的操作符. 一.前言 javascript中有许多操作符,但是许多初学者并不理解或曲解他们的用途,本章将会带领初学者们一起来学习一下javascript的几个常用操作符:typeof.in.delete.new. 二.学习目标 1. 深入了解javascript操作符:typeof.in.delete.new的功能及用法. 2. 剖析根本,掌握这些常用的操作符的运用场景,活学活

javascript 中 in操作符

in in 操作检查对象中是否有名为 property 的属性.也可以检查对象的原型,以便知道该属性是否为原型链的一部分. 对于一般的对象属性需要用字符串指定属性的名称 ? 1 2 3 var mycar = {make: "Honda", model: "Accord", year: 1998}; "make" in mycar  // returns true "model" in mycar // returns tru