你根本不懂Javascript(2):表达式和运算符

本文最初发布于http://szhshp.org/tech/2017/02/18/JavaSprite.html
转载请注明

表达式和运算符

原始表达式

原始表达式分为三种:

  1. 直接量
1.23       //数字直接量
"hello"    //字符串直接量
/pattern/  //正则表达式直接量
  1. 保留字
true  //返回一个布尔值:真
false //返回一个布尔值:假
null  //返回一个值:空
this  //返回“当前”对象
  1. 变量
i         //返回变量i的值
sum       //返回sum的值
undefined //undefined是全局变量,和null不同,它不是一个关键字

对象和数组的初始化表达式

对象和数组初始化表达式实际上是一个创建新的对象和数组。

因为数组本身就是一个对象

[]         //一个空数组:[]内留空即表示该数组没有任何元素
[1+2,3+4]  //拥有两个元素的数组,第一个是3,第二个是7

var matrix =[[1,2,3],[4,5,6],[7,8,9]];//数组的初始化可以嵌套

var a = new Array(1,2,3)
a = [1,2,3]


var a = new Array(1,,2,3)//报错
a = [1,,2,3]//index=1的元素是undefined

var a = new Array(10)//创建一个长度为10的数组并且值全部为undefined
a = [10]//创建了一个长度为1的数组并且值为10

属性访问表达式

一个典型的函数定义表达式包含关键字function,跟随其后的是一对圆括号,括号内是一个以逗号分隔的列表,列表含有0个或多个标识符(参数名),然后再跟随一个由花括号包裹的JS代码段(函数体),如:

var o = {x:1,y:{z:3}}; //一个示例对象
var a = [o,4,[5,6]];   //一个包含这个对象的示例数组
o.x                    //=>1:表达式o的x属性
o.y.z                  //=>3:表达式o.y的z属性
o["x"]                 //=>1:对象o的x属性
a[1]                   //=>4:表达式a中索引为1的元素
a[2]["1"]              //=>6:表达式a[2]中索引为1的元素
a[1+1][0+1]            //=>6:表达式a[2]中索引为1的元素,大括号里的数据运算后并且转换为了字符串
a[0].x                 //1:表达式a[0]的x属性

