一、基本(原始)数据类型
JavaScript目前有6种基本数据类型:number、string、boolean、undefined、null、symbol(ES6新增)。
基本数据类型保存在栈内存中,因为基本数据类型占用空间小、大小固定,通过按值来访问,属于被频繁使用的数据。
二、引用(复杂)数据类型
常见的引用数据类型有:Object、Array、Function、Date、RegExp
引用数据类型存储在堆内存中,因为引用数据类型占据空间大、占用内存不固定。 如果存储在栈中,将会影响程序运行的性能;引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体
三、两种数据存储方式的不同
基本数据类型存在栈里,引用数据类型在栈里存地址,而在堆里存内容,如果定义数组m与数组n相等,表示地址相同,所以m与n的指针指向同一个内容,改变其中任意一个的内容,m与n都会改变。
四、栈内存和堆内存?
JavaScript的内存分为栈内存(stack)和堆内存(heap)
- 栈内存:是一种特殊的线性表,它具有后进先出的特性,存放基本类型。
- 堆内存:存放引用类型(在栈内存中存一个基本类型值保存对象在堆内存中的地址,用于引用这个对象)。
五、隐式转换
在JavaScript,当运算符在运算的时候,如果两边数据类型不统一,就无法直接计算,编译器会对运算符两边的数据做一个数据类型转换,转成相同的数据类型再计算。
1. +和-
巧用 + 和 - 规则转换类型:
- 把变量转换成数字: numStr - 0;
- 把变量转换成字符串: numStr + '';
2. a == b
类型相同,等同于 ===;
类型不同,尝试类型转换后比较:
null == undefined; // true
null === undefined; // false
// number == string; => string转number
1 == '1.0' // true
// boolean == ?; => 转number
1 == true // true
0 == fasle // true
'abc' == true // false => Number('abc') == NaN
// Obejct == number | string;尝试将对象转换为基本类型
new String('abc') == 'abc' // true
// 特殊的
NaN == NaN; // false
3. a===b
类型不同,返回false;
类型相同:
null === null; // true
undefined === undefined; // true
NaN === NaN; // false
new Object() ≠ new Object()
4. 布尔值为false的6种情况
undefined, null, false, 0, NaN, ""
六、包装对象
基本类型中的number,string,boolean都有对应的包装类型。
let str = 'abcde';
console.log(str.length); // 5
str.name = 233;
console.log(str.name); // undefined
把一个基本类型尝试用对象的方式使用它的时候,比如访问 length 属性,或者增加一些属性的操作时,JavaScript 会把这些基本类型转化为对应的包装类型对象。完成这样一个访问比如 str.length 返回以后或者 str.name 设置了以后,这个临时对象会被销毁掉。所以 str.name 赋值233以后,再去输出 str.name 的值是undefined。
七、类型检测
JavaScript 中检测类型的方法有很多:
- typeof
- instanceof
- Object.prototype.toString
- constructor
1. typeof
typeof 100; // "number"
typeof true; // "boolean"
typeof 'abc'; // "string"
typeof undefined; // "undefined"
typeof null; // "object"
typeof NaN; // "number"
typeof [1,2,3]; // "object"
typeof date; // "object"
typeof function; // "function"
比较特殊的是typeof null返回“object”。
历史原因,规范尝试修改typeof null返回“null”修改完大量网站无法访问,为了兼容,或者说历史原因返回"object"。
typeof对 基本类型 和 函数对象 很方便,但是其他类型就没办法了。
判断一个对象是不是数组?用typeof返回“object”。因此对对象的判断常用到的是instanceof。
2.instanceof
基于原型链操作。obj instanceof Object。
左操作数为对象,不是就返回false,右操作数必须是函数对象或者函数构造器,不是就返回typeError异常。
原理:判断左边的左操作数的对象的原型链上是否有右边这个构造函数的prototype属性。
任何一个构造函数都有一个prototype对象属性,这个对象属性将用作new出来的对象的原型(_proto_)。
3.Objetc.prototype.toString
Object.prototype.toString.call(null); // "[object Null]"
Object.prototype.toString.call(undefined);// "[object Undefined]"
Object.prototype.toString.call(“abc”); // "[object String]"
Object.prototype.toString.call(123); // "[object Number]"
Object.prototype.toString.call(true); // "[object Boolean]"
Object.prototype.toString.call([]); // "[object Array]"
Object.prototype.toString.call(function(){});// "[object Function]"
Object.prototype.toString.call(person); // 自定义类型 "[object Object]"
4.constructor
任何对象都有constructor属性,继承自原型的,constructor会指向构造这个对象的构造器或者构造函数。(constructor可以被改写,所以使用要小心。)
5.类型检测小结
- typeof:适用于检测基本类型及function,遇到null失效
- 对象:通过Object.prototype.toString检测,适合内置对象和基元类型
- instanceof:适合自定义对象,也可以用来检测原生对象