string 不是,存储于字符串常量区,JS 屏蔽了这些细节,使其表现同其他基本数据类型)numberJavaScript 使用 IEEE 754 标准定义的 64 位浮点格式表示数值(绝大多数现代编程语言都使用该标准,如 C、Java)
这意味着:
Infinity 或 -Infinity
Number.MAX_VALUE:1.7976931348623157e+308Number.MIN_VALUE:5e-324Number.MAX_SAFE_INTEGER:2^53 - 1Number.MIN_SAFE_INTEGER:-(2^53 - 1)0.1+0.2 === 0.3 // falseMath.abs((0.1+0.2) - 0.3) < Number.EPSILON // trueMath.abs((0.1+0.2) - 0.3) < 0.0001 // true0b11010o74
074,但基本禁止使用(如严格模式、ESLint),因为:
074 是八进制084 是十进制(超出 0~7)0o74,因为 0o84 会报语法错误,而不是莫名其妙以十进制解析1230x5F(字母大小写都可以)1.6e9 // 1.6 * 10^9(e 大小写都可以)1.6e+9 // 1.6 * 10^91.6e-9 // 1.6 * 10^-910_000 // 10000.16 === 0.16 // true16. === 16 // true
16.toString() // SyntaxError: Invalid or unexpected token16. 被认为是一个数字,数字toString() 语法错误16..toString()、(16).toString()NaN:Not a Number,非法数字
0 / 0、undefined - 10NaN 的操作都会返回 NaNNaN 与任何值都不相等,包括它自身(即:NaN !== NaN)Infinity:无穷大
5 / 0、Infinity - 10000Infinity 无论如何运算都将是 InfinityInfinity - Infinity // NaN-Infinity:无穷小
-5 / 0、5 / -0-Infinity 无论如何运算都将是 -InfinityInfinity - Infinity // NaN补充:
0 / 5 // 0+0 和 -0 (+0 即 0)
+0 === -0 // trueObject.is(0, -0) // falseNumber(xxx)、+xxxboolean:true → 1;false → 0null → 0undefined → NaN
+undefined // NaNNumber(undefined) // undefinedNumber() // 00
+'' // 0+' ' // 0+'\t' // 0+"0b110" // 6+"0o46" // 38+"46" // 46
0 被省略,而不是认为八进制 +"046" // 46Number(046) // 38Number('0.16') // 0.16Number('.16') // 0.16Number('000.16') // 0.16Number('010.16') // 10.16NaN
Number('0o468')Number('66NB')Number('NB666')parseIntparseInt(字符串, 第一个参数的进制),第二个参数默认是 10,介于 2~36(36:0~9 + A~Z)
NaN0 或未指定,基数将会根据字符串的值进行推算parseInt:向零取整;Math.floor:向下取整// 二进制
parseInt("0b110") // 16
// 八进制
parseInt('0o46') // 38
// 十进制
parseInt('46') // 46
// ECMAScript 5 移除了八进制解析
parseInt('046') // 46,ECMAScript 5 之前会是 38
parseInt('049') // 49
// 十六进制
parseInt('0x6a') // 106
// 前面可以有空白
parseInt(' 46') // 46
parseInt('\t46') // 46
// 空白串是 NaN
parseInt('') // NaN
parseInt(' ') // NaN
// --------------------------------
parseInt("0b113") // NaN
parseInt('46真不错') // 46
parseInt('46.6') // 46
parseInt('46+5') // 46
parseInt('a46') // NaN
// 传入的参数不是字符串,会自动转换成字符串
parseInt(true) // NaN
parseInt({}) // NaN
parseInt(4*5) // 20
parseInt(014) // 12,这里是先运算,再自动转换成字符串
const arr = ['1', '2', '3']
const result = arr.map(parseInt)
console.log(result) // [1, NaN, NaN]
// 为什么?
// 因为
arr.map(parseInt)
// 相当于
arr.map((item, index) => parseInt(item, index))
// 第二个参数为 0,基数将会根据字符串的值进行推算
parseFloat同 parseInt,但没有进制概念
parseFloat('3.14159265ufo') // 3.14159265
parseFloat('12.3.4') // 12.3
NumberNumber.POSITIVE_INFINITY // 同 Infinity
Number.NEGATIVE_INFINITY // 同 -Infinity
Number.NaN // 同 NaN
Number.EPSILON // 2 ** -52,数值与数值之间最小的差
Number.parseInt() // 同全局 parseInt() 函数
Number.parseFloat() // 同全局 parseFloat() 函数
Number.isNaN(x) // 判断 x 是不是 NaN
Number.isFinite(x) // 判断 x 是不是有限
Number.isInteger(x) // 判断 x 是不是整数
Number.isSafeInteger(x) // 判断 x 是不是安全范围内的整数
isNaN() VS. Number.isNaN()isNaN():判断传入的参数是否可以转换为 NaN
isNaN(1) // false
isNaN('1') // false
isNaN(true) // false,布尔 true 可以转化为 1
isNaN('abc') // true
isNaN(NaN) // true
isNaN(undefined) // true
Number.isNaN():ES6 新增,只有传入 NaN 才返回 true,传入其他值都是 false
boolean只有两个值:true、false
!!a === true 的变量!!a === false 的变量以下是 falsely 变量,除此之外都是 truly 变量:
number:0、NaNstring:''
!!' ' // truenullundefined特别强调:引用类型转换为 boolean 都是 true,即使是空对象或空函数
string" 和单引号 ' 完全等价、ES6 新增 [[#模板字符串|模板字符串]] 反引号String():将传入的参数转换为字符串(调用其 toString 方法)new String():返回的是一个字符串对象(前两种方法得到的都是基本数据类型)const age = 18
// 不使用模板字符串
const s1 = '刚满 ' + age + '岁'
// 使用模板字符串
const s2 = `刚满 ${age}岁`
// 转义
`\`` === "`"; // true
`\${1}` === "${1}"; // true
// 不使用模板字符串
const s1 = '<div>\n' +
' Hello World!\n' +
'<div>'
// 使用模板字符串
const s2 = `<div>
Hello World!
<div>`
function myTag(strings, ...exps) {
const arr = []
const len = exps.length
for (let i = 0; i < len; i++) {
arr.push(strings[i], exps[i])
}
arr.push(strings[len])
return arr.join('')
}
const res = myTag`刚满 ${18} 岁`
console.log(res) // 刚满 18 岁
JavaScript 使用 [[001.词法结构#Unicode|Unicode]] 字符集的 UTF-16 编码,因此 JavaScript 字符串是无符号 16 位值的序列
null 和 undefinedReferenceError: xxx is not definedundefined:表示“未定义”
undefinedundefined?
undefined)的变量null:表示空对象、空指针,一般指引用数据类型指向为“空”,表示“引用空”
null?
nullnullnullboolean,是 falsestring,是其本身
null + '' // "null"undefined + '' // "undefined"TypeError
null.toString() // TypeError: Cannot read properties of null (reading 'toString')undefined.toString() // TypeError: Cannot read properties of undefined (reading 'toString')== 但不 ===
null == undefined // truexxx == null 代替 xxx === null || xxx === undefinednull 是关键字;undefined 是全局变量typeof
typeof null // "object"typeof undefined // "undefined"number:null 是 0;undefined 是 NaN
null + 0 // 0undefined + 0 // NaNsymbol代表创建后独一无二且不可变的数据类型
它的出现主要是为了解决可能出现的对象键名冲突的问题
#todo
bigint是一种数字类型的数据,可以表示任意精度格式的整数
字面量(数字后跟小写字母 n):
1234n // 十进制
0b10101010n // 二进制
0o7777n // 八进制
0xffff56 // 十六进制
可以用 BigInt() 函数把 number 或 string 转换为 bigint:
BigInt(562) // 562n
const str = '1' + '0'.repeat(100) // 1 后跟 100 个 0
BigInt(str) // 一个天文数字:10n**100n
bigint 值的算术运算与 number 的算术运算类似,只不过是整数,如:除法会丢弃余数并且会向零舍入
1000n + 2000n // 3000n
3000n - 2000n // 1000n
2000n * 3000n // 6_000_000n
3000n / 997n // 3n
3000n % 997n // 9n
(2n ** 131071n) - 1n
注意:不能混合 bigint 和 number 操作数进行算术运算
bigint:可以表示超大值,但只能是整数number:不能表示超大值,但可以是整数或浮点数比较操作符允许混合操作数类型:
1 < 2n // true
2 > 1n // true
0 == 0n // true
0 === 0n // false,先比较类型是否相同
位操作符通常可以用于 bigint 操作数;但 Math 对象的任何函数都不接收 bigint 操作数
引用数据类型只有一种:object
{ a: 1, b: 2 }new Object()
new Object(1) 或 Object(1)Object.create(原型对象)
Object.create(null):创建没有原型的“纯”对象Function[[005.函数|函数]]
特殊点:
[[call]] 调用new 关键字)prototype 属性以实现原型体系Array字面量:[1, 2, 3]
特殊点:
length 属性自动更新RegExp字面量:/pattern/flags
Number、Boolean、String 即可作为普通函数使用也可以作为构造函数使用:
Number(xxx)new Number(xxx)基本数据类型要使用其对应包装类型的属性或方法时,会自动装箱成对应包装类型的实例对象
'aa'.split('')
// 相当于:
(new String('aa')).split('')
包装类对象会自动拆箱成基本数据类型
new Number(1) + 2
// 相当于:
1 + 2
==:
null 或 nudefined,就判断另一个变量是否也是 null 或 nudefinednull 或 nudefined:如果类型不同,先进行[[#隐式类型转换|隐式类型转换]],再判断值是否相同;类型相同则直接判断值是否相同===:先判断类型是否相同,不同直接返回 false,之后判断值是否相同
Object.is(a, b):基本同 ===,除了:
NaN === NaN // false;Object.is(NaN, NaN) // true+0 === -0 // true;Object.is(+0, -0) // true。其中 +0 即 0注:switch...case 是使用 === 判断是否匹配
number:+xxx、Number(xxx)boolean:!!xxx、Boolean(xxx)string:xxx + ''、(反引号)${xxx}(反引号)、String(xxx)numbernumber引用数据类型 → 基本数据类型:
Symbol.toPrimitive 方法?
TypeError: Cannot convert object to primitive valuevalueOf 方法
toString 方法
TypeError: Cannot convert object to primitive valuexxx == undefined,会报错 ReferenceError: xxx is not definedtypeof xxx === undefinedundefined:xxx === undefinednull:xxx === nullundefined 或 null:xxx == nullfunction isEmptyObject(obj: object): boolean {
for (let key in obj) {
if (obj.hasOwnProperty(key)) return false
}
return true
}
function isEmptyArray(arr: array): boolean {
return (arr instanceof Array && arr.length === 0)
}
// 或者使用 ES6 新增的 Array.isArray() 方法
typeof用于判断变量的数据类型。
number、boolean、string、undefined、symbol、bigint、object 都是正常的,只有两个特殊:
typeof null === 'object'typeof 函数 === 'function'两种使用方法:
typeof xxxtypeof(xxx)(不推荐)底层机制:直接在计算机底层基于数据类型的值(二进制)进行检测
typeof 12 // "number"
typeof NaN // "number"
typeof '' // "string"
typeof true // "boolean"
typeof undefined // "undefined"
typeof 11n // "bigint"
typeof Symbol() // "symbol"
typeof {} // "object"
// 特殊
typeof null // "object"
// 对象存储在计算机中,都是以 000 开始的二进制存储,null 也是,所以检测出来的结果是对象
typeof function() {} // "function"
typeof () => {} // "function"
// 其他
typeof [] // "object"
typeof /^.$/ // "object"
// 数组和正则都是对象
typeof Symbol // function
instanceof用于判断变量是否是类的实例,作用于引用数据类型
使用方法:实例 instanceof 类
注意点:
1 instanceof 2 // TypeError: Right-hand side of 'instanceof' is not an object1 instanceof Number // falsenew Number(1) instanceof Number // true底层机制:只要当前类出现在实例的原型链上,结果都是 true
[[007.原型与原型链|原型链回顾]]
[] instanceof Array // true
/^.$/ instanceof ReqExp // true
new Date() instanceof Date // true
// 问题 1
1 instanceof Number // false
// instanceof 不能检测基本数据类型
// 问题 2
[] instanceof Object // true
// 无法手动控制查询第几层原型链
// 问题 3
function Fn() {}
Fn.prototype = Array.prototype
new Fn() instanceof Array // true
// 可以肆意修改原型指向
// 当然,实际开发中,几乎不会修改原型指向
// 问题 4
const window2 = window.frames[0]; // 拿到 iframe window 对象
[] instanceof window2.Array // flase
// 必须是同一个全局执行上下文
constructor与 instanceof 一样,但是:
// 解决 instanceof 的问题 1
// 可以检测基本数据类型
const num = 1
1..constructor === Number // true
// 解决 instanceof 的问题 2
// 可以自己写代码,手动控制查询第几层原型链
// 但是性能要比 instanceof 差(无关紧要,几乎无差别)
const arr = []
arr.constructor === Array // true,相当于 arr.__proto__.constructor
arr.__proto__.__proto__.constructor === Object // true
// 问题
// constructor 可以随便改
// 同样,实际开发很少改 constructor
Number.prototype.constructor = 'AA'
1..constructor === Number // false
Object.prototype.toString.call()// const toType = target => {
// return Object.prototype.toString.call(target).slice(8, -1).toLowerCase()
// }
// 其实上面就可以达到效果了,但是还可以优化效率
// typeof 效率更高:避免函数调用和自动装箱
const classof = target => {
const type = typeof target
return type === 'object'
? Object.prototype.toString.call(target).slice(8, -1).toLowerCase()
: type
}
Object.prototype.toString 方法执行步骤:
this 的 [[Class]] 属性的值,记为 xxx[object xxx]xxx 是什么:([[Class]] 类属性)
Array、Date 等)创建的对象包含“类属性”(class attribute),他与构造函数的名称相匹配Symbol.toStringTag 属性,并且值的类型是 string,则是该值"Object"call():
Object.prototype.toString 的 this 指向call() 调用而不是直接使用 xxx.toString() 的原因是防止 toString() 方法被重写call() 中直接传入基本数据类型也是可以的,因为会自动装箱call() 中直接传入 undefined 和 null 也是可以的,因为它俩也有自己唯一的特定类属性(class attribute)标识classof({ [Symbol.toStringTag]: 'Foo' }) // foo
class Bar {
[Symbol.toStringTag] = 'Bar'
}
classof(new Bar()) // bar