深究js(五)——运算符

2024-03-15 16:48
文章标签 js 运算符 深究

本文主要是介绍深究js(五)——运算符,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

    JavaScript的运算符用于算术表达式、比较表达式、逻辑表达式、赋值表达式等等。大多数的运算符都是标点符号,如加减乘除,而有一些运算符是关键字,如delete和instanceof。下图是有关运算符的,顺序按优先级排列,由高到低优先级依次减少(每个水平分割线内的操作符都是同一优先级),标题A为运算符的结合性,L(从左往右),R(从右往左),标题N为操作数的个数,标题为类型的表示期望的操作数类型和运算符结果类型。


    在JavaScript的操作符中,我们可以根据操作数的个数进行分类。如果一个复杂表达式由一个操作符和一个表达式组成的话,这个运算符叫一元运算符,如求反的-x。如果两个表达式加一个操作符组成一个表达式的话,这叫二元运算符,如x+y。如果是三个表达式和一个操作符组成一个复杂表达式的话,这叫三元运算符,如a?b:c。

    在该表中有个注释叫左值,左值指的是表达式只能出现在赋值运算符的左侧,如变量、对象属性和数组元素都是左值。在ECMAScript规范里允许内置函数返回一个左值,但自定义的函数则不能返回一个左值。

    需要注意的是,在JavaScript的优先级里,属性访问表达式和调用表达式的优先级比typeof的还要高。也就是说,像如下的例子:

typeof my.functions[x](y)
    该表达式运行的方向是先执行中括号的,再执行小括号的,最后才到typeof。在JavaScript中,运算的顺序是从左往右的。接下来下面就来填补前一章所遗留下来的坑,这个坑分别是算术表达式的运算符、关系表达式的运算符、逻辑表达式的运算符合赋值表达式的运算符。


一、算术运算符

    常见的基本算术运算符有五种,分别是“+”、“-”、“*”、“/”和“%”。“+”留作一会再讲,现在讲其余四个。这四个运算符在执行操作的时候,JavaScript会自动的将操作数转换为数字类型,然后进行操作,如果转换的结果是NaN的话,则运算返回的是"NaN"。在JavaScript中,所有的数字都是浮点型,所以在执行两个整数相除,如:

var x = 5/2
    返回的是2.5而不是2。在别的编程语言如java,如果除数为0的话则会报错,但是在JavaScript中则不会报错,返回的结果是正无穷大或者负无穷大,而如果0除0的话返回结果是NaN,这个需要注意。

    操作符“%”是进行求余运算,即求两数相除的余数,比较常见的是整数之间求余,其实小数也可以求余。如6.5%2.1,余数是0.2。

    接下来着重讲的是“+”运算符。为什么放到最后讲,是因为“+”在JavaScript中有两种用法,第一种上一篇已讲过,就是字符串的连接,第二种是两数求和。其中前者的优先级是比后者高。比如:

var x = 1 + "1"
    返回的结果是11而不是2,因为有字符串1,所以执行这个运算的时候会把数字类型1转换成字符串类型,然后两个字符进行连接。也就是说,如果操作数中有一个是字符串的话,那么“+”执行的是字符串连接。除此之外,如果操作数是对象的话,则将对象转换成字符串,如果进行字符串连接。如用JavaScript内置的Date对象作为举例:

var date = new Date()
var x = 1 + date
    返回的结果是一串字符串。

    基本的运算符除了上述五种外,还有一元算术运算符,有“+”,“-”,“++”,“--”,这里的“+”和“-”与上面的不同,这里的是表明数值的正负。一元运算符具有很高的优先级,而且往往都是右结合。这四个运算符如果操作数是字符串的话会将其转换成数字类型,然后进行操作,如果转换成NaN的话则返回NaN。下面有一个误区列举出来让大家看清“++”的用法:

var a = "1"
a++
    如果你以为这个输出的结果是11的话那就大错特错了,“++”运算符不会进行字符串的连接,而是将字符串转换成数字类型然后加1,所以结果是2.。但是如果你是这样的话:

