基础数据类型
- number数字
- string字符串
- boolean布尔值
- null空
- undefined未定义
- symbol唯一值(es6)
- 给对象设置“唯一值”的属性名
- 字符串
- Symbol类型
- Map新的数据类型:可以允许属性名是对象
- Symbol.asyncIterator/iterator/hasInstance/toPrimitive/toStringTag...是某些JS知识底层实现的机制
- 在派发行为标识统一进行管理的时候,可以基于symbol类型的值,保证行为标识的唯一性
- 给对象设置“唯一值”的属性名
- BigInt大数(es6)
- Number.MAX_SAFE_INTEGER 9007199254740991 JS中的最大安全数
- Number.MIN_SAFE_INTEGER -9007199254740991 最小安全数
- 超过安全数后,进行运算或者访问,结果会不准确!!!
- 解决方案
- 服务器返回给客户端的大数,按照“字符串”格式返回!
- 客户端把其变为 BigInt ,然后按照BigInt进行运算
- 最后把运算后的BigInt转换为字符串,在传递给服务器即可
// console.log(BigInt('90071992547409912434234') + BigInt(12345));
// console.log((90071992547409912446579n).toString());
对象类型 【引用数据类型】
- 标准普通对象 例如:{x:10,y:20}
- 标准特殊对象
- new Array数组
- new RegEXp正则
- Math数学函数UI想
- new Date日期对象
- new Error错误对象
- Set/Map (es6 新增的数据结构)
非标准特殊对象
-
例如:new Number(1) ->原始值类型对应的“对象类型”实例
-
函数对象 function
-
创建一个数字
-
字面量(创建的是原始值) var num1 = 10;
-
构造函数(创建出来的是非标准特殊对象) var num2 = new Number(10);
num1 VS num2
一个是原始值、一个是对象
num2是Number类的一个实例,可以直接调用Number.prototype上的方法;从严格意义角度来讲,num1不是Number类的实例(因为实例都是对象类型的),按理来说num1应该是无法调用Number.prototype上的方法的,
但是实际操作中,是可以调用的,所以也可以称num1是Number累的实例;
num1.toFixed(2) -> new Number(num1)默认会把原始值转换为对象,然后再去调用toFixed方法。我们把这种操作(“把原始值转换为实例对象”)称之为“装箱”!!
num2+10 -> 20 浏览器会默认把实例对象转换为对应的原始值,然后再进行数学运算,这个过程称之为“拆箱”
装箱: new Number(num) 或者 Object(num)
拆箱: 把对象转换为原始值
- 首先调用对象的“Symbol.toPrimitive”函数
- 如果对象不具备这个属性,则调用“对象.valueOf()”函数,看获取的是否为原始值,是原始值则实现目标
- 如果不是原始值,则继续调用“对象.toString()”函数,把其转换为字符串!
- 如果最后的目的是变为数字,则再把字符串转换为数字 例如:
var num2 = new Number(10);
num2[Symbol.toPrimitive] -> undefined
num2.valueOf() -> 10
10+10 => 20
平时项目中会涉及数据类型的检测
- typeof
- instanceof
- constructor
- Object.prototype.toString.call
- Array.isArray()
- isNaN
typeof检测数据类型
- 所有的数据类型值,在计算机底层都是按照 “64位” 的二进制值进行存储的!
- typeof是按照二进制值进行检测类型的
- 二进制的前三位是零,认为是对象,然后再去看有么有实现call方法,如果实现了,返回 'function',没有实现,则返回 'object'
- null是64个零 typeof null -> 'object' 「局限性」
- ...
- 检测未被声明的变量,值是'undefined'
// 场景一:检测当前值是否是一个对象
const fn = options => {
let type = typeof options;
if (options !== null && (type === "object" || type === "function")) {
// 是个对象
}
};
fn({
x: 10,
y: 20
});
fn(10);
// 场景二:支持更多的模块导入方案
(function () {
let utils = {};
if (typeof window !== "undefined") window.utils = utils;
if (typeof module === "object" && typeof module.exports === "object") module.exports = utils;
})();
parseInt/parseFloat都是用来把其它值转换为数字的,从字符串(传递的不是字符串,也要先转换为字符串)左侧第一个字符开始查找,把找到的有效数字字符转换为数字,遇到一个非有效的,则停止查找!一个都找不到,结果是NaN!
“+”在JS中比较特殊:除了数学运算,还有字符串拼接
- 加号两边有一边是字符串
- 加号两边有一边是对象,则可能是字符串拼接
- 如果两边既没有字符串也没有对象,则是数学运算
var a = ?;
if(a == 1 && a == 2 && a==3){
console.log("OK")
}
解决方案一:利用“==”会进行数据类型转换、再利用对象转数字要经过四步,此时我们重写其中某一步,拿到自己想要的即可。
a = {
i : 0
}
a[Symbol.toPrimitive] = function(){
return ++this.i;
}
var a = [1,2,3];
a.toString = a.shift;
解决方案二:
var i =0;
Object.defineProperty(window,'a',{
get(){
return ++i;
}
});
if(a==1 && a==2 && a==3)
console.log("OK")
}