学习 JavaScript (四)核心概念:操作符
JavaScript 的核心概念主要由语法、变量、数据类型、操作符、语句、函数组成,前面三个上一篇文章已经讲解完了。后面三个内容超级多,这篇文章主要讲解的是操作符。
操作符
什么叫做操作符?
这是一种工具,帮助我们操作字符串、数字值、布尔值,乃至对象,运用一些操作符能够让代码更简洁、计算更高效。它包括以下几种:
- 赋值操作符
- 一元操作符(加、减)
- 位操作符
- 关系操作符
- 相等操作符
01 赋值操作符
赋值操作符就是我们常见的 “=”,作用就是把右边的值赋给左边的变量。比如:
let a = 1;
如果复杂一些(性能上不会有提升,看起来牛*一点而已),就是结合后面要碰到的操作符,变成这样:
*= ; // 乘/赋值
// 举例
let num = 10;
num = num * 10; // 和下面的用法效果一样
num *= 10;
下面的复杂赋值操作符如下:
/= ; // 除/赋值
%= ; // 模/赋值
+= ; // 加/赋值
-= ; // 减赋值
<<= ; // 左移赋值;
>>=; // 有符号右移;
>>>= ; // 无符号右移;
02 一元操作符
记住:只对一个数值进行操作的符号叫做一元操作符,而不是指操作符自身的数量。
递增操作:两个加号 ++
前置操作 ++i ,i 先自己加上 1 ,然后拿着计算后的 i 值进行下一步计算。
let i = 1;
let result = ++i + 20
console.log(i) // 2
console.log(result) // 22
后置操作 i++,先进行下一步计算,然后再自己加上1。
let i = 1;
let result = i++ + 20
console.log(i) // 2
console.log(result) // 21
递减操作:两个加号 --
递减操作和递增操作的规则一样,-- 符号在前面就先进行递减操作,否则就等接下来的计算进行完再递减。
前置操作 --i ,i 先自己减去 1 ,然后拿着计算后的 i 值进行下一步计算。
let i = 1;
let result = --i + 20
console.log(i) // 0
console.log(result) // 20
后置操作 i--,先进行下一步计算,然后再自己减去1。
let i = 1;
let result = --i + 20
console.log(i) // 0
console.log(result) // 21
统一记忆成:符号在前,马上加减。
加和减操作符
前面讲的是两个相同的符号联合起来操作一个数值,而家下来介绍的这个操作符只有一个。
+
或者 -
,对于数值来说,+
没有任何作用,对于 -
来说,把正数变成负数而已。
如果我们把操作符用在其他数据类型上,会发生怎样的情况呢?直接看例子:
let a = "01";
a = +a; // 1
let b = "1.1";
b = +b; // 1.1
let c = "z";
c = "z"; // NaN
let d = "true";
d = "true"; // 1
let e = 1.1;
e = 1.1; // 1.1
let o = {
valueOf: function(){
return -1;
}
} // 如果没有看懂这个对象的写法,不用着急,后面会针对对象做进一步的解释。
o = +o ; -1
而 -
操作则是在+
操作的结果前面加上负号(-)而已。其他类型的数据的转换规则依然不变。
03 位操作符
位操作符是在最基本的、最底层的水平上对数值进行操作,也就是在内存中直接对二进制进行操作。
JavaScript 中的所有数据都是按照 64 位存储的,但是位操作符并不能直接对 64 位的数据进行操作,而是将其转换成 32 位的,操作完成后,再转换成 64 位的,所以我们真正关心的是计算机如何操作 32 位的数值。
对于有符号的整数,二进制从右往左数,32 位中的前 31 位表示整数的值,第 32 位是符号位,表示数值的符号,0 表示正数,1 表示负数。比如 数值 18 表示成二进制为:
0 0000000000000000000000000010010
符号位
写成简洁版的:
10010
31 位中每一位都表示 2 的幂,所以从二进制转换成数值:
(2^4 x 1) + (2^3 x 0) + (2^2 x 0) + (2^1 x 1) + (2^0 x 0) = 18
这是正数的二进制表达方式,负数的二进制需要用到二进制补码。步骤如下:
- 求这个数值的绝对值的二进制;
- 求二进制反码,将 0 替换成 1,将 1 替换成 0 ;
- 得到的二进制反码加 1 ;
举一个例子(-18):
-18 的绝对值等于 18:
0 0000000000000000000000000010010
求二进制反码:
1 1111111111111111111111111101101
反码加 1
1 1111111111111111111111111101110
最终得到的结果就是 11111111111111111111111111101110 。但是计算机给我们看的结果却不是这样,把 -18 转换成字符串会发现得到的结果是“-10010”,计算机隐藏了计算过程,直接展示友好的结果而已,别被骗了。
因为是底层操作,所以应用位操作的计算方式会比普通计算方式要快:
- 按位非(NOT)
- 符号:~ ;
- 作用对象:一个数值(数字、字符串、布尔值、对象);
- 操作:把操作数变成相反数再减去一 ;
- 例子:
~2 == -3
、~-2 == 1
、~true == -2
。
- 按位与(AND)
- 符号:& ;
- 作用对象:两个数值;
- 操作:将两个数值的二进制形式中的每一位对齐,然后依据普通的与操作进行合并,把 1 看成 true,把 0 看成 false , 即 1 和 1 组合是 1 ,1 和 0 组合是 0 , 0 和 0 组合是 0 。得到的二进制再转换成 十进制就可以了;
- 例子:
25 & 3 == 1
;
- 按位或(OR)
- 符号:| ;
- 作用对象:两个数值;
- 操作:和按位与的操作类似,与之不同的是,按位或操作时,只要碰到 1 就返回 1 ,只有两个对应的位全部为 0 时才返回 0 ;
- 例子:
25 | 3 == 27
。
- 按位异或(XOR)
- 符号:^ ;
- 作用对象:两个数值;
- 操作:有且仅有一个位是 1 ,另一个位是 0 ,才返回 1 ,否则都返回 0,即 1 和 1 也返回 0;
- 例子:
25 ^ 3 == 26
。
- 左移
- 符号:<< ;
- 作用对象:一个数值;
- 操作:将数值的所有位向左移动指定的位数,右侧多出来的空位由 0 进行填充;
- 例子:
2 << 5 == 64
,2 向左移动 5 位,左移不会影响操作数的符号位,即 -2 ; ,左移后的结果将会是 -64。
- 右移
- 符号:>> ;
- 作用对象:一个数值;
- 操作:将数值的所有位向右移动指定的位数,符号位不动,左侧多出来的空位由 0 进行填充;
- 例子:
64 >> 5 == 2
,64 向右移动 5 位,右移不会影响操作数的符号位,即 -64 ,右移后的结果将会是 -2。
- 无符号右移
- 符号:>>>;
- 作用对象:一个数值;
- 操作:将数值的所有位向右移动指定的位数,左侧多出来的空位由 0 进行填充,这个时候符号位也要向右移动。可以知道,对于正数而言,这个操作和右移是一样的结果,但是对于负数来说,因为符号位是 1 ,移动后要计入最终结果;
- 例子:
-64 >>> 5 == 134217726
。
04 布尔操作符
在上述位操作符中的按位非、按位与、按位或,我们已经简单介绍了一些跟布尔操作类似的用法。
总的来说,布尔操作的地位跟相等操作符(、=)的地位是一样的,一共右三种:非(NOT)、与(AND)、或(OR)。
逻辑非
- 符号:!;
- 作用对象:一个数值;
- 操作:先将数值转换成一个布尔值,再取反;
- 例子:
!false; //true
!true; //false
!null; //true
!{}; // false
!0; //true
!123; //false
!""; //true
!"abc"; //false
要点:此时连用两个 “!”,则跟布尔转换函数 Boolean() 的作用是一样的,即还原了数值本身代表的布尔值。
- 逻辑与
- 符号:&&;
- 作用对象:两个数值;
- 操作:比较两个数值的布尔值,返回结果(不一定是布尔值);
- 例子:
true && true; //true
true && false; //false
false && true; // fasle
false && false; // false
要点:
- 这里的 true 和 false,可以替换成别的数值类型,比如对象、null等
- 逻辑与是短路操作,只要第一个操作数或者操作数的转换值是 false ,计算终止,直接返回 false 。如果是 true 的话再返回后面的值。
- 在写判断语句的时候经常会用到。
- 逻辑或
- 符号:||;
- 作用对象:两个数值;
- 操作:比较两个数值的布尔值,返回结果(不一定是布尔值);
- 例子:
true || true; //true
true || false; //true
false || true; // true
false || false; // false
要点:
- 逻辑或也是短路操作,只要第一个操作数或者操作数的转换值是 true ,计算终止,直接返回第一个操作数。如果是 false 的话,返回第二个操作数。
- 利用逻辑或的性质,我们在定义变量的时候可以给它找个备胎,降低 Bug 发生率。
04 乘性操作符
乘性操作符包括三种:乘法、除法、求模。在 JavaScript 中,操作数为非数值的情况下也能计算。比如:
"10" * 2 ; // 计算结果为 20
可以看得出来,计算机自动执行了类型转换,如果参与的操作数不是数值,会先用 Number() 函数转换。
- 乘法:
- 符号: *
- 举例:
4 * 5
有三点需要注意:
- 乘积超过 JavaScript 范围,用 Infinity表示无穷大 或者 -Infinity 表示负无穷大;
- Infinity 和 0 相乘是 NaN;
- 其中一个操作数是 NaN,则结果是 NaN。因为 Number() 转换非数值型字符串是 NaN,所以非数值型字符串和数字相乘就是 NaN 。其他的规则与乘法操作符类似。
- 除法:
- 符号: /
- 举例:
44 / 11 ;等于 4
有一点需要注意:如果 Infinity 被 -Infinity 除,那么结果是 NaN。
- 求模:
- 符号: %
- 举例:
26 % 5 ;等于 1
求模就是取余数。
05 加性操作符
加法和减法都被称作是加法操作符。在这里说明一下,加性操作符也会强制转换数据类型。
- 加法:
- 符号: +
- 举例:
1 + 1
需要注意的是,
- 如果两个操作数都是字符串,那么直接拼接起来返回结果;如果其中一个操作数是字符串,那么就把另一个操作数转换乘字符串再拼接起来。
- 利用 Chrome 的 console 命令窗口,实验得到如下的规则:
{} + 11; // 11
11 + {}; // "11[object,object]"
false + 1; // 1 ; 操作数可以调换位置,结果不变
true + 1; // 2 ; 同上
null + 1;// 1 ;同上
undefined + 1 ; // NaN;同上
- 减法:
- 符号: -
- 举例:
2 - 1
减法两边的操作数和加法的区别是,无论是字符串还是对象,都应该转换成数值,再进行计算。不存在字符串相减的情况。
06 关系操作符
关系操作符就是小学的时候学过的小于(<)、大于(>)、小于或等于(<=)、大于或等于(>=)。
JavaScript 中,使用关系操作符比较两个操作数后,返回的结果是布尔值(true、false)。
需要注意的是,
当比较的两个数都是数值时,直接比数字大小;
如果都是字符串则比较对应位置的字符编码值。比如:
"Brick" < "apple"; //返回的是 true,因为 B 的字符编码是 66 ,而 a 的字符编码是 97 "23" < "3"; // 返回 true,因为 2 的字符编码是 50 ,3 的字符编码是 51 。
如果其中一个是数字,则把另一个操作数变为数值以后再比较;
任何数据类型和 NaN 比较都是返回 false。
这里有个小思考:如果 A、B 表示两个数据,有 A > B 不成立(false),则 A <= B 是否成立?
07 相等操作符
JavaScript 提供两种比较方案:
相等(
==
)和不相等(!=
),会把操作数转换成相似的类型再比较。"5" == 5; //true
- null 和 undefined 是相等的;
- 如果有一个操作数是 NaN 则返回 false ;
- NaN 和 NaN 不相等,NaN 返回 true ;
严格相等(
===
)和严格不相等(!==
),直接比较,不转换数据类型,使用严格相等操作符,有一丁点不相等就返回 false。"5" === 5; //false
- null 和 undefined 是不严格相等的
总之,在实际使用过程种,建议是使用严格相等和严格不相等。
08 条件操作符
条件操作符也被称作是三目运算符,用法如下:
let a = 条件语句 ? 1 :2
如果条件语句返回的是 true ,则把 1 赋值给 a,如果是 false, 则把 2 赋值给 a。
返回一个较大值,我们就可以不用谢一个 if 语句,直接按照下面这种写法就可以实现:
let a = (number1 > number2) ? number1 : number2
欢迎大家关注微信公众号:可视化技术( visteacher )
不仅有前端和可视化,还有算法、源码分析、书籍相送
各个分享平台的 KurryLuo 都是在下。
用心学习,认真生活,努力工作!
学习 JavaScript (四)核心概念:操作符的更多相关文章
- 使用Firebug或chrome-devToolBar深入学习javascript语言核心
使用Firebug和chrome-devToolBar调试页面样式或脚本是前端开发每天必做之事.这个开发神器到底能给我们带来哪些更神奇的帮助呢?这几天看的一些资料中给了我启发,能不通过Firebug和 ...
- webpack学习2.3webpack核心概念
核心概念(四个) Entry(入口) Output(出口) Loaders()来处理其他类型的资源文件 Plugins(插件) 1.入口(Entry) 作用:代码的入口,打包的入口,单个或多个, 示例 ...
- Elasticsearch学习之基本核心概念
在Elasticsearch中有许多术语和概念 1. 核心概念 Elasticsearch集群可以包含多个索引(indices)(数据库),每一个索引可以包含多个类型(types)(表),每一个类型包 ...
- Docker 学习笔记之 核心概念
Docker核心概念: Docker Daemon Docker Container Docker Registry Docker Client 通过rest API 和Docker Daemon进程 ...
- 学习 JavaScript (三)核心概念:语法、变量、数据类型
JavaScript 的核心概念主要由语法.变量.数据类型.操作符.语句.函数组成,这篇文章主要讲解的是前面三个,后面三个下一篇文章再讲解. 01 语法 熟悉 JavaScript 历史的人应该都知道 ...
- 如何正确学习JavaScript
不要这样学习JavaScript 不要一开始就埋头在成堆的JavaScript在线教程里 ,这是最糟糕的学习方法.或许在看过无数个教程后会有点成效,但这样不分层次结构地学习一个东西实在是十分低效,在实 ...
- 「译」如何正确学习JavaScript
原文:How to Learn JavaScript Properly 目录 不要这样学习JavaScript 本课程资源 1-2周(简介,数据类型,表达式和操作符) 3~4周(对象,数组,函数,DO ...
- [转]如何正确学习JavaScript
原文:How to Learn JavaScript Properly(2014-2-7) 学习时长:6-8周 学习前提:中学水平,无需编程经验 更新(2014-1-7) 在Reddit上创建了一个学 ...
- 轻松学习JavaScript十八:DOM编程学习之DOM简单介绍
一DOM概述 DOM(文档对象模型)是HTML和XML的应用程序接口(API).DOM将把整个页面规划成由节点层级构成的文档. DOM描绘了一个层次化的节点树,执行开发者加入,移除和改动页面的某一部分 ...
随机推荐
- mybatis源码解读(四)——事务的配置
上一篇博客我们介绍了mybatis中关于数据源的配置原理,本篇博客介绍mybatis的事务管理. 对于事务,我们是在mybatis-configuration.xml 文件中配置的: 关于解析 < ...
- linux基础-系统安装教程篇(centos6.5)
一.linux系统简介: Linux是一套免费使用和自由传播的类Unix操作系统,是一个基于POSIX和UNIX的多用户.多任务.支持多线程和多CPU的操作系统.它能运行主要的UNIX工具软件.应用程 ...
- 使用伪类before和after
.content { padding: 20px } .content::before { content: "我是before添加的内容"; font-weight: bold ...
- 如何在自定义组件中使用v-model
文章属于速记,有错误欢迎指出.风格什么的不喜勿喷. 先来一个组件,不用vue-model,正常父子通信 <!-- parent --> <template> <div c ...
- URL 规范 整理
URL 规范 不用大写:(强制) 用中杠-不用下杠_:(强制) 参数列表要encode,编码使用utf-8:(强制) URI中的名词表示资源集合,使用复数形式.(建议) 增加版本号(建议) URI中统 ...
- Netflix性能监控工具Vector
简介: Vector是Netflix开源的主机级性能监控框架,向每位工程师的浏览器提供精心挑选的高分辨率系统和应用程序指标. 登录到系统并从shell运行大量命令是一种选择,但是通常涉及的复杂性可能成 ...
- Spring Boot常用注解总结
Spring Boot常用注解总结 @RestController和@RequestMapping注解 @RestController注解,它继承自@Controller注解.4.0之前的版本,Spr ...
- 【转】JavaScript 错误处理与调试——“错误处理”的注意要点
try-catch语句 该语句最适合处理那些我们无法控制的错误,在明明白白地知道自己的代码会发生错误时,再使用该语句就不太合适了. ECMA-262第3版引入了try-catch语句,基本的语法如下所 ...
- Nctf_web_wp
1.签到题 右键源代码即可2.md5 collision 这个考点是php"=="的弱相等,为何会出现弱加密呢,是因为在比较==两边的时候,会将字符串类型转化为相同, ...
- 盒子模型、IFC、BFC和Collapsing margins
前言 盒子模型作为CSS基础中的基础,曾一度以为掌握了IE和W3C标准下的块级盒子模型即可,但近日在学习行级盒子模型时发现原来当初是如此幼稚可笑.本文尝试全面叙述块级.行级盒子模型的特性.作为近日学习 ...