js数据类型从入门到精通

数据类型

  • 六种原始类型

    • undefined
    • Boolean
    • Number
      • NaN (不是一个有效数字)
      • Infinity (无穷大)
    • String
    • BigInt
    • Symbol
  • Null

  • Object

    • 普通对象
    • 数组对象
    • 正则对象
    • JSON 对象
    • 日期对象
    • Set
    • Map
  • Function

    • 普通函数
    • 箭头函数
    • 构造函数
    • 生成器函数

    引用类型(Object Function)

基本类型和引用类型的区别

基本类型:值存储在栈内存中

引用类型:栈内存中存储的实际是对象在堆内存的引用地址,实际值都存储在堆内存中

Number

NaN 不和任何类型相等

console.log(NaN === NaN); //false

isNaN([value]); // 检测一个是否是无效的数字(不是有效数字是true)

Infinity 无限大 -Infinity 无限小

  • 显示转换

    Number() / parseInt() / parseFloat()

  • 隐式转换

    数学运算(10 - "10" 等于 0) (10 - "10px" 等于 NaN)

    基于 == 比较的时候

    isNaN([value]) // 会先转化成数字再做判断

String

+号除了数学运算还会有字符串拼接

var m = 10;
var n = "10";

console.log(10 + n); // 一边是字符串并且+号两边都有那么就是字符串拼接
console.log(+n); // 只有一边 那么会被转化成数字
console.log(++n); // 两个加号,会转化成数字 并且自身+1
// i++ 和 ++i 和 i+=1  大部分情况相同  i++ 和 ++i 永远都是数学运算 当 i是字符串的时候 i+=1是字符串拼接

// 如果+两边 有对象,那么也有可能是字符串拼接
// 10 + {}  10[Object Object]
// 10+[10] 10[Object Object]
// 特殊
// 10 + new Number(10) // 20
// {} + 10 或者 {name:'11'} + 10  // 都等于10  因为{}没有参数运算,浏览器认为这是一个代码块
// let x = {} + 10 // [Object Object]10 从词法分析上都参与计算了

// 底层机制:对象在做数学运算的时候规则
// + 检测对象的Symbol.toPrimitive这个属性,如果有则基于这个运算,没有继续向下找
// + 检测对象的valueOf() 这个值是基本类型,如果有则直接参与计算,没有继续向下找
// + 获取对象的toString() 把其变成字符串 遇到+ 则拼接

console.log(10 + new Number(10)); // 20 new Number(10).valueOf

let obj = {
  [Symbol.toPrimitive]: function (hint) {
    return 10;
  },
};
console.log(10 + obj); // 20

Symbol 的应用场景

因为每个 Symbol 实例是唯一的,永远不会重复,可以作为

  • 使用 Symbol 来作为对象属性名(key)
  • 使用 Symbol 来替代常量
  • 使用 Symbol 定义类的私有属性/方法

使用方法

let x = Symbol(); //唯一值
let obj = {
  [x]: 10,
};
console.log(obj[x]); // 10

实际使用较少

BigInt 大数

当我们超出最大安全数字范围的时候,我们的计算就会不准确,这个时候就需要使用

  • BigInt([number])
  • XXXn

最大安全数 Number.MAX_SAFE_INTEGER
最小安全数 Number.MIN_SAFE_INTEGER

使用场景:在大型项目中,服务器返回给我们的数字中可能出现大数(服务器数据库中基于 longint 存储数,这个值可能会超过最大安全数)

检测数据类型有几种方式

  • typeof
  • instanceof
  • constructor
  • Object.prototype.toString

typeof 的使用

typeof 检测类型是有限的,只有(number boolean string undefined function symbol )

var a = "1";
typeof a; // string

var b = null;
typeof b; // object

typeof NaN; // number NaN 代表非数字 但是是number类型

为什么 typeof 检测 null(空指针) 是对象呢,

首先这是一个设计上的失误,因为 typeof 检测类型是对存储值的二进制进行检测,每一种类型都有固定标识,
1:整型(int)
000:引用类型(object)
010:双精度浮点型(double)
100:字符串(string)
110:布尔型(boolean)

恰好 null 二进制 前三位也是 000 所以 typeof 检测 null 就会是一个对象(object)

