1. 基本数据类型和复杂数据类型
- 基本类型:
undefined
,null
,bool
,string
,number
,symbol
(ES6新增)。
虽然 typeof null
返回的值是 object
,但是null
不是对象,而是基本数据类型的一种。这是一个历史遗留问题,JS 的最初版本中使用的是 32 位系统,为了性能考虑使用低位存储变量的类型信息,000
开头代表是对象,null
表示为全零,所以将它错误的判断为 object
。
基本数据类型存储在栈内存,存储的是值。
- 复杂数据类型:
Object
,Array
,Date
,function
复杂数据类型的值存储在堆内存,地址(指向堆中的值)存储在栈内存。当我们把对象赋值给另外一个变量的时候,复制的是地址,指向同一块内存空间,当其中一个对象改变时,另一个对象也会变化。
[1] == [1] // false
{name:1} == {name:1} // false
因为引用类型值比较的是地址,这两个对象字面量指向不同的引用地址,所以为false。
2. 判断方法
typeof
typeof
能够正确的判断基本数据类型,但是除了 null
,typeof null
输出的是对象。但是对象来说,typeof
不能正确的判断其类型, typeof
一个函数可以输出 ‘function
’,而除此之外,输出的全是 object
,这种情况下,我们无法准确的知道对象的类型。
instanceof
instanceof
可以准确的判断复杂数据类型,但是不能正确判断基本数据类型。
instanceof
是通过原型链判断的,A instanceof B
, 在A
的原型链中层层查找,是否有原型等于B.prototype
,如果一直找到A
的原型链的顶端(null
;即Object.__proto__
),仍然不等于B.prototype
,那么返回false
,否则返回true
。
instanceof
的一个实现:
//L instance_of R
function instance_of(L, R) {
var O = R.prototype; //取R的显式原型
L = L.__proto__; //取L的隐式原型
while(true) {
if(L===null) { //已经找到顶层
return false;
} else if(O===L) { //当O严格等于L时,返回true
return true;
}
L = L.__proto__; //继续向上一层原型链查找
}
}
console.log(instance_of([], Array)) //true
Object.prototype.toString.call(obj) === ‘[Object ’ + type + ‘]’
用该方法检测出的null
是Null
类型:
var a = Symbol();
var b = 23;
console.log(Object.prototype.toString.call(a)); // [object Symbol]
console.log(Object.prototype.toString.call(null)); // [object Null]
console.log(Object.prototype.toString.call(undefined)); // [object Undefined]
console.log(Object.prototype.toString.call(b)); // [object Number]
如果想要了解Object.prototype.toString.call()
的原理,可参考链接https://www.cnblogs.com/ziyunfei/archive/2012/11/05/2754156.html
3. 基本数据类型和复杂数据类型的区别为:
- 内存的分配不同
基本数据类型存储在栈中;
复杂数据类型存储在堆中,栈中存储的变量,是指向堆中的引用地址。 - 访问机制不同
基本数据类型是按值访问;
复杂数据类型按引用访问,JS不允许直接访问保存在堆内存中的对象,在访问一个对象时,首先得到的是这个对象在栈内存中的地址,然后再按照这个地址去获得这个对象中的值。 - 复制变量时不同(
a=b
)
基本数据类型:a=b;
是将b
中保存的原始值的副本赋值给新变量a
,a
和b
完全独立,互不影响;
复杂数据类型:a=b;
将b
保存的对象内存的引用地址赋值给了新变量a
;a
和b
指向了同一个堆内存地址,其中一个值发生了改变,另一个也会改变。
let b = {
age: 10
}
let a = b;
a.age = 20;
console.log(b); //{ age: 20 }
- 参数传递的不同(实参/形参)
函数传参都是按值传递(栈中的存储的内容):基本数据类型,拷贝的是值;复杂数据类型,拷贝的是引用地址,具体细节参考链接:
https://juejin.im/post/5a5cb80151882573385fb84d#comment