js基础类型和引用类型
开始第一篇,那我们从 js 最基础的讲起,基础类型和引用类型
1、什么是基础类型(值类型、原始类型)
保存在栈中的类型就是基础类型,原因是基础类型存储的空间很小,存放在栈中方便查找,且不易于改变
js 中的基础类型(值类型、原始类型)有哪些
1 | Undefined、Null、Boolean、Number、String、Symbol(ES6中新加类型) |
2、什么是引用类型
指有多个值构成的对象,引用数据类型是存储在堆中,也就是说存储的变量处的值是一个指针,指向存储对象的内存地址。存在堆中的原因是:引用值的大小会改变,所以不能放在栈中,否则会降低变量查询的速度
js 中的引用类型有哪些
1 | Object; |
3、如何判断类型
3.1 typeof
具体使用:
1 | console.log(typeof a); //'undefined' |
实现原理如下:
1 | 不同的对象在底层都表示为二进制, 在 JavaScript 中二进制前三位都为 0 的话会被判断为 object 类型, null 的二进制表示是全 0, 自然前三位也是 0, 所以执行 typeof 时会返回“object”。 |
所以 typeof null 的返回值是 object,这是个“历史遗留问题”。
因为 typeof 判断引用类型时不太准确,所以我们选用其他方法。
3.2 instanceof
通常来说,instanceof 是判断一个实例是否属于某种类型
具体使用:
1 | console.log(1 instanceof Number); //false |
从以上结果可以看出,instanceof 对引用类型来说判断的非常准确,但是对于基础类型却不能精准的判断。原因是 instanceof 运算符用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性。其意思就是判断对象是否是某一数据类型的实例,1、‘1’、true 并不是实例,所以为 false。
如下所示:
1 | console.log(new Number(1) instanceof Number); //true |
但是对 undefined 和 null,却比较特殊
1 | console.log(new null() instanceof Null); //Uncaught TypeError: null is not a constructor |
原因是因为 undefined 和 null 并不是构造函数
3.3 constructor
具体使用:
1 | console.log((1).constructor === Number); //true |
看着貌似很准确的样子,但是还是有缺陷,当创建一个对象改变他的原型的时候,就不再准确了!
1 | function Foo() {} |
这是因为 js 每个函数都有一个 prototype 属性,指向原型对象,对象.prototype.constructor 指向的是该对象的构造函数,当把该对象的原型对象更改时,该函数的构造对象也会更改,所以就会出现如上的问题
3.4 Object.prototype.toString.call()
具体使用:
1 | console.log(Object.prototype.toString.call(1)); //[object Number] |
这是最准确的类型判定的方法,就算改变原型也不会有问题。
具体分析一下这个方法背后的故事:
每个 Object 原型上都有一个 toString 的方法,当调用这个方法的时候会执行三个步骤:
1、获取对象的类名(对象类型)
2、将[object、获取的对象类型]组合为字符串
3、返回字符串
为什么要用 call 方法?
因为 Array、String 等类型都对其继承下来原型上的 toSring 方法进行了重写,无法返回我们想要的结果,所以我们通过 call 方法,将 Object.prototype.toString 上的 Object 的指向改变,才能对类型进行精准的判断。
Object.toString 和 Object.prototype.toString 的区别?
Object.toString 是 Object 构造器的方法,返回的是函数
1 | Object.toString({}); //"function Object() { [native code] }" |
Object.prototype.toString 是 Object 原型上的方法,返回的是类型字符串,才是我们想要的结果
1 | Object.prototype.toString({}); //"[object Object]" |