一、ECMAScript标准
根据ECMAScript的标准,JavaScript(ES5)的类型定义如下:
-
5种基本的数据类型:String、Number、Boolean、null、undefined -
1种复杂的数据类型:Object
可以通过typeof操作符判断数据类型,typeof操作符可能会返回如下字符串:
-
undefined(
undefined) -
boolean(
Boolean的实例) -
number(
Number的实例) -
object(
Object/Array/RegExp/Date的实例,或者null) -
function(
Function的实例)
二、值类型和引用类型
-
值类型:实际上就是5种基本的数据类型:String、Number、Boolean、null、undefined
-
引用类型:Object(包含:Array、Function)
三、== 与 === 的区别
-
对于
String、Number等值类型,==和===是有区别的: -
不同类型之间比较,
==会先做隐式转化(转化成同一类型后的值)再比较,而===如果类型不同,其结果就是不等。 -
同类型比较时,直接进行值比较,
==和===的结果一样。
// 测试1:值类型
let str = '42';
let num1 = 42;
let num2 = 42;
console.log(str == num1); // true, 在比较时进行了隐式类型转换
console.log(str === num1); // false 说明首先比较了类型,类型不等,所以为 false
console.log(num1 === num2); // true 同类型比较,直接比较值
- 对于
Array、Object等引用类型,==和===是没有区别的,因为都是直接比较保存的内存指针地址。
// 测试2:引用类型
let o1 = {};
let o2 = o1;
let o3 = {};
console.log(o1 == o2); // true
console.log(o1 === o2); // true
console.log(o1 == o3); // false
console.log(o1 === o3); // false
-
基础类型与引用类型比较时,
==和===是有区别的。 -
对于
==,将引用类型转换为基本类型,进行**“值”**比较。 -
因为类型不同,
===结果为false。
// 测试3:引用类型和值类型比较
let array = [1, 2, 3];
let fn = function() {};
let object = {
name: 'Tom'
};
let string = '1,2,3';
let string2 = `function() {}`;
console.log(array == string); // true 比较时进行了类型转换
console.log(fn == string2); // true
console.log(object == '[object Object]'); // true
结论:==会在比较时强制类型转换,因此,当我们需要严格判断两个变量的类型和值时,请使用===。
- 根据上面一个例子,我们会注意到,在执行比较时,隐式的进行类型转换。那么隐式的具体是指什么呢?那就是:
object.toString()。所以,我们可以得出对象类型的判断终极武器:
// 测试4:通用的派生对象类型判断方法
Object.prototype.toString.call([]) // "[object Array]" 还可以直接用静态方法 Array.isArray 来进行判断
Object.prototype.toString.call({}) // "[object Object]"
Object.prototype.toString.call(new Date()) // "[object Date]"
Object.prototype.toString.call(new RegExp()) // "[object RegExp]"
Object.prototype.toString.call(new Map()) // "[object Map]"
Object.prototype.toString.call(new Promise(function() {})) // "[object Promise]"
Object.prototype.toString.call(Symbol()) // "[object Symbol]"
四、引用类型带来的问题
由于引用类型存储的是内存中的一个指针地址,所以当我们修改了某个值后,这个值的变化会直接导致另外一个值的变化,如果不明白其中的原理,会在平时开发中遇到一些困惑。
例子一:Object
// 测试5:对象的赋值
let obj1 = {
name: {
firstName: 'Tom',
lastName: 'Jerry',
},
age: 42,
};
let obj2 = obj1;
obj2.name.firstName = 'Foo';
console.log(obj1 === obj2); // true
// 2个对象引用的是同一个地址,赋值会同时受影响
console.log(obj1.name.firstName); // Foo
console.log(obj2.name.firstName); // Foo
例子二:Array
// 测试5:数组的赋值
let arr1 = [1, 2, 3, 4, 5];
let arr2 = arr1;
arr2[0] = 0;
console.log(arr1); // [0, 2, 3, 4, 5]
例子三:Function
// 测试6:函数的赋值
function Fn(name) {
this.name = name;
}
Fn.prototype.getName = function () {
return this.name;
};
let Fn2 = Fn;
Fn2.prototype.getName = function () {
return `${this.name} - new`;
};
console.log(Fn2 === Fn); // true
var foo = new Fn('Bar');
console.log(foo.getName()); // Bar - new