经常在国内的各大网站博客上看到一句话,叫做JS中万物皆对象,那是否真是如此?
那么,我们先来捋一捋JS中的数据类型,JS中的数据类型有下面几种
Undefined
Null
Boolean
Number
String
Symbol (ES6中新增)
Object
所以本质上真的都是Object? -- NO
1.数据类型
在JS中我们把前面六种类型称为为基本数据类型,最后一种则是复杂数据类型,也就是对象类型。其实从这里看貌似已经区分了对象以及其他。
2.对象类型与其他类型的区别
对象可以动态的添加属性和方法,而基本类型不行。
如下:
// 基本类型 Number
var num1 = 1000;
num1.length = 10;
console.log(num1.length); //undefinded
// 对象类型 Array
var arr1 = [];
arr1.length = 10;
console.log(arr1.length); //10
3.值类型与引用类型
再进一步看,JS中的数据类型有值类型(基本类型)和引用类型(对象类型)之分(其实其他很多语言中也有这么个区别),所谓值类型和引用类型,无非只是实例对象中保存了值或者保存了对象的引用。
值类型:初始化一个值类型实例的时候,实际上是给这个值分配了一个内存空间来保存,当进行赋值操作的时候,新的实例会开辟一块新的内存空间,然后将原来的值
copy
到了这个新的内存空间中;引用类型:初始化一个引用类型实例的时候,仅仅是把这个实例的值所在内存空间的引用赋给这个实例,当
copy
给了新的实例对象使,实际上是copy
了对这块内存空间的引用,两个实例对象本质上共用一块内存空间。
举个?:
// 值类型 Number
var num1 = 1;
var num2 = num1;
num2 = num2 + 1
console.log(num1); // 1
// 引用类型 Array
var arr1 = [];
var arr2 = arr1;
arr2.push('oujm')
console.log(arr1); // ["oujm"]
目前的结论
其实从上面看,很明显的能得出JS中并非万物皆对象,可为什么还是有这么多的人认为并相信这个观点是正确的呢?(包括当初懵懂无知的我?)
为什么呢?
1. typeof null
console.log(typeof null); // object
很多人(可能不多,我瞎猜)都说,连null
都是对象类型,其他的能不是对象吗?讲道理我之前也很疑惑。直到在看书的时候看到null
只不过是一个空对象引用,这么说来,它的类型是object
也就没有那么奇怪了。
还有些人说这个是JS中的一个
bug
,不同的对象在底层都表示为二进制,在JavaScript
中二进制前三位都为 0 的话会被判 断为object
类型,null
的二进制表示是全 0,自然前三位也是 0,所以执行typeof
时会返回"object"
。是真也好,假也罢。但说这是个bug
其实没必要,我不知道底层是怎么实现,可仅仅是因为null
在底层全是0就返回object
,这种bug
未免显的太低级了点把... 我更愿意相信,JS的设计者就是想把null
表示为空对象引用
2. 基本数据类型的实例对象有 __proto__
如下所示:
var str = "oujm";
console.log(str.__proto__);
/* String {
anchor:ƒ anchor()
at: ƒ at()
big: ƒ big()
blink: ƒ blink()
bold: ƒ bold()
charAt: ƒ charAt()
charCodeAt: ƒ charCodeAt()
codePointAt: ƒ codePointAt()
concat: ƒ concat()
constructor: ƒ String()
...
} */
// Boolean Number 等基本类型打印出来的结论类似
从我们之前的学习中能知道str
是个基本类型,基本类型怎么会有属性呢。可是这里不但看到了这个基本类型的实例对象有属性__proto__
,而且很明显它的构造函数就是String()
,这个时候有些人就会觉得既然有属性,有构造函数,那说明str
本质上就是个对象。这在表面上看起来好像是没什么问题。
那让我们再来看一个更直白的?:
var str1 = "oujm";
var str2 = str1.substring(2);
从上面能看出来str1
是有方法的。
OK,宗上所得:基本类型也是对象类型,即万物皆对象
我觉得大部分人能得出这个结论都基于此。但是他们忽略了,在JS的世界中有一种对象类型叫包装对象。
包装对象(String,Number,Boolean)
咦?,String
,Number
,Boolean
,这三个不是基本类型吗。其实不然,ECMAScript提供了这三个特殊的引用类型,这三个引用类型和其他的引用类型相似,但同时也具有于各自的基本类型相应的特殊行为,实际上,每当读取一个基本类型的时候,后台就会创建一个对应的基本包装类型的对象。
再来看上面那个?,str1
很明显是一个基本类型实例,问题就出在 str1.substring(2)
字符串怎么会有方法。其实,为了让我们更好的操作基本类型的实例对象,后台进行了一系列的操作:
创建String的实例
在实例上调用指定的方法
销毁这个实例
// var str2 = str1.substring(2) 动作拆解:
var tempStr = new String("oujm");
var str2 = tempStr.substring(2);
tempStr = null;
从这里能够看到,一般的引用类型和包装类型唯一的区别就在于对象的生命周期。包装类型的对象生命周期很短,只有代码执行的一瞬间,然后就被销毁了,所以这也就是为什么我们不能在运行的时候为基本类型的值添加属性和方法。
var str1 = "oujm";
var str1.bf = "ethan";
console.log(str1.bf); // undefined
这也解答了我曾经的一个疑问
var str1 = "oujm";
var str2 = new String("ethan");
console.log(str1.__proto__ === str2.__proto__); // true
console.log(str1 instanceof String); // false
console.log(str2 instanceof String); // true
同样的道理,在调用__proto__
属性的瞬间,也是使用new String()
先来实例化一个对象,所以那一瞬间他们的构造函数以及原型对象是相同的,但也仅仅是那一瞬间。
综上
别再?到有些文章说的,JS的世界很大,并不只有对象
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。