var a = "1"
a = a + 1
    则得到的是11,因为a是字符串,所以加号执行的是字符串连接。除了这些以外,我还要讲一下“++”和“--”他们的数放在左边和放右边是有什么样的区别。当操作符在操作数之前,叫前增量,如++i,这个是将操作数转换成数字类型,并加1,然后返回结果;如果操作符在操作数之后,叫后增量,如i++,这个是同上,但是不返回加1后的结果。如:

var a,b
a = 1; b = ++a
var a,b
a = 1; b = a++
    第一个返回的结果是a和b都为2,第二个返回的结果分别是2和1。同理“--”操作符的结果也是一样的。


二、位运算符

    在讲这个位运算符之前,首先要讲明白整数的二进制编码还有区分好反码和补码的概念,不然等一下会晕乎乎的。我在第二遍讲类型的时候有些地方讲的不明白,现在纠正过来。在JavaScript中是不区分整数值和浮点数值,JavaScript中的所有数字均用浮点数值来表明,JavaScript采用的是IEEE754标准定义的64位浮点格式来表示数字。但是,如果是在一些操作中,如数组索引和位操作符,则是基于32位整数的。这个我已经在第二篇那里纠正过来了,请见谅。

    在二进制中,数不是1(真)就是0(假),那么简单的1在二进制中,全写应该是这样的“0000 0000 0000 0000 0000 0000 0000 0001”,简写可以将前面的0省略,如:1。而反码就是将原来位数全部取反,如果拿1来作例子的话,则1的反码是“1111 1111 1111 1111 1111 1111 1111 1110”。而补码,通常是求一个数的负值,如1的负值是-1,则1的补码就是这个负数的值,那么补码是如何计算的呢,就拿-1来将,首先要求它绝对值的编码,-1的绝对值是1,则他的编码如上所述。然后求1的反码,1的反码上面也有写明,这里不再详写。然后对反码的第一位数加1则得到-1的二进制编码:“1111 1111 1111 1111 1111 1111 1111 1111”

    基础打好了,那么现在来讲位运算符。在JavaScript中,运算符有七种,分别是&(按位与)、|(按位或)、^(按位异或)、~(按位非)、<<(左移)、>>(带符号右移)和>>>(无符号右移)。下面一个一个的讲。

    按位与运算是对它的整型操作数逐位执行布尔与运算。只有两个操作数中相对应的位都是1,结果那一位才是1。如10 & 5,首先将10转换成二进制得:1010。5转换成二进制得101。然后逐位进行与运算。二进制第一位是右边的第一个数,所以从第一位进行比较,0和1为假得0,1和0为假得0,0和1为假得0,1和0为假得0,所以结果是0。

    按位或运算是对它的整型操作数逐位进行布尔或运算,相应位中至少有一个为1则为1,。如10 | 5。按照上面的分析可得结果是1111,转换成十进制是15。

    按位异或运算是对它的整型操作数逐位进行布尔异或运算,如果两个操作数中只有一个相应位为1则为1,反之则为0。如10 ^ 5,结果也是15。而10 ^ 6的结果是12,10 | 6的结果是14。

    按位非运算是将操作数的所有位取反。如果对一个整数使用按位非运算的话,相当于改变它的符号并减一。如~1的结果是-2而不是-1,理解这一点很重要,因为上面说过,一个数的负值二进制也就是该数的绝对值的补码,是由该数的原码求出反码,然后在反码的基础上加一得出补码的,所以~1的结果是-2。

    在正负数中,左移的方式都是一样的,就是将一个操作数中的二进制位进行左移操作,移动的位数由第二个操作数来决定的,移动的位数是0~31之间的整数。左移是二进制位整体向左移动几位,左边的数溢出后由右边的补回0,如3<<2的结果是12。因为3的二进制是11,向左移两位是1100,即12。实际上左移几位相当于第一个操作数乘以2的第二个操作数次方,第二个操作数是2,所以是3乘以2的2次方。不管正负数,如果左移了31位,如2<<31,结果都是0。

    但是在右移中,是区分符号的,这里先讲有符号右移,也就是(>>)。在右移操作中,二进制位向右移动,右边溢出的在左边补,如果这个数是正数,则左边补0,如果是负数则补1。如7>>1=3,而-7>>1=-4,这里右移相当于第一个操作数除以2的第二个操作数的次方,因为上面讲过,负数的二进制是该数绝对值的反码加1,也就是相当于改变它的符号并减一,所以-7>>1等于的是-4而不是-3。

    右移有一个不带符号的,记为(>>>),这里不管是正负数,右边溢出后在左边一律补0,也就是说-7>>>1=2147483644。有符号右移(>>)如果移31位,正数的结果是0而负数是-1。如果是无符号右移31位,则正数是0负数是1。不管是左移还是右移,如果移过了31位,则等于重头移过。如移32位等于移0位,移33位等于移1位,如此类推。


