运算符
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.newPropertyundefined> strObj.newProperty1为什么给str创建属性不会报错呢?这涉及到自动包装,请看“联系”部分。
- 对象类型可以用new操作符创建,原始类型不能,原始类型可以通过直接量创建或者由对象的某些方法返回得到(toString(), valueOf())
联系:auto-boxing
- 当在原始类型值上进行添加属性、调用方法等只能在对象上进行的操作时,JS会自动创建该原始类型相应的包装对象,并在该包装对象上进行操作,所以不会报错,但操作结束后这个对象就立即被销毁了。所以
> var str = "text" //str为原始类型undefined> str.newProperty = 1 //给str创建一个属性并赋值1> str.newPropertyundefined
这里的第二条语句在执行时实际上创建了一个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".length1> '?'.length2
然而这种情况比较少见
- 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 === nullfalse> i === nulltrue> var hahah;undefined> hahah === undefinedtrue> 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 MyObjecttrue> myObject instanceof Object //也是“父类”的instancetrue
- 区分同一原型链上的对象:constructor(缺点是,可以被修改)
> myObject.constructor === Objectfalse> myObject.constructor === MyObjecttrue> 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
- 一元!将其操作数转为布尔值并取反



