浮点数
JavaScript会自动判断你的浮点数是否有意义,比如1.0
,这样的数会自动保存成1
,因为存储一个浮点数的开销比存储一个整数大得多。
可以用浮点数 + 科学计数法
来表示一个大数:
const num = 3.123e7 // 31230000 复制代码
字母e
后面的数字表示再加上一个要乘的 10 的多少次幂,反之一样,比如31230000e-7
。
0.1 + 0.2 != 0.3
,而是0.300 000 000 000 000 04
,双精度和单精度计算出来的结果还不一样,这是是因为使用了 IEEE 754 数值,这种错误并非 ECMAScript所独有。其他使用相同格式的语言也有这个问题。
部分浮点数在十进制下是有限小数,但是在二进制下尾数是无限数,比如0.1、0.2 尾数0011无限循环。
由于计算精度有限,计算机底层根据IEEE 754舍入规则进行处理后存储了一个近似值(近似值的长度与精度有关),近似值0.3
与 值0.3
在二进制上表现不同,是不能用来比较的,因为近似值和任何数比较都可能返回false。
值的范围
Number.MIN_VALUE // 最小值 5e-324 Number.MAX_VALUE // 最大值 1.7976931348623157e+308 复制代码
如果超出则返回Infinity
or -Infinity
。
也可以通过Number.NEGATIVE_INFINITY === -Infinity
& Number.POSITIVE_INFINITY === Infinity
获取这两个值。
判断一个值是不是无穷值,可以通过isFinite
:
isFinite(Number.POSITIVE_INFINITY) // false isFinite(1) // true 复制代码
NaN
NaN(Not a Number),表示本来要返回数值的操作失败了:
0/0 // NaN 5/0 // Infinity 5/-0 // -Infinity 复制代码
NaN和任何值比较都返回false
哪怕是自身:
NaN === NaN //false 复制代码
判断一个值是否是 不是一个数字,可以通过isNaN
:
isNaN(NaN) // true isNaN(10) // false isNaN('10') // false isNaN('aaa') // true isNaN(true) // false 复制代码
NaN实现会调用对象的valueOf
方法,然后确定返回的值是否可以转换成数值,如果不能,再调用toString
方法,并测试其返回值。
数值转换
3个内置函数,将非数值转换为数值:
Number() + Number(true) ---> 1 + Number(false) ---> 0 + Number('') ---> 0 + Number('1') ---> 1 + Number('asd') ---> NaN + Number('0123') ---> 123 + Number({}) ---> NaN + Number(new Number(1)) ---> 1 + Number(undefined) ---> NaN + Number(null) ---> 0 + Number(070) ---> 56 // Number传入对象时,会调用对象的valueOf方法 parseInt() + parseInt(true) ---> NaN + parseInt(false) ---> NaN + parseInt('') ---> NaN + parseInt('1') ---> 1 + parseInt('0123') ---> 123 + parseInt('asd') ---> NaN + parseInt(undefined) ---> NaN + parseInt(null) ---> NaN + parseInt(new Number(1)) ---> 1 + parseInt(1.3) ---> 1 + parseInt(1.9) ---> 1 + parseInt('1.3') ---> 1 + parseInt('11aa') ---> 11 + patseInt('aa11') ---> NaN // 不同的数值格式很容易混淆,因此parseInt也接受第二个参数,用于指定「进制数」 + parseInt('0xAF', 16) ---> 175 // 按照16进制进行解析 + parseInt('070', 8) ---> 56 // 按照8进制进行解析 + parseInt('10', 10) ---> 10 // 按照10进制进行解析 + parseInt('010', 2) ---> 2 // 按照2进制进行解析 + parseInt('010') ---> 10 // 按照10进制进行解析 parseFloat() + parseFloat('1.2.3.4') ---> 1.2 + parseFloat('0xAF') ---> 0 + parseFloat("0908.5") ---> 908.5 + parseFloat('3.998e7') ---> 39980000 // parseFloat与parseInt基本类似,float支持小数,解析到第一个小数点,后面再有小数点就不解析了,parseFloat只支持10进制 复制代码
String
字面量
字符串的3种字面量:
const age = '12' const name = "HoMeTown" const gender = `male` 复制代码
字符
\n
换行\t
制表\b
退格\r
回车
特点
字符串一旦声明,就不能修改了。
let name = 'HoMeTown' name[2] = 'O' console.log(name) // HoMeTown 复制代码
转换为字符串
toString
true.toString() // true let age = 1 age.toString() // 1 () let opt = {} opt.toString() // [object Object] null.toString() // null没有toString String(null) // 'null' undefined.toString() // undefined没有toString String(undefined) // 'undefined' Object.prototype.toString.call(true) // [object Boolean] 复制代码
toString一般情况下不接收参数,用在数值上的时候,可以传入一个「进制数」,得到该数值的x进制:
let num = 10; console.log(num.toString()); // "10" console.log(num.toString(2)); // "1010" console.log(num.toString(8)); // "12" console.log(num.toString(10)); // "10" console.log(num.toString(16)); // "a" 复制代码
模板字符串
将表达式转换为字符串时会调用
let foo = { name: 1, toString() { console.log("完了,我被调用了"); }, }; let num = new Number(1); num.toString = function () { console.log("数字对象"); return "改一下"; }; const fooStr = `${foo}`; const numStr = `${num}`; console.log(numStr); // 改一下 复制代码
Symbol
Symbol 是原始值,并且是唯一的、不可变的。
let sym = Symbol(); console.log(typeof sym); // symbol let firstSym = Symbol("hello"); let lastSym = Symbol("hello"); console.log(firstSym); // Symbol(hello) console.log(lastSym); // Symbol(hello) console.log(firstSym === lastSym); // false // let tryNewSym = new Symbol(); // Uncaught TypeError: Symbol is not a constructor // 使用Symbol.for 可以使用之前创建过的symbol let forSym1 = Symbol.for("hello"); let forSym2 = Symbol.for("hello"); console.log(forSym1); // Symbol(hello) console.log(forSym2); // Symbol(hello) console.log(forSym1 === forSym2); // true // 使用Symbol.keyFor 可以查询全局注册表 console.log(Symbol.keyFor(forSym1)) // hello console.log(Symbol.keyFor(forSym2)); // hello 复制代码
Symbol属性
定义对象属性:
const s1 = Symbol("msg"); const s2 = Symbol("gender"); const s3 = Symbol("name"); const s4 = Symbol("address"); let opt = { [s1]: "hello", }; console.log(opt); // {Symbol(msg): 'hello'} console.log(opt[s1]); // hello Object.defineProperty(opt, s2, { value: "male" }); console.log(opt); // {Symbol(msg): 'hello', Symbol(gender): 'male'}Symbol(msg): "hello"Symbol(gender): "male"[[Prototype]]: Object console.log(opt[s2]); // male Object.defineProperties(opt, { [s3]: { value: "HoMeTown", }, [s4]: { value: "北京", }, }); console.log(opt); // ...Symbol(name): HoMeTown, Symbol(address): 北京 复制代码
获取对象上的属性:
console.log(Object.getOwnPropertyNames(opt)); // ['id'] console.log(Object.getOwnPropertySymbols(opt)); // [Symbol(msg), Symbol(gender), Symbol(name), Symbol(address)] console.log(Object.getOwnPropertyDescriptors(opt)); // {id: {…}, Symbol(msg): {…}, Symbol(gender): {…}, Symbol(name): {…}, Symbol(address): {…}} console.log(Reflect.ownKeys(opt)); // ['id', Symbol(msg), Symbol(gender), Symbol(name), Symbol(address)] 复制代码
内置 Symbol符号
Symbol.hasInstance
instanceof 的原理就是Symbol.hasInstance
,用来检测一个对象实例的原型上是否有原型:
class Foo {} const foo = new Foo(); console.log(foo instanceof Foo); // true 复制代码
在ES6 中,instanceof 操作符会使用 Symbol.hasInstance 函数来确定关系。以 Symbol.
hasInstance 为键的函数会执行同样的操作,只是操作数对调了一下:
console.log(Foo[Symbol.hasInstance](foo)); // true 复制代码
这个属性定义在 Function 的原型上。因此默认在所有函数和类上都可以调用。由于 instanceof
操作符会在原型链上寻找这个属性定义,就跟在原型链上寻找其他属性一样,因此可以在继承的类上通过静态方法重新定义这个函数:
class Foo { static [Symbol.hasInstance]() { return false } } console.log(foo instanceof Foo); // false 复制代码
Object
对象其实就是一堆数据和功能的集合。
每个 Object 实例都有如下属性和方法。
- constructor:用于创建当前对象的函数。在前面的例子中,这个属性的值就是 Object()函数。
- hasOwnProperty(propertyName):用于判断当前对象实例(不是原型)上是否存在给定的属性。要检查的属性名必须是字符串(如 o.hasOwnProperty("name"))或符号。
- isPrototypeOf(object):用于判断当前对象是否为另一个对象的原型。
- propertyIsEnumerable(propertyName):用于判断给定的属性是否可以使用for-in 语句枚举。与 hasOwnProperty()一样,属性名必须是字符串。
- toLocaleString():返回对象的字符串表示,该字符串反映对象所在的本地化执行环境。
- toString():返回对象的字符串表示。
- valueOf():返回对象对应的字符串、数值或布尔值表示。通常与 toString()的返回值相同。
总结
Js的数据类型:String
、Number
、Null
、Undefined
、Bollean
、Symbol
、Object