instanceof 的使用以及原理

instanceof 可以检测出引用类型 弥补了 typeof 的不足 但是 instanceof 也有缺陷
instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。

var str = "1";
str instanceof String; // false

var str = new String("11");
str instanceof String; // true
typeof str; // object
let person = function () {};
let no = new person();
no instanceof person; //true

因为我们可以随意修改原型的指向,所以 instanceof 检测是不准的

instanceof 是不能检测出基本类型的,但是经过 new 的基本类型是可以检测出来的,实际上 new 的过程把基本类型包装成了一个对象

当我们理解了 instanceof 实际上就是检测实例是否存在某个实例对象的原型链上,那么我们是不是可以模拟 instanceof 的实现呢

看一段代码

function newInstanceof(left, right) {
  left = left._proto_;
  var rightValue = right.prototype;
  while (true) {
    if (left === rightValue) {
      return true;
    }
    if (left === null) {
      return null;
    }
    left = left._proto_;
  }
}
// 主要是通过原型链和原型的知识进行判断,如果原型和原型链的知识不 熟悉,可以向下面查看,然后再回过头查看这端模拟的函数

constructor

constructor 主要是利用原型上的 prototype.constructor 指向实例的构造函数来进行判断的
先定义一个构造函数 Animal, 并 new 一个实例 dog

const Animal = function (name) {
  this.name = name;
}; // 声明一个构造函数
let dog = new Animal("dog"); // 生成实例dog

声明 Animal 函数的同时 js 会在 Animal 上挂载一个 prototype 对象,同时在 prototype 对象上会自动生成一个 constructor 属性并指向构造函数 Animal,相当于:
Animal.prototype.constructor === Animal // true ,根据原型链的查找原则,
console(dog.prototype) // Animal
所以利用构造函数原型上的 constructor 属性可以判断当前实例是否为当前构造函数的实例,进而确定数据所属类型:

console.log("1".constructor === String); // true
console.log(new Number(1).constructor === Number); // true
console.log(true.constructor === Boolean); // true
console.log(alert.constructor === Function); // true
console.log([].constructor === Array); // true
console.log(new Date().constructor === Date); // true

null, undefined 是无效的对象,因此是不会有 constructor 存在的,这两种类型的数据需要通过其他方式来判断。

constructor 检测也是不准的,因为我们可以随意的更改

var n = 1;
n.constructor === Number; // true
Number.prototype.constructor = "aa";
n.constructor === Number; // false

Object.prototype.toString

最标准的一种检测
可以返回当前实例的所属信息

// 定义判断类型函数
let getType = (target) => Object.prototype.toString.call(target);

console.log(getType("")); // [object String]
console.log(getType(2)); // [object Number]
console.log(getType(true)); // [object Boolean]
console.log(getType(undefined)); // [object Undefined]
console.log(getType(null)); // [object Null]
console.log(getType(Symbol())); // [object Symbol]
console.log(getType({})); // [object Object]
console.log(getType([])); // [object Array]
console.log(getType(alert)); // [object Function]
console.log(getType(new RegExp())); // [object RegExp]
console.log(getType(new Date())); // [object Date]

封装成一个函数

function toType(obj) {
  var class2Type = {};
  var toString = class2Type.toString; // => Object.prototype.toString() 他们两个是相等的
  // 设定数据映射表
  var data = [
    "Boolean",
    "Number",
    "String",
    "Function",
    "Array",
    "Date",
    "RegExp",
    "Object",
    "Error",
    "Symbol",
  ];
  data.forEach((name) => {
    class2Type[`[object ${name}]`] = name.toLowerCase();
  });
  if (obj == null) {
    return obj + "";
  }
  return typeof obj === "object" || typeof obj === "function"
    ? class2Type[toString.call(obj)] || "object"
    : typeof obj;
}

数据类型转化规则

数字

把其他类型转化成 Number 的规则

1.特定需要转化成 Number

  • Number()

  • parseInt/parseFloat

    2.隐式转化(浏览器内部默认转成 Number()计算)

  • isNaN() 会先转成数字再计算

  • 数学运算符(+ 在出现字符串的时候是拼接不是数学运算)

  • 在==比较的时候有些需要转化成数字比较