相关运算逻辑:

  • 不管用哪种形式的属性访问表达式,在"."和“[”之前的表达式总是会首先计算。
  • 如果计算结果是null或者undefined,表达式会抛出一个类型错误异常,因为这两个值都不能包含任意属性。
  • 如果运算结果不是对象(或者数组),JS会将其转换为对象。
  • 如果对象表达式后跟随句点和标识符,则会查找有这个标识符所指定的属性的值,并将其作为整个表达式的值返回。
  • 如果对象表达式后跟随一对方括号,则会计算方括号内的表达式的值并将它转换为字符串。(注意是计算方括号里面的表达式的值并且转换为字符串)
  • 不论哪种情况,如果命名的属性不存在,那么整个属性访问表达式的值就是undefined

如果属性名称是一个保留字或者包含空格和标志点符号,或是一个数字(对于数组来说),则必须使用方括号的写法。
当属性名是通过运算得出的而不是固定值的时候,这时必须使用方括号写法。

调用表达式

调用表达式以一个函数表达式开始,这个函数表达式指代了要调用的函数。函数表达式后跟随一对圆括号,括号内是一个以逗号隔开的参数列表,如:

f(0)                    //f是一个函数表达式;0是一个参数表达式
Math.max(x,y,z)  //Math.max是一个函数;x,y和z是参数
a.sort()               //a.sort是一个函数,它没有参数
  • 当对调用表达式进行求值的时候,先计算函数表达式,然后计算参数表达式,得到一组参数值。
  • 如果函数表达式的值不是一个可调用的对象,则抛出一个类型错误异常。
  • 然后实参的值被依次赋值给形参,这些形参是定义函数时指定的,接下来开始执行函数体。如果函数使用return语句给出一个返回值,那么这个返回值就是整个调用表达式的值。否则,调用表达式的值就是undefined
  • 任何一个调用表达式都包含一对圆括号和左圆括号之前的表达式。
  • 如果这个表达式是一个属性访问表达式,那么这个调用称作方法调用。在方法调用中,执行函数体的时候,作为属性访问主体的对象和数组便是其调用方法内this的指向。

这部分this的描述很模糊,不过后面会有详细的介绍

对象创建表达式

对象创建表达式(object creation expression)创建一个对象并调用构造函数来初始化对象的属性。对象创建表达式和函数调用表达式非常类似,只是对象创建表达式之前多了一个关键字new:

new Object()
new Point(2,3)

如果对象创建表达式不需要传入任何参数给构造函数的话,那么这对圆括号是可以省略掉的

new Object
new Point

运算符概述

+运算符

  • 如果一个操作数是对象:
    则对象会遵循对象到原始值的转换规则为原始类值。
    日期对象toString()方法执行转换,其他对象如果valueOf()方法返回一个原始值的话,则通过valueOf()方法执行转换。
    由于多数对象都不具备可用的valueOf()方法,因此他们会通过toString()方法来执行抓换
  • 在进行了对象到原始值的转换后,如果其中一个操作鼠是字符串的话,另一个操作数也会转换为字符串。然后进行字符串连接。
  • 否则,两个操作数都将转换为数字(或者NaN),然后进行加法操作。

总结归纳:

  1. 如果是日期那么就使用toString()
  2. 如果不是日期那么看看valueOf()能否返回一个原始值
  • 如果可以,那么就使用这个原始值
  • 如果不行或者当前对象的valueOf()不可用,那么就使用toString()
  1. 以上运算之后
  • 如果一个操作数是字符串,另一个操作数也会转为字符串
  • 如果没有字符串参与运算,那么就将操作数转换为数字然后进行加法操作.这儿不合法的数字都会转成NaN
1 + 2 //=>3 加法
"1" + "2" //=>"12" 字符串连接
"1" + 2 //=>"12"数字转换为字符串后进行字符串连接
1 + {} //=>"1[object object]":对象转换为字符串后进行字符串连接
true + true //=>2 布尔值转换为数字后做加法
2 + null //=>2 null转换为0后做加法
2 + undefined //=>NaN undefined转换为NaN做加法 

因此,加法符号类型混用时需要注意其优先级:

1 + 2 + "bmice" //=> "3 bmice"
1 + (2 + "bmice") => "12bmice"

递增/递减运算符

先来看段代码

var a=1; 
a++;//输出2

var a="1"; 
a++;//输出2,首先将1转换为数字然后自增

var a="abc"; 
a++;//输出Nan,因为abc无法转换为数字

"a"+1; //输出a1
"a"++; //Uncaught ReferenceError: Invalid left-hand side expression in postfix operation,因为左操作数无法转换为数字
  • 递增“++”运算符对其操作数进行增量(+1)的操作,操作数是一个左值(变量、数组元素或者对象属性)。
  • 运算符将操作数转换为数字。
  • 然后给数字加1,并将加1后的数值重新赋值给变量,数组元素或者对象属性。

关系表达式

相等和不等运算符

==运算符用于检测两个操作数是否相等,这里的比较很宽松因为允许了类型转换,检测室会通过如下逻辑:

  1. 如果一个值是null另一个是undefined,则相等
  2. 如果一个是数字一个是字符串,字符串转为数字再比较
  3. 如果是true则转换成1,false转换成0
  4. 如果一个值是对象另一个是数字或字符串,对象则转换成原始值(参考上文逻辑,注意日期类的例外情况)

===的检测就比较严格,会通过如下逻辑:

  1. 如果两个值类型不同,则不相等
  2. 如果两个值都是null/undefined,则不相等
  3. 如果两个值都是布尔值true或者都是布尔值false,则相等
  4. 如果一个是NaN或者都是NaN,则不相等(NaN与任何值都不相等)
  5. 如果都是数字并且值相等,则相等
  6. 如果都是字符串并且对应16位值相同,则相等
  7. 如果两个引用值指向同一个对象,则相等

比较运算符

包含各种>,<,>=,<=等比较运算符的运算逻辑:

  1. 如果操作数为对象,转换成原始值
  2. 转换后如果都是字符串那么按照字母表顺序比较
  3. 转换后如果至少一个不是字符串,那么两个都转为数字进行比较
  4. 如果转换后一个值是NaN那么一定返回false

typeof

typeof也是一个运算符!

delete

delete: 没想到吧, 我也是运算符~

  • 删除属性或者删除数组元素不仅仅是设置一个undefined的值,实际这个属性将不再存在。
  • 读取一个不存在的属性将返回undefined
  • 用户var语句声明的变量不能删除
  • 通过function语句定义的函数和函数参数也不能被删除
var o={x:1,y:2};
delete o.x;//true
typeof o.x;//undefined
delete o.x;//true
delete o;//false, var定义的变量无法删除
delete 1;//...闹哪样?
this.x=1;//重新赋值,注意没有var
delete x;//非严格模式下返回true
//严格模式下会抛出异常,应该用delete this.x代替
x;//运行错误
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容