常常在国内的各大网站博客上看到一句话,叫作JS中万物皆对象,那是否真是如此?javascript
那么,咱们先来捋一捋JS中的数据类型,JS中的数据类型有下面几种java
Undefined函数
Null学习
Boolean网站
Numberspa
String设计
Symbol (ES6中新增)3d
Objectcode
在JS中咱们把前面六种类型称为为基本数据类型,最后一种则是复杂数据类型,也就是对象类型。其实从这里看貌似已经区分了对象以及其余。对象
对象能够动态的添加属性和方法,而基本类型不行。
以下:
// 基本类型 Number var num1 = 1000; num1.length = 10; console.log(num1.length); //undefinded // 对象类型 Array var arr1 = []; arr1.length = 10; console.log(arr1.length); //10
再进一步看,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中并不是万物皆对象,可为何仍是有这么多的人认为并相信这个观点是正确的呢?(包括当初懵懂无知的我?)
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
表示为空对象引用
__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
,这三个不是基本类型吗。其实否则,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的世界很大,并不仅有对象