console.log("10px"); // NaN 只要出现非有效字符串 那么就是NaN
console.log(undefined); // NaN
console.log(null); // 0
console.log(Symbol(10)); // 报错
// parseInt 机制:从左侧第一个字符开始查找,查找有效数字字符(遇到非有效数字将停止查找,把找到的有效数字字符转化成数字,没有就是NaN,parseFloat只多识别一个小数点)
//

字符串

把其他类型转化成 String 的规则

  1. 能使用的方法

    • toString()
    • String()
  2. 隐式转化(一般都是调用 toString()转化)

  • 加号运算 如果一边是字符串,那么就是字符串拼接
  • 把对象转成数字,需要先用 toString()转成字符串再转成数字
  • 基于 alert/confirm/prompt 这些方式输出内容,都是先把内容转化成字符串,再输出

其他类型转化成字符串都很简单,只有{}普通对象是调取 toString(),而这个 toString 是调取 Object.prototype.toString(),这个不是用来转化成字符串,而是检测数据类型,返回结果"[Object Object]"

布尔值

1.基于一下方式可以把其他数据类型转化成布尔值

  • !转化成布尔值后取反

  • !!

  • Boolean()

    2.隐式转化

  • 在循环或者条件判断中,条件处理的结果就式布尔值

规则:只有 0 null NaN undefined 空字符串 会变成布尔值 false 其余全部式 true

==

在==比较的过程中,数据转换规则

类型一致

  • {} == {} false :对象比较的式堆内存地址
  • [] == [] false
  • NaN == NaN false

类型不一致

null=undefined 但是 === 就不相同因为类型不一致

字符串 == 对象 要把对象转成字符串

其余的 == 如果两边数据类型不一致,那么都要抓化成数字再比较

面试题

console.log([] == false); // true
// 对象 == 布尔  都是转化成数字(隐式转化)
// 对象转数字:先toString()转化成字符串,(应该是先基于valueOf获取原始值,没有原始值再去toString)然后再转成数字
// 执行过程:[] 没有valueOf没有基本类型的值,所以直接toString()
// [].toString() 等于 ''
// ""转成数字  Number('') // 0
// false 转成数字 是0 所以两者相等

console.log(![] == false); // true
// ![] 把数组转化成布尔值然后取反  false
// false == false
let res = 10 + false + undefined + [] + "Tencent" + null + true + {};
// 10+false = 10 false 会转化成0
// 10+undefined  NaN
// NaN + []  字符串"NaN"
// 后面都是字符串拼接了
// "NaNTencentnulltrue[Object Object]"
let arr = [10.18, 0, 10, 25, 23];
arr = arr.map(parseInt);
console.log(arr);

/*
arr = arr.map((item,index)=>{
  循环每一项都会触发回调函数
  每一次还会传递当前项和当前项的索引
})
parseInt 也是一个函数,所以接受当前项和当前索引

最后所有的都需要转化成十进制
parseInt('10.18',0)  第二位代表当前 value的进制 0就代表十进制
parseInt 只取到字符串有效的数字 所以 第一个是10 因为是十进制 所以 还是10
parseInt('0',1) // 没有1进制 进制只有2-36  因为没有1进制 所以为NaN
parseInt('10',2) // 2进制只有有数字 01 都是有效数字

10转化成 十进制

1*2^1+0*2^0  2 

parseInt('25',3)
三进制有效数字只有 0 1 2
所以只有2有效

2*3^0  2

parseInt('23',4)
四进制有效数字是0123
23都是有效数字

2*4^1+3*4^0  11

所以最终答案为 [10,NaN,2,2,11]

以上所有的 进制如果第一查找数字不符合进制有效数字,那么转化都为NaN
*/
parseInt(070)
// JS中遇到“以0开始的数字”,浏览器解析阶段 就会把其当做8进制,最后转换为十进制
//    0*8^0 + 7*8^1 + 0*8^2 =>56
// parseInt(56) -> parseInt('56',10) 

参考文献

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,258评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,335评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,225评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,126评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,140评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,098评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,018评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,857评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,298评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,518评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,400评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,993评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,638评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,661评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352

推荐阅读更多精彩内容