JavaScript类型可以分为两类:原始类型和对象类型。原始类型包括数值、字符串、布尔值和两个特殊值null
和undefined
。除了上述值以外的值都是对象类型。对象是属性的集合,对象也有很多种,比如普通对象、数组、Set、Map、Date、function等等。
内存结构
程序运行时,计算机内存会为程序开辟出一块专用内存,用于存储数据。在JavaScript中,变量名和变量值都是数据,但是它们存储的位置是不同的,变量名存储在内存的一个空间中,变量值是存储在另一个空间中。
每一个值都有一个内存地址,变量名实际上保存的就是值的内存地址,这样就建立了名字和值的联系。
前面我们知道了值分为原始类型和对象类型,而内存分为栈内存与堆内存。
- 栈内存用于保存变量名,内存地址和原始类型。
- 堆内存用于保存对象类型。
内存中不会创建重复的原始类型,可以理解为原始类型是不可改变的。
ini
let a = 'HelloWorld';
let b = 'HelloWorld';
但是内存中可以创建重复的对象类型,并且它们的内存地址不同。
- 给不同变量赋值同样的原始类型,它们是相等的,它们保存的是同一个内存地址。
- 给不同变量赋值同样的对象类型,它们是不相等的,因为它们比较的是内存地址。
ini
let a = 1;
let b = 1;
console.log(a === b); // true
let arr1 = [1, 2, 3];
let arr2 = [1, 2, 3];
console.log(arr1 === arr2); // false
对象中的属性和值是可修改的。
- 变量arr1赋值给变量arr2,实际上是把arr1保存的数组[1, 2, 3, 4]的内存地址赋给arr2。它们俩指向同一个地址的数组,所以arr1修改对arr2是有影响的。
ini
var arr1 = [1, 2, 3, 4];
var arr2 = arr1;
arr1.push(5);
// arr1和arr2的地址是同一个
console.log(arr1 + '|' + arr2); // 1,2,3,4,5|1,2,3,4,5
- 重新赋值的过程是指向了新的内存地址。
ini
var arr1 = [1, 2, 3, 4];
var arr2 = arr1;
arr1 = [1, 2];
console.log(arr1 + '|' + arr2);
// 1,2|1,2,3,4,5
类型判断
typeof
typeof(data)
方法 返回一个字符串用于表示参数的数据类型,但是对于引用类型它只能区分是函数还是其它引用类型,比如以下代码中的对于数组的返回结果就是object
。
javascript
console.log(typeof(123)); // "number"
console.log(typeof("hello")); // "string"
console.log(typeof(true)); // "boolean"
console.log(typeof(undefined)); // "undefined"
console.log(typeof(null)); // "object"
console.log(typeof({})); // "object"
console.log(typeof([])); // "object"
console.log(typeof(function(){})); // "function"
console.log(typeof(null)); // "object"
console.log(typeof(NaN)); // "number"
console.log(typeof(document.all)); // "undefined"
注意null
是一个object
类型,它最早是空对象的指针,目前来说是一个历史遗留问题。
csharp
console.log(typeof(null)); //object
如果一个变量a未定义,使用typeof()
返回的是undefined
,注意这个undefined是字符串格式的。
csharp
console.log(typeof(a)); // undefined
console.log(typeof(typeof(a))); // string
constructor
constructor
指向创建该实例对象的构造函数。
ini
var arr = [];
console.log(arr.constructor); // ƒ Array() { [native code] }
instanceof
instanceOf()
方法 判断一个对象是否是右边的实例。
javascript
function Car(){}
var car = new Car();
console.log(car instanceof Car); // true
并且只要该对象能通过原型链访问到右边,都会返回true。
- 第一条语句打印true,因为
Car
构造函数是由Function
构造函数创建的实例。 - 第二条语句打印fasle,因为
car
对象和Function
之间并不存在原型链上的联系。 - 第三条语句打印true,因为
car
对象可以找到Car
构造函数的原型,然后接着找到Object
。
javascript
function Car(){}
var car = new Car();
console.log(Car instanceof Function); // true
console.log(car instanceof Function); // false
console.log(car instanceof Object); // true
Object.prototype.toString
toString()
方法 不接收参数,返回表示调用它的对象的值的字符串,注意的是它返回的字符串格式为[object 对象类型]
ini
var obj = {name: 'Li'};
console.log(obj.toString()); // [object Object]
所以虽然默认的toString()
方法不会显示太多信息,但是可以用于判断数据的类型,所以可以结合call
使用。
对于 Object.prototype.toString.call(arg)
,若参数arg
为 null
或 undefined
,直接返回结果。
javascript
console.log(Object.prototype.toString.call(undefined)) // "[object Udefined]"
console.log(Object.prototype.toString.call(null)) // "[object Null]"
对于其他数据类型,如果是原始数据类型,那么首先是进行包装类,如果是引用对象类型则直接使用。
javascript
console.log(Object.prototype.toString.call(123)) // "[object Number]"
console.log(Object.prototype.toString.call('HelloWorld')) // "[object String]"
console.log(Object.prototype.toString.call(true)) // "[object Boolean]"
console.log(Object.prototype.toString.call({name: 'Li'})) // "[object Object]"
console.log(Object.prototype.toString.call([1, 2, 3])) // "[object Array]"
console.log(Object.prototype.toString.call(function(){var a = 1;})) // "[object Function]"
- 在实际项目中会经常使用这个方式判断数据类型,使用时要注意变量缓存。
ini
var arr = [];
var str = Object.prototype.toString,
trueTip = '[object Array]';
if(str.call(arr) === trueTip){
console.log('是数组');
}else{
console.log('不是数组');
}
由于这个默认方法不会显示太多有用的信息,所以很多类都会重新定义
自己的toString()
方法。比如,在把数组转换为字符串时,会得到数组元素的一个列表,每个元素都会转换为字符串。而把函数转换为字符串时,可以得到函数的源代码。
- 原始类型重新定义的
toString()
方法,会返回当前值的字符串。 - 注意
undefined
和null
并没有自己的toString()
方法,直接调用会报错。
ini
var a = 'HelloWorld',
b = 123,
c = true,
d = undefined,
e = null,
f = [4, 5, 6],
g = function(){
var str = 'demo';
};
console.log(a.toString()); // 'HelloWorld'
console.log(b.toString()); // '123'
console.log(c.toString()); // 'true'
// console.log(d.toString()); // error
// console.log(e.toString()); // error
console.log(f.toString()); // '4, 5, 6'
console.log(g.toString()); // 'function(){ var str = 'demo'; }'