三、关系运算符

    关系运算符有分四种,分为相等和不等运算符(“==”、“===”、“!=”、“!==”)、比较运算符(“<”、“>”、“<=”、“>=”)、in运算符合instanceof运算符。下面一个一个的讲。

    相等运算符(==)和恒等运算符(===)其实有比较大的区别,在JavaScript中,操作数可以根据操作符来自动转换类型,但是在“===”运算符中,操作数则不能进行类型转换,恒等运算符(也称严格相等运算符)不仅比较值,也比较操作数的类型。特别是用在对象之间的比较,如果两个不同变量,即使里面的属性名和值都完全一样,但是在恒等运算符眼里,他们就是不等的,而在相等运算符眼里是相等的。如:

var a = {x : 1}
var b = {x : 1}
alert(a.x == b.x)
alert(a.x === b.x)
    第一个返回的是true,第二个返回的是false。如果要想恒等运算符返回的是真,则要对对象进行复制,详细的看我之前的第二篇。下面一幅图是摘自《JavaScript权威指南》的一幅图,详细的说明了哪种情况下,恒等运算符输出是真,哪种情况下输出的是假。


    而相等运算符进行比较的时候,则可以进行类型的转换,如果1 == “1”,返回结果是真,尽管两个类型不同,但是在JavaScript中已经自动的进行了类型转换,所以结果才返回真。下面同样用一幅图来说明相等运算符什么情况会返回真,什么情况返回假:



    比较运算符用来检测两个操作数的大小关系,这个大小关系有数值大小和字母表大小,这里的字母表大小指的是16位Unicode字符的索引顺序。在进行比较运算的时候,操作数的类型会自动的转换,在比较运算中,如果两个数有一个是数字,则另一个操作数会转换成数字类型。这里和“+”运算符有些区别,“+”运算符如果有一个操作数是字符串的话则另一个操作数会转换成字符串。所以在进行“11”<“3”和“11”<3的比较的时候,前者是字符串的比较,后者将字符串11转换成数字11然后比较,所以前者返回true或者返回false。如果一个操作数是NaN的时候,则比较运算符得出的结果将会是false。

    in运算符希望它的左操作数是一个字符串可以转换成字符串,希望它的右操作数是一个对象,如果右侧的对象有一个名为左操作数的属性名,则返回真。如:

var point = {x : 1, y : 1}
alert("x" in point)    //返回真,因为point对象里面有x属性
alert("z" in point)    //返回假,因为point对象没有z属性
alert("toString" in point)    //返回真,因为point对象继承了toString方法var data = [7, 8, 9]
alert("0" in data)    //返回真,因为数组里面有下标为0的元素
alert(1 in data)      //返回真,因为将数字1转换成字符串1
alert(3 in data)      //返回假,因为该数组下标最大为2
    instanceof运算符则希望左操作数是一个对象,右操作数标识对象的类。如果左侧的对象是右侧类的实例,则返回真,否则返回假。需要注意的是,这个判断是会包含父类来进行判断的,比如Object类是所有对象的实例。下面有一个例子;

