JS数据类型
简单的分为原始值类型和对象类型
原始值类型
number
- 包含以下几种值
- 有效数:0、正负数、Infinity
- 非有效:NaN,NaN与任何值都不等,包括NaN
// isNaN([value])用于检测某变量是否为有效数字,@return:Boolean
// isNaN会将传入的[value]均隐式的转化为数字类型,再判断是否为有效数字
- js数字类型的精度wenti --加链接
string
js没有char类型,在js中,用单引号/双引号/反引号,包起来的都是字符串
null
undefined
boolean
symbol
唯一值,执行Symbol创建处理的值永不相等。
- 注意点:
- symbol不能进行运算,Symbol是构造函数,但不能new Symbol(…)。
- Symbol()返回的是基本类型值,不是Symbol类型所以不是Symbol实例,要产生实例必须Object(Symbol())。
- Symbol值可以强制转换为字符串,调toString()。
- 深克隆一个含有Symbol键的对象不会把Symbol键值对克隆。
- Object.getOwnPropertySymbols(obj)返回所有Symbol键名的数组。
- symbol用途
- symbol用于对象唯一键名
//给对象添加属性
let obj = {...}
/**
* 此处想给obj对象添加属性或方法
* 但obj比较庞大,结构复杂,添加属性或方法的命名可能冲突
* 借助Symbol添加一定不会重复
*/
let nameSpace = {
up: Symbol('up方法'),
down: Symbol('down方法')
}
obj[nameSpace.up] = function() {
console.log('up');
}
//调用:
obj[nameSpace.up]()
// 这种方式创建symbol键值对是错误的,obj的symbol属性将永远取不到
let obj = {
[symbol]: 'the value'
}
- 对象属性保护
//对象属性保护
const SITE = Symbol('这是一个symbol')
class User {
constructor (name, age) {
this.name = name;
this.age = age;
this[SITE] = '**私有属性**'
}
}
let user = new User('lisi',22)
for (const key in user) {
//site属性遍历不出
console.log(key);
}
- 宏观标识管理(Vuex/Redux宏唯一)
- 排除字符串耦合
let grade = {
jam: {js: 100, css: 60},
jam: {js: 90, css: 70}
}
//后面的会被覆盖掉
console.log(grade.jam);
//使用对象封装,并添加symbol唯一标识
let user1 = {
name: 'jam',
key: Symbol()
}
let user2 = {
name: 'jam',
key: Symbol()
}
let grade = {
//Symbol()作为键时,必须加中括号
[user1.key]: {js: 100, css: 60},
[user2.key]: {js: 90, css: 70}
}
console.log(grade[user1.key]);
- 消除魔术字符串
//如果有静态常量字符串作为判断标识,则每次都手动输入容易错误
//应该用Symbol宏变量将其包装成唯一值
function foo(param) {
switch (param) {
case 'param1':
...
break;
}
}
//传参时进入函数的switch进行字符串判断
//程序是否能正常执行完全取决于字符串的拼写正确与否,属于强耦合
//若有不一致,不会报错,只是不能进入相应逻辑判断体,排错困难
foo('param1')
//应该提取为唯一宏变量
const nameSpace = {
param1: Symbol('param1')
}
function foo(param) {
switch (param) {
case nameSpace.param1:
...
break;
}
}
// 若变量名书写错误会报错,很好排错
foo(nameSpace.param1)
- Symbol常量用作底层接口 --加链接
-
Symbol.hasInstance 在Function.prototype上,所有函数都能调用这个方法。是instanceof的底层原理。
-
Symbol.iterator 迭代接口的实现,所有可迭代类和类的实例都有这个迭代接口。
-
Symbol.toPrimitive 是一个函数,执行它可以干扰一个对象隐式转换为原始值时输出的结果。
-
Symbol.toStringTag: 调用Object原型上的toString方法时返回指定的[Object xxx类型] (eg: [object Array])。自定类设置标签需要用到toStringTag属性。
bigint
Number.MAX/MIN_SAFE_INTEGER 之外的所有数字进行计算均需要加n(eg:xxxn-xxxn)
对象类型
标准对象(Object)
标准特殊对象
Array数组
RegExp正则
Date日期
Error通用错误
Math数学库
ArrayBuffer流
Map集合
Set集合
非标准特殊对象
各种Number、String、Boolean等包装类
可调用对象
对象上实现了call方法,即Function
数据类型检测
typeof
操作符检测
- typeof [value]可以是变量、表达式。@return:String。取值可以是以下几种 'undefined' –未定义的变量或值
'boolean' –布尔类型的变量或值
'string' –字符串类型的变量或值
'number' –数字类型的变量或值
'object' –对象类型的变量或值,或null
'function' –函数类型的变量或值
'symbol' –唯一标识之的引用变量
'bigint' –大数变量或值,数字n
- 弊端
- 不能检测null,typeof null = 'object'
- 除了可调用对象,其他对象均返回'object'
- typeof检测一个未被声明的变量,不会报错,返回'undefined'
instanceof
操作符检测 检测当前实例是否属于这个类(或者检测当前值是否为某个类的实例)。
用法: 值 instanceof 类(当前类的原型只要出现在了实例的原型链上就返回true)。
原理:构造函数就近调用Function.prototype上的Symbol.hasInstance方法(es5无法重写,但可以基于es6重写到构造函数的函数对象上),传入实例对象,返回查看实例对象是否在构造函数上的结果。若没有Symbol.hasInstance方法,则实例寻折原型链,对比查找的原型对象与构造函数的原型对象,一旦有则true;找到Object.prototype还没有,则false。原始值类型无法使用instanceof,统一为false,必须进行装箱操作后使用
function P() {}
let p = new P()
// 一下两种检测一样
p instanceof P;
P[Symbol.hasInstance](p)
// es6 重写Symbol.hasInstance
class Fn{
static [Symbol.hasInstace](value) {
...
return true
}
}
// Fn[Symbol.hasInstance]优先调用Fn自己的
xx instanceof Fn // true
它有很多缺陷
- 缺陷1:不能识别原始值
// 原始值与包装值的转化称为 装箱 对象=Object(原始值)/拆箱 原始值=Symbol.toPrimitive/valueOf(对象)
let num1 = 10;
let num2 = Number(10);
num1 instanceof Number // false,而原始值10是Number的一个实例。
num2 instanceof Number // true
constructor
constructor属性值就是可以得到构造函数本身。proto和prototype上都存在constructor。在constructor没有被修改(重定向prototype等)的情况下,始终会是精确的类型检测
Object.prototype.toString.call
专门用于数据类型检测,没有瑕疵。几乎所有类的prototype上都有自己的toString方法,它们的toString都是用于实现将其实例转化为字符串的功能。而Object.prototype的toString并不是用于转化为对象的描述字符串的 普通自定义类的实例调用toString是检测数据类型,在没有设置[Symbol.toStringTag]时,始终是[object Object]。如果有的话,取有的那个值 Object.prototype.toString.call(任意内置类的实例),就是使得任意类的实例均调用Object.prototype上的toString进行类型检测,返回[object 任意类.constructor(内置类不受修改影响)]字符串 Object.prototype.toString.call(基本类型值),返回[object 对应的包装类.constructor(不受修改影响)]