运算符
h1.section { background: lightblue; color: white; padding: 10px; }
一个概念问题:基本数据类型,简单数据类型,原始数据类型 —— 简单 = 原始 < 基本
分类:
原始类型(简单类型):
- 数字(the number type)
- 字符串(the string type)
- 布尔值(the boolean type)
- null (the null type)
- undefined (the undefined type)
对象类型(复杂类型):Object
- 内置对象类型:Funciton, Date, Error, JSON, Promise等 (more)
- 原始类型的包装对象(wrapper object):Number, String, Boolean
- 可用直接量表示的:Object, Array, Function, RegExp, 以及wrapper object
原始类型与对象类型的区别与联系:
区别:
- 原始类型的值保存在栈中,对象类型的值保存着堆中
- 原始类型是不可变的(immutable), 对象类型是可变的(mutable)
- 给变量赋值的时候,原始类型赋的是值,对象类型赋的是引用
- 原始类型没有属性,对象类型有
> var str = "text" //str为原始类型 undefined > var strObj = new String("text") //strObj为对象类型 undefined > str.newProperty = 1 //给str创建一个属性并赋值 1 > strObj.newProperty = 1 //给strObj创建一个属性并赋值 1 > str.newProperty undefined > strObj.newProperty 1
为什么给str创建属性不会报错呢?这涉及到自动包装,请看“联系”部分。
- 对象类型可以用
new
操作符创建,原始类型不能,原始类型可以通过直接量创建或者由对象的某些方法返回得到(toString()
,valueOf()
)
联系:auto-boxing
- 当在原始类型值上进行添加属性、调用方法等只能在对象上进行的操作时,JS会自动创建该原始类型相应的包装对象,并在该包装对象上进行操作,所以不会报错,但操作结束后这个对象就立即被销毁了。所以
> var str = "text" //str为原始类型 undefined > str.newProperty = 1 //给str创建一个属性并赋值 1 > str.newProperty undefined
这里的第二条语句在执行时实际上创建了一个
new String(str)
,但在第三条语句执行的时候,刚刚创建的那个对象已经不在了。 - 当用
call
和apply
方法传入的第一个参数(this
指向的那个)是原始类型时,在非strict模式下,除了null
和undefined
会被全局对象取代,其他原始类型会转换为相应于的包装对象。
各类型要点:
数字类型 (The Number Type)
- 值:
-Infinity
, 负数,-0
,0
,+0
, 正数,(+)Infinity
,NaN
- 进制:默认十进制,0X或者0x开头为十六进制
- 进制转换可用
parseInt(value, digit)
方法
- 进制转换可用
- NaN
- NaN与任何值都不相等,包括它自己
- 判断变量x是否是NaN的方法:
- 判断
x!=x
, 如果结果为true
, 表示x的值为NaN, 因为只有NaN不与自己相等 isNaN(x)
检测NaN
isFinite(x)
排除NaN
,Infinity
,-Infinity
字符串 (The String Type)
本节讨论的是字符串直接量,而非String包装对象(new String()
)
- length属性计算的是字符串包含的16位值得个数,有些字符不能表示为16位的字符将采用utf-16编码规则——用两个16位值组成。所以,有些字符的长度可能为2。
> "e".length 1 > '?'.length 2
然而这种情况比较少见
- Using JavaScript’s Array Methods on Strings
布尔值 (The Boolean Type)
暂时没什么好说的
null
- 注意
typeof
javascript var car = null; alert(typeof car); //"object"
undefined
- 注意
typeof
:不仅未赋值的变量是”undefined”, 就连本身会报错的未声明变量javascript > var ab; // 声明了ab,但没赋值 > typeof ab 'undefined' // 这个结果是理所应当的 > typeof adfasdf //adfasdf是什么鬼,根本没声明过的东西 'undefined' // 然而。。却得到和声明过的变量一样的待遇,confusing huh? 记住就好!
对象 (Object)
暂时没甚好说的
类型检测:
typeof
只有七个可能的值:"number"
,"string"
,"boolean"
,"undefined"
,"object"
,"function"
,"symbole"(ECMAscript 2015)
instanceof
检查的是实例的[[Prototpye]](或者__proto__)
与构造函数的prototype
属性是否相等:
> var arr = [];
undefined
> arr instanceof Array //事实上检查的是 arr.__proto__ === Array.prototype (true)
true
constructor
可以通过prototype进行修改
– Object.prototype.toString.call
无法区分自定义的类型
检测null, undefined:
分别直接检查值是否 === null
和 === undefined
, 不能用==
,因为会进行类型转换
> var i = null;
undefined
> var j = {};
undefined
> j === null
false
> i === null
true
> var hahah;
undefined
> hahah === undefined
true
> safasdf === undefined //为声明变量正常报错~ typeof can never!
ReferenceError: safasdf is not defined
at repl:1:1
at REPLServer.defaultEval (repl.js:132:27)
at bound (domain.js:254:14)
at REPLServer.runBound [as eval] (domain.js:267:12)
at REPLServer.<anonymous> (repl.js:279:12)
at REPLServer.emit (events.js:107:17)
at REPLServer.Interface._onLine (readline.js:214:10)
at REPLServer.Interface._line (readline.js:553:8)
at REPLServer.Interface._ttyWrite (readline.js:830:14)
at ReadStream.onkeypress (readline.js:109:10)
检测原始类型的number, boolean, string: typeof
> typeof 1
'number'
> typeof 1.2
'number'
> typeof 1.200
'number'
> typeof 0x1233
'number'
> typeof 0123
'number'
> typeof Infinity
'number'
> typeof -0
'number'
> typeof NaN
'number'
> typeof new Number(3)
'object'
> typeof "2"
'string'
> typeof "\n"
'string'
> typeof 'c'
'string'
> typeof new String("test")
'object'
> typeof "true"
'string'
> typeof true
'boolean'
> typeof false
'boolean'
> typeof new Boolean(false)
'object'
检测对象类型:typeof
- 注意:除了Function和Symbol,所有类型的对象,
typeof
都是object
> typeof new Function()
'function'
> typeof new String()
'object'
> typeof new Date()
'object'
> typeof new RegExp()
'object'
> typeof new Number()
'object'
> typeof new Object()
'object'
> function MyObject() {}
undefined
> typeof new MyObject()
'object'
> typeof MyObject
'function'
- 检测各种不同的Object类型
- 内置对象:
Object.prototype.toString.call(obj)
- 内置对象:
> Object.prototype.toString.call(new String())
'[object String]'
> Object.prototype.toString.call(new Date())
'[object Date]'
> Object.prototype.toString.call(new Boolean())
'[object Boolean]'
> Object.prototype.toString.call(new Error())
'[object Error]'
> Object.prototype.toString.call(new URIError())
'[object Error]'
> Object.prototype.toString.call(new RegExp())
'[object RegExp]'
> Object.prototype.toString.call(new Array())
'[object Array]'
> Object.prototype.toString.call(new Map())
'[object Map]'
> function Haha() {}
undefined
> Object.prototype.toString.call(new Haha()) //非内置的自定义对象无法得到准确的类型名
'[object Object]'
- 自定义对象:
- 区别非同一原型链上的对象:
instanceof
- 区别非同一原型链上的对象:
> var myObject = new MyObject()
undefined
> myObject instanceof MyObject
true
> myObject instanceof Object //也是“父类”的instance
true
- 区分同一原型链上的对象:
constructor
(缺点是,可以被修改)
> myObject.constructor === Object
false
> myObject.constructor === MyObject
true
> MyObject.prototype.constructor = String //把constructor改掉
[Function: String]
> myObject.constructor === MyObject //就检测不到了
false
类型转换:
途径:
- 调用
String()
,Number()
,Boolean()
,Object()
(隐式转换的效果与此相同)- 对数字、字符串、布尔值调用
Object()
其实就是自动包装对象auto-boxing, 如2
变成new Number(2)
Object()
把undefined
和null
转成{}
, 这只能通过显示转换实现- 需要注意的Number()转换:
javascript > Number(undefined) NaN > Number(null) 0 > Number([9]) 9 > Number(['9']) 9 > Number(['9',3]) NaN > Number(['A']) NaN > Number("Infinity") Infinity > +"Infinity" Infinity > Number("-Infinity") -Infinity > Number("-0") -0 > Number("0") 0 > Number("NaN") NaN
- 对数字、字符串、布尔值调用
toString()
:与String()
效果相同,但不同的是,此方法对null
,undefined
无效- 对象到布尔值:所有对象都会转为
true
, 包括new Boolean(false)
javascript > !!new Boolean(false) true
- JS试图将内置对象转为字符串的过程:先尝试
toString()
,如果失败(没得到原始值),再尝试valueOf()
, 若最终得到原始值,将原始值转为字符串,否则报错。 - JS试图将内置对象转为数字的过程:先尝试
valueOf()
,如果失败(没得到原始值),再尝试toString()
, 若最终得到原始值,将原始值转为数字,否则报错。 - 宿主对象有各自的算法转换为数字或字符串。
- 更多字符串-数字相互转换方法:
- 数字转为字符串:
toFixed(n)
: 四舍五入保留n位小数toExponential(n)
: 用科学计数法表示的字符串,小数点后保留n位toPrecision(n)
: 保留n位有效数字
- 字符串转为数字:
parseInt(string, [声明第一个参数的进制])
返回十进制整数或NaN
parseFloat(string)
返回小数或NaN
- 数字转为字符串:
- 特殊内置对象的
toString()
方法:- 数组:各元素用逗号相连的字符串 (注意与JAVA区分,JS中打印数组没有”[]”)
- 函数:函数定义的代码
- 正则:直接量的字符串
- 日期:一个表示详细日期时间信息的字符串,如
'Thu Oct 15 2015 23:37:56 GMT+0800 (中国标准时间)'
valueOf()
方法:- 如果存在任意原始值,就返回原始值
- 默认返回对象本身(数组、函数、正则——返回对象本身)
- 日期:返回毫秒数
运算符与类型转换
- 算术运算符
一元+, 一元-, ++, --, +, -, *, /, %
:- 二元
+
:- 如果有一个操作数是字符串,就会把另一个转为字符串
- 如果有操作数是对象,会先尝试把对象转为原始值,如果转换后有字符串,就进行上一步的操作,否则,将两个原始值转为数字
- 如果两个都是数字,直接相加;如果两个都是字符串,直接连接。
- 除了二元
+
, 其余都将操作数转为数字类型 /
运算符的结果为浮点型(与JAVA不同)%
运算符的结果为浮点型,甚至操作数都可以是浮点型6.5%2.1
的结果为0.2
- 二元
- 比较运算符
==, !=, ===, !==, <, >, <=, >=
===
和!==
不进行类型转换,直接比值==
和!=
会对类型不同的两个数进行类型转换,转换成相同的类型后,按照严格相等===
的规则来比较,类型转换的规则如下:- 如果是null和undefined,它们相等
- 如果是数组和字符串,字符串转为数字(数字比字符串更容易比较)
- 布尔值转为数字
- 如果是对象和原始值,对象转为原始值(对内置对象而言,除了日期对象,其他的先尝试
valueOf()
, 再尝试toString()
)
<, >, <=, >=
的转换规则:- 有对象,先转为原始值
- 两个原始值:如果两个都是字符串,参照String.localeCompare()比较;如果至少有一个不是字符串,都转为数字
- NaN和任何数比较,结果都是false
+
更偏爱字符串,比较运算符更偏爱数字- in运算符:把左操作数转为字符串,右操作数转为对象
- instanceof运算符期待左操作符是一个对象,如果不是的话,不会进行自动转换!!!,而是返回false
- 一元
!
将其操作数转为布尔值并取反