var a = new Date()
alert(a instanceof Date)      //返回真,因为a就是由Date类来实例的
alert(a instanceof Object)    //返回真,因为所以对象都是Object类的实例
alert(a instanceof Number)    //返回假,对象a不是Number的实例var b = [1, 2, 3]
alert(b instanceof Array)     //返回真,因为b是Array类的实例
alert(b instanceof Object)    //返回真,因为数组是特殊的对象
alert(b instanceof RegExp)    //返回假,因为数组并不是正则类的实例


四、逻辑运算符

    逻辑运算符有如下三种:“&&”、“||”和“!”,这些操作符是对操作数进行布尔算术运算,经常和关系运算符一起配合使用的。首先讲的是“&&”。“&&”执行的是布尔与操作,这个“&&”有时候也称短路,因为这个运算符一定要两个操作数都是真值才返回真,否则则返回假。所以,如果是第一个操作数返回的是假,则不会执行到第二个操作数,直接返回假。如果第一个操作数返回的是真,则要考虑第二个操作数是否是真值,如果为假则返回假,真则为真。所以灵活的运用“&&”操作符将会减少不必要的代码。

    “||”运算符执行的是布尔或操作,操作数中只要有一个为真则返回真。在操作中,如果第一个为真的话则不会执行第二个操作数,否则则会执行第二个操作数,结果由第二个操作数来决定,这样可以用来写一些比较复杂的表达式,如:

var a = b || 10    //如果有这个变量ba=b,否则a=10
    “!”运算符首先是将操作数转换成布尔值,然后再对布尔值求反。所以“!”运算符总是返回的是真或假。


五、赋值运算符

    常用的赋值运算符是“=”,“=”的运算顺序是从右到左,也就是说像x=y=z=0的意思是给x、y、z三个变量初始化为0。除了这些赋值运算符之外,还有“+=”、“-=”、“*=”、“/=”、“%=”、“<<=”、“>>=”、“>>>=”、“&=”、“|=”和“^=”,这些都不细讲,因为多少人都知道什么意思。如:a+=1即为a=a+1。


六、逗号运算符

    逗号运算符是二元运算符,它的操作数可以是任意类型。它首先计算左操作数,然后计算右操作数,最后返回右操作数的值。它总是会计算左侧的表达式,但计算结果忽略掉,返回的是右操作数的值。如:

i = 0, j = 1, k = 2
    在浏览器的开发者工具栏里输入这段代码,返回的结果是2。其实这个代码等价于下面这段代码;

i = 0; j = 1; k = 2
    所以当左侧的表达式有副作用的时候,但是不想要它的结果,可以用这个逗号运算符。逗号运算符用的最多的是在for循环体里。


七、其他运算符

    其他常见的运算符有条件运算符(?:)、typeof运算符、delete运算符合void运算符。下面则逐个讲解。

    条件运算符是一个三元运算符,如果第一个操作数为真,则取第二个操作数的值作为它的值,否则取第三个操作数的值。如:

a > 0 ? 2 : -2
    typeof运算符是放在操作数前面,用来返回操作数的类型,返回结果是个字符串,下表是经过typeof运算返回的值:

    typeof运算符可以写成typeof(),括号内填参数,使得这个运算符看起来像函数。

    delete运算符是用来删除对象属性或者数组元素,在删除一个对象的属性或者一个数组的元素时,这个属性或者元素不仅仅被设置成一个underfined值,当删除属性,这个属性将不再存在,而删除数组的元素,虽然该元素被删掉,但是数组长度不变。不过不管怎么样,用in运算符是找不到他们的存在。并不是任何东西都可以通过delete运算符删除,一些内置核心和客户端属性是不能删除,用var声明的变量是不能删除,通过function声明的函数和函数参数也是不能删除。在严格模式中,如果delete运算符操作非法,则抛出语法错误,在非严格模式中,如果delete运算符操作非法,则返回false。

    void运算符是一元运算符,它在操作数之前,它的运算过程是操作数会照常运算,但是返回的结果是忽略操作数的运算结果并返回underfined,也就是说会忽略操作数的值。void运算符更多用在客户端URL,如:

