js的数据类型一共存在8种。
当然可以这样来进行简记 USONB 这样会不会记得更加牢固了呢?
Object包含了哪几种类型?
最常用的就是Array function Data
js的数据类型分为基本类型和引用类型
基本类型: String、Number、boolean、null、undefined
引用类型:Object 。里面包含function array data
null和undefined区别
typeof 是一个操作符,其右侧跟一个一元表达式,并返回这个表达式的数据类型。
返回的结果用该类型的字符串(全小写字母)形式表示
包括以下 7 种:number、boolean、symbol、string、object、undefined、function 等。
//1 typeof
console.log(typeof "");
console.log(typeof 1);
console.log(typeof true);
console.log(typeof null);
console.log(typeof undefined);
console.log(typeof []);
console.log(typeof function(){});
console.log(typeof {});
console.log(typeof Symbol()); //symbol
从上述结果中可以看到,typeof对于基本数据类型的判断是没有问题的,但是遇到了引用数据类型
是不起作用的,只能返回一个object。(typeof(null)输出object 是因为在js中,null表示一个空对象指针)
instanceof 是用来判断 A 是否为 B 的实例,表达式为:A instanceof B,如果 A 是 B 的实例,则返回 true,否则返回 false。
在这里需要特别注意的是:instanceof 检测的是原型,我们用一段伪代码来模拟其内部执行过程:
instanceof (A,B) = {
var L = A.__proto__;
var R = B.prototype;
if(L === R) {
// A的内部属性 __proto__ 指向 B 的原型对象
return true;
}
return false;
}
从上述过程可以看出,当 A 的 proto 指向 B 的 prototype 时,就认为 A 就是 B 的实例
我们来看几个例子
//instanceof
console.log([] instanceof Array) // true
console.log({} instanceof Object) // true
console.log(new Date() instanceof Date) //true
function Person(){};
console.log(new Person() instanceof Person) //true
console.log([] instanceof Object) //true
console.log(new Date() instanceof Object) //true
console.log(new Person instanceof Object) //true
console.log("1" instanceof String); //false
console.log(1 instanceof Number); //false
console.log(true instanceof Boolean); //false
由此可见对于基本数据类型是无效的!
其中值得注意的是:
console.log([] instanceof Array) // true
console.log([] instanceof Object) //true
那么为什么会这样呢?三者之间存在什么关系呢?
从原型链可以看出,[] 的 proto 直接指向Array.prototype,
间接指向 Object.prototype,所以按照 instanceof 的判断规则,[] 就是Object的实例。
依次类推,类似的 new Date()、new Person() 也会形成一条对应的原型链 。
因此,instanceof 只能用来判断两个对象是否属于实例关系, 而不能判断一个对象实例具体属于哪种类型。
当一个函数 F被定义时,JS引擎会为F添加 prototype 原型,然后再在 prototype上添加一个 constructor 属性,并让其指向 F 的引用。如下所示:
当执行 var f = new F() 时,F 被当成了构造函数,f 是F的实例对象,此时 F 原型上的 constructor 传递到了 f 上,因此 f.constructor == F
可以看出,F 利用原型对象上的 constructor 引用了自身,当 F 作为构造函数来创建对象时,原型上的 constructor 就被遗传到了新创建的对象上, 从原型链角度讲,构造函数 F 就是新对象的类型。这样做的意义是,让新对象在诞生以后,就具有可追溯的数据类型。
同样,JavaScript 中的内置对象在内部构建时也是这样做的:
- null 和 undefined 是无效的对象,因此是不会有 constructor 存在的,这两种类型的数据需要通过其他方式来判断。
- 函数的 constructor 是不稳定的,这个主要体现在自定义对象上,当开发者重写 prototype 后,原有的 constructor 引用会丢失,constructor 会默认为 Object
为什么变成了 Object?
因为 prototype 被重新赋值的是一个 { }, { } 是 new Object() 的字面量,因此 new Object() 会将 Object 原型上的 constructor 传递给 { },也就是 Object 本身。
因此,在重写对象原型时一般都需要重新给constructor赋值,以保证对象实例的类型不被篡改
toString() 是 Object 的原型方法,调用该方法,默认返回当前对象的 [[Class]] 。这是一个内部属性,其格式为 [object Xxx] ,其中 Xxx 就是对象的类型。
对于 Object 对象,直接调用 toString() 就能返回 [object Object] 。而对于其他对象,则需要通过 call / apply 来调用才能返回正确的类型信息。
<script type="text/javascript">
var a = Object.prototype.toString;
console.log(a.call("aaa"));
console.log(a.call(1));
console.log(a.call(true));
console.log(a.call(null));
console.log(a.call(undefined));
console.log(a.call([]));
console.log(a.call(function() {}));
console.log(a.call({}))
console.log({}.toString());
</script>
可以看到,所有的数据类型,这个办法都可以判断出来
那或许会有人会质疑,假如我改变一下它的原型呢?还能正确判断吗?
那我们测试一下
那这里就可以放心了吧,仍然可以得到正确的结果!