表达式和运算符
- 原始表达式是表达式的最小单元---它们不再包含其他表达式。javascript中的原始表达式包含常量或直接量、关键字和变量。
// 直接量
1.23
"hello"
/pattern/
// 保留字
true
false
null
this
// 变量
i
sum
undefined
复制代码
- 当Javascript代码中出现了标识符,Javascript会将其当做变量而去查找他的值。如果变量名不存在,表达式运算结果为undefined。
对象和数组的初始化表达式
- 这两种表达式初始化有时称做"对象直接量"和"数组直接量"
- 数组直接量中的列表逗号之间的元素可以省略,这时省略的空位会填充值undefined
- 对象初始化表达式只是方括号被花括号代替,并且每个子表达式包含一个属性名和一个冒号作为前缀。
函数定义表达式
- 一个典型的函数定义表达式包括关键字function,跟随其后的是一对圆括号,括号内是一个以逗号分割的列表,列表含有0个或多个标识符(参数名),然后再跟随一个由花括号包裹的Javascript代码段(函数体)
var fn = function(x){return x}
复制代码
属性访问表达式
- 第一种写法是一个表达式后跟随一个句点和标识符。表达式指定对象,标识符则指定需要访问的属性的名称。
- 第二种写法是使用方括号,方括号内是另外一个表达式(这种方法适用于对象和数组)
- 点的方式只适用于要访问的属性名称是合法的标识符,并且需要知道要访问的属性的名字。如果属性名称是一个保留字或者包含空格和标点符号,或是一个数字(对于数组来说),则必须使用方括号的写法。当属性名是通过运算得出的值而不是固定的值的时候,这是必须使用方括号写法。
对象创建表达式
- 对象创建表达式创建一个对象并调用一个函数(称作构造函数)初始化新对象的属性。对象创建表达式和函数调用表达式非常类似,只是对象创建表达式之前多了一个关键字new
new Object()
new Point(2,3)
复制代码
- 如果一个对象创建表达式不需要传入任何参数给构造函数的话,那么这对空圆括号是可以省略掉的。
运算符的副作用
- delete运算符同样有副作用:删除一个属性就像(但不完全一样)给这个属性赋值undefined
- 属性访问表达式和调用表达式的优先级要比所有运算符都高
- 一元操作符、赋值和三元运算符都具有从右至左的结合性。
算术表达式
- 5/2的结果是2.5,而不是2.除数为0的运算结果为正无穷大或负无穷大,而0/0的结果是NaN,所有这些运算都不会报错
1+2 // 3
"1"+"2" //"12"
"1"+2 // "12"
1+{} // "1[object Object]"
true+true // 2
2+null // 2
2+undefined // NaN
复制代码
一元算术运算符
- "+":一元加法运算符把操作数转换为数字(或者NaN),并返回这个转换后的数字。
- "-":把操作数转换为数字,然后改变运算结果的符号。
- "++":递增运算符对其操作数进行增量(加一)操作。(注意a++和++a的区别)。表达式++x并不总和x=x+1完全一样,"++"运算符从不进行字符串拼接操作,它总是会将操作数转换为数字并增1.
- "--":和递增类似。
位运算符
- 按位与(&):执行(AND)操作,只有两个操作数中相对应的位都是1,结果中的这一位才是1。
- 按位或(|):执行(OR)操作,如果其中一个操作数相应的位为1,或者两个操作数相应为都是1,那么结果中的这一位就是1.
- 按位异或(^):执行(XOR)操作,异或是指第一个操作数位true或第二个操作数为true,但两者不能同时为true。如果两个操作数中只有一个相应位为1(不能同时为1),那么结果中的这一位就是1.(相同为0,不同为1)
- 按位非(~):是一元运算符,位于一个整型参数之前,它将操作数的所有位取反。对一个值使用"~"运算符相当于改变它的符号并减1.
- 左移(<<):a<<1 左移一位相当于乘以2。
- 带符号右移(>>):右移一位相当于除以2。
- 第一个操作数是正数,移位后用0填补最高位。
- 第一位操作数是负数,移位后就用1填补高位。
- 无符号右移(>>>):和运算符一样,只是左边的高位总是填补0,与原来的操作数符号无关。
比较运算符
- 如果两个操作数都是字符串,那么将依照字母表的顺序对两个字符串进行比较,这里提到的"字母表顺序"是指组成这个字符串的16位Unicode字符的索引顺序。
- 在对象转换为原始值之后,如果至少有一个操作数不是字符串,那么两个操作数都将转换为数字进行数值比较。
个人理解:将两个操作数都转换为字符串可以比较的时候就不需要再进行向下转换。否则最终是需要转换为数字进行比较
- 字符串比较区分大小写的,所有的大写的ASCII字母都"小于"小写的ASCII字母。
- 对于数字和字符串操作符来说,加号运算符和比较运算符的行为都有所不同,前者更偏爱字符串,如果它的其中一个操作数是字符串的话,则进行字符串连接操作,而比较运算符则更偏爱数字,只有在两个操作数都是字符串的时候,才会进行字符串的比较。
- in运算符希望它的左操作数是一个字符串或可以转换为字符串,希望它的右操作数是一个对象。如果右侧的对象拥有一个名为左操作数值的属性名,那么表达式返回true。(判断当前属性是否属于当前对象)
- instanceof运算符希望左操作符是一个对象,右操作数标识对象的类。(判断当前实例属于这个类)
- 所有的对象都是Object的实例。当通过instanceof判断一个对象是否是一个类的实例的时候,这个判断也会包含对"父类"的检测。如果instanceof的左操作数不是对象的话,instanceof返回false。如果右操作数不是函数,则抛出一个类型错误异常。
逻辑表达式
- 逻辑或(||)会首先计算第一个操作数的值,也就是说会首先计算左侧的表达式,如果计算结果为真值,那么返回这个真值,否则,在计算第二个操作数的值,即计算右侧的表达式,并返回这个表达式的计算结果。
- 通常这种惯用法用在函数体内,用来给参数提供默认值。
function copy(o,p){
p = p || {} // 如果向参数p没有传入任何对象,则使用一个新创建的对象
}
复制代码
- 逻辑非(!)运算符首先会将操作数转换为布尔值,然后再对布尔值求反。也就是说"!"总是返回true或者false,并且,可以通过使用两次逻辑非运算来得到一个值的等价布尔值:!!x.
!(p && q) === !p || !q
!(p || q) === !p && !q
复制代码
typeof运算符
- typeof是一元运算符,放在其单个操作数的前面,操作数可以是任意类型。返回值为表示操作数类型的一个
字符串
.
x typeof
undefined "undefined"
null "object"
true或false "boolean"
任意数字或NaN "number"
任意字符串 "string"
任意函数 "function"
任意内置对象(非函数) "object"
复制代码
delete运算符
- delete是一元操作符,它用来删除对象属性或者数组元素。
var o = {x:1,y:2}
delete o.x
"x" in o // false
var a = [1,2,3]
delete a[2]
2 in a; //false 第三个索引也就是2不存在了
a.length // 3 :数组长度并没有改变,删除后操作留下了一个"洞",实际上并没有修改数组的长度,因此a数组的长度仍然是3
复制代码
- 并不是所有的属性都可删除,一些内置核心和客户端属性是不能删除的,用户通过var语句声明的变量不能删除。同样,通过function语句定义的函数和函数参数也不能删除。
var o = {x:1,y:2} // 定义一个变量,初始化为对象
delete o.x // 删除一个对象属性,返回true
typeof o.x // 属性不存在 返回"undefined"
delete o.x // 删除不存在的属性,返回true
delete o // 不能删除通过var声明的变量,返回false
// 在严格模式下,将抛出一个异常
delete 1; // 参数不是一个左值 返回true
this.x = 1; // 给全局对象定义一个属性,这里没有使用var
delete x; // 试图删除它 在非严格模式下返回true
// 在严格模式下会抛出异常,这时使用"delete this.x"来代替
x // 运行时错误 没有定义x
复制代码