<a href="javascript:void window.open()">a</a>
    这个void则让浏览器不必显示这个表达式的计算结果。但是这个void表达式如今比较少用。


这篇关于深究js(五)——运算符的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/812619

相关文章

JS常用组件收集

收集了一些平时遇到的前端比较优秀的组件,方便以后开发的时候查找!!! 函数工具: Lodash 页面固定: stickUp、jQuery.Pin 轮播: unslider、swiper 开关: switch 复选框: icheck 气泡: grumble 隐藏元素: Headroom

在JS中的设计模式的单例模式、策略模式、代理模式、原型模式浅讲

1. 单例模式(Singleton Pattern) 确保一个类只有一个实例,并提供一个全局访问点。 示例代码: class Singleton {constructor() {if (Singleton.instance) {return Singleton.instance;}Singleton.instance = this;this.data = [];}addData(value)

Node.js学习记录(二)

目录 一、express 1、初识express 2、安装express 3、创建并启动web服务器 4、监听 GET&POST 请求、响应内容给客户端 5、获取URL中携带的查询参数 6、获取URL中动态参数 7、静态资源托管 二、工具nodemon 三、express路由 1、express中路由 2、路由的匹配 3、路由模块化 4、路由模块添加前缀 四、中间件

EasyPlayer.js网页H5 Web js播放器能力合集

最近遇到一个需求,要求做一款播放器,发现能力上跟EasyPlayer.js基本一致,满足要求: 需求 功性能 分类 需求描述 功能 预览 分屏模式 单分屏(单屏/全屏) 多分屏(2*2) 多分屏(3*3) 多分屏(4*4) 播放控制 播放(单个或全部) 暂停(暂停时展示最后一帧画面) 停止(单个或全部) 声音控制(开关/音量调节) 主辅码流切换 辅助功能 屏

使用JS/Jquery获得父窗口的几个方法(笔记)

<pre name="code" class="javascript">取父窗口的元素方法:$(selector, window.parent.document);那么你取父窗口的父窗口的元素就可以用:$(selector, window.parent.parent.document);如题: $(selector, window.top.document);//获得顶级窗口里面的元素 $(

js异步提交form表单的解决方案

1.定义异步提交表单的方法 (通用方法) /*** 异步提交form表单* @param options {form:form表单元素,success:执行成功后处理函数}* <span style="color:#ff0000;"><strong>@注意 后台接收参数要解码否则中文会导致乱码 如:URLDecoder.decode(param,"UTF-8")</strong></span>

js react 笔记 2

起因, 目的: 记录一些 js, react, css 1. 生成一个随机的 uuid // 需要先安装 crypto 模块const { randomUUID } = require('crypto');const uuid = randomUUID();console.log(uuid); // 输出类似 '9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d'

学习记录:js算法(二十八):删除排序链表中的重复元素、删除排序链表中的重复元素II

文章目录 删除排序链表中的重复元素我的思路解法一:循环解法二:递归 网上思路 删除排序链表中的重复元素 II我的思路网上思路 总结 删除排序链表中的重复元素 给定一个已排序的链表的头 head , 删除所有重复的元素,使每个元素只出现一次 。返回 已排序的链表 。 图一 图二 示例 1:(图一)输入:head = [1,1,2]输出:[1,2]示例 2:(图

【重学 MySQL】十九、位运算符的使用

【重学 MySQL】十九、位运算符的使用 示例检查权限添加权限移除权限 在 MySQL 中,位运算符允许你直接在整数类型的列或表达式上进行位级操作。这些操作对于处理那些需要在二进制表示上进行直接修改或比较的场景特别有用,比如权限管理、状态标记等。 &(位与) 对两个数的二进制表示进行位与操作。只有两个相应的二进制位都为 1 时,结果的该位才为 1,否则为 0。 |(位

uuid.js 使用

相关代码 import { NIL } from "uuid";/** 验证UUID* 为空 则返回 false* @param uuid* @returns {boolean}*/export function MyUUIDValidate(uuid: any): boolean {if (typeof uuid === "string" && uuid !== NIL) { //uuid