关于javascript:js学习笔记9运算符

2次阅读

共计 5157 个字符,预计需要花费 13 分钟才能阅读完成。

  • js 提供了指数运算符:* 指数运算符x ** y

加法运算符

根本规定
  • js 容许非数值的相加:布尔值主动转化为数值
true + true // 2
1 + true // 2
  • 两个字符串相加,变成连贯运算符
'a' + 'bc' // "abc"
  • 字符串 + 非字符串:非字符串转为字符串,在连贯在一起
1 + 'a' // "1a"
false + 'a' // "falsea"
  • 运算子的不同,导致了相加和连贯的行为不同,这种景象称为重载。留神,因为从左到右的运算程序,字符串地位不同,运算后果不同
'3' + 4 + 5 // "345"
3 + 4 + '5' // "75"

除了加法运算符,其余算术运算符(比方减法、除法和乘法)都不会产生重载。它们的规定是:所有运算子一律转为数值,再进行相应的数学运算。

对象的相加

当运算子为对象时,必须先转换成原始类型的值,而后再相加

var obj = {p: 1};
obj + 2 // "[object Object]2"
对象转换成原始类型的值的规定
  • 首先调用对象的 valueOf 办法,返回对象本身
var obj = {p: 1};
obj.valueOf() // { p: 1}
  • 而后调用对象的 toString 办法,将其转为字符串。留神,对象的 toString 办法默认返回[object Object],所以就失去了最后面那个例子的后果。
var obj = {p: 1 ;}
obj.valueOf().toString() // "[object Object]"
失去规定之后,咱们就能够本人定义 valueOf 办法或 toString 办法,失去想要的后果。
  • 自定义 valueOf
var obj = {valueOf: function () {return 1;}
};

obj + 2 // 3

下面代码中,咱们定义 obj 对象的 valueOf 办法返回 1,于是obj + 2 就失去了 3。这个例子中,因为valueOf 办法间接返回一个原始类型的值,所以不再调用 toString 办法。

  • 自定义 toString
var obj = {toString: function () {return 'hello';}
};

obj + 2 // "hello2"

下面代码中,对象 objtoString办法返回字符串hello。后面说过,只有有一个运算子是字符串,加法运算符就变成连贯运算符,返回连贯后的字符串。

  • 这里有一个特例,如果运算子是一个 Date 对象的实例,那么会优先执行 toString 办法。
var obj = new Date();
obj.valueOf = function () { return 1};
obj.toString = function () { return 'hello'};

obj + 2 // "hello2"

下面代码中,对象 obj 是一个 Date 对象的实例,并且自定义了 valueOf 办法和 toString 办法,后果 toString 办法优先执行。

余数运算符

  • 运算后果的正负号由第一个运算子正负号决定,不遵循算数法令
-1 % 2 // -1
1 % -2 // 1

因而,为了失去正数的正确余数值,能够先用绝对值函数

// 谬误的写法
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

数值运算符、负数值运算符

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

数值运算符的作用在于能够将任何值转为数值(与 Number 函数的作用雷同)。

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

下面代码示意,非数值通过数值运算符当前,都变成了数值(最初一行 NaN 也是数值)。具体的类型转换规定,参见《数据类型转换》一章。

负数值运算符(-),也同样具备将一个值转为数值的性能,只不过失去的值正负相同。连用两个负数值运算符,等同于数值运算符。

var x = 1;
-x // -1
-(-x) // 1

下面代码最初一行的圆括号不可少,否则会变成自减运算符。

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

指数运算符

留神,指数运算符是右联合,而不是左联合。即多个指数运算符连用时,先进行最左边的计算。

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

比拟运算符

比拟运算符能够分为相等比拟和非相等比拟。对于非相等比拟,先看两个运算子是否都是字符串,如果是,就依照字典程序比拟(实际上是比拟 Unicode 码点);否则,将两个运算子都转成数值,再比拟数值的大小

非相等运算符字符串的比拟

若两个都是字符串,依照字典程序进行比拟,即比拟 Unicode 码点

非相等运算符非字符串的比拟

只有两个运算子有一个不是字符串,就属于非字符串比拟

  • 若都是原始类型,(字母、字符串、布尔值)先转换成数值再比拟。这里留神的是,任何值与 NaN 比拟,返回的都是 false(包含 NaN 自身)
  • 对象会先调用 valueOf 办法;如果返回的还是对象,再接着调用 toString 办法,最终转换为原始类型的值。在进行比拟

严格相等运算符

严格相等运算符(===)先比拟类型,后比拟值,只有一个不相等就返回 false;而相等运算符当类型不同时,会先转换成雷同类型,再比拟

  • NaN 与任何值都不相等(包含自身),+0=-0
  • 复合类型的数据比拟时,不是比拟值是否相等,而是比拟是否指向同一个地址

如果两个变量援用同一个对象,则它们相等。

var v1 = {};
var v2 = v1;
v1 === v2 // true

留神,对于两个对象的比拟,严格相等运算符比拟的是地址,而大于或小于运算符比拟的是值。

var obj1 = {};
var obj2 = {};

obj1 > obj2 // false
obj1 < obj2 // false
obj1 === obj2 // false

下面的三个比拟,前两个比拟的是值,最初一个比拟的是地址,所以都返回false

  • undefined 和 null 与本身严格相等。另外,因为变量申明后默认值为 undefined,所以两个只申明未赋值的变量是相等的
var v1;
var v2;
v1 === v2 // true

相等运算符

  • 原始类型的值转换成数值再比拟
  • 对象转换成原始函数的值再比拟
  • undefined 和 null 互相比拟为 true,与其余比拟为 false

布尔运算符:将表达式转为布尔值

!取反运算符

除了以下 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

这种跳过第二个运算子的机制,被称为“短路”。有些程序员喜爱用它取代 if 构造,比方上面是一段 if 构造的代码,就能够用且运算符改写

if (i) {doSomething();
}

// 等价于

i && doSomething();

且运算符能够多个连用,后果会返回第一个为 false 的值;若所有表达式都为 false,则返回最初一个表达式的值

|| 或运算符

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

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

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

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

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

下面代码示意,如果函数调用时,没有提供参数,则该参数默认设置为空字符串。

二进制运算符

位运算符只对整数起作用,若运算子不是整数,会主动转换为整数后再执行

i = i | 0;

下面这行代码的意思,就是将i(不论是整数或小数)转为 32 位整数

二进制或运算符 |

  • 将小数与 0 进行二进制或运算,可用于去除小数的小数局部

二进制与运算符 &

二进制否运算符~

~ 3 // -4
  • 返回后果有时难以了解,因为波及到就三级外部的数值示意机制

3的 32 位整数模式是00000000000000000000000000000011,二进制否运算当前失去11111111111111111111111111111100。因为第一位(符号位)是 1,所以这个数是一个正数。JavaScript 外部采纳补码模式示意正数,即须要将这个数减去 1,再取一次反,而后加上负号,能力失去这个正数对应的 10 进制值。这个数减去 1 等于11111111111111111111111111111011,再取一次反失去00000000000000000000000000000100,再加上负号就是-4。思考到这样的过程比拟麻烦,能够简略记忆成,一个数与本身的取反值相加,等于 -1。

  • 对一个整数间断两次二进制否运算,失去自身。对小数间断两次二进制否运算,达到取整成果
  • 当对字符串等其余类型的值进行二进制否运算时,js 会先调用 Number 函数,将其转化为数值

异或运算符

  • “异或运算”有一个非凡使用,间断对两个数 ab进行三次异或运算,a^=b; b^=a; a^=b;,能够调换它们的值。这意味着,应用“异或运算”能够在不引入长期变量的前提下,调换两个变量的值。
  • 异或运算也能够用来取整。
12.9 ^ 0 // 12

利用:开关作用

位运算符能够用作设置对象属性的开关。

假设某个对象有四个开关,每个开关都是一个变量。那么,能够设置一个四位的二进制数,它的每个位对应一个开关。

var FLAG_A = 1; // 0001
var FLAG_B = 2; // 0010
var FLAG_C = 4; // 0100
var FLAG_D = 8; // 1000

下面代码设置 A、B、C、D 四个开关,每个开关别离占有一个二进制位。

而后,就能够用二进制与运算,查看以后设置是否关上了指定开关。

var flags = 5; // 二进制的 0101

if (flags & FLAG_C) {// ...}
// 0101 & 0100 => 0100 => true

下面代码测验是否关上了开关C。如果关上,会返回true,否则返回false

当初假如须要关上 ABD 三个开关,咱们能够结构一个掩码变量。

var mask = FLAG_A | FLAG_B | FLAG_D;
// 0001 | 0010 | 1000 => 1011

下面代码对 ABD 三个变量进行二进制或运算,失去掩码值为二进制的1011

有了掩码,二进制或运算能够确保关上指定的开关。

flags = flags | mask;

下面代码中,计算后失去的 flags 变量,代表三个开关的二进制位都关上了。

二进制与运算能够将以后设置中但凡与开关设置不一样的项,全副敞开。

flags = flags & mask;

异或运算能够切换(toggle)以后设置,即第一次执行能够失去以后设置的相同值,再执行一次又失去原来的值。

flags = flags ^ mask;

二进制否运算能够翻转以后设置,即原设置为0,运算后变为1;原设置为1,运算后变为0

flags = ~flags;

void 运算符

  • void 运算符的作用是执行一个表达式,而后不返回任何值。
var x = 3;
void (x = 5) //undefined
x // 5
  • 留神的是,咱们倡议应用 void 运算符时用圆括号括起来,因为 void 运算符优先级很高,防止谬误后果。比方,void 4 + 7实际上等同于(void 4) + 7
  • 这个运算符次要用于做浏览器的书签工具,以及在超级链接中插入代码避免页面跳转
<a href="javascript: void(document.form.submit())">
  提交
</a>

如上边,用户点击链接提交表单,然而不产生页面跳转

,逗号运算符

  • 逗号运算符用于对两个表达式求值,并返回后一个表达式的值
var x = 0;
var y = (x++, 10);
x // 1
y // 10
  • 用处:在返回一个值前,进行一些辅助操作
var value = (console.log('Hi!'), true);
// Hi!

value // true

运算程序

  • 留神括号的应用,来防止运算程序与预期不同
  • 左联合和右联合。大部分都是左联合,然而赋值运算符、三元运算符和指数运算符是右联合
w = x = y = z;
q = a ? b : c ? d : e ? f : g;
w = (x = (y = z));
q = a ? b : (c ? d : (e ? f : g));
2 ** 3 ** 2
// 相当于 2 ** (3 ** 2)
// 512
正文完
 0