2019.03.16 18:17 字数 1194 阅读 11评论 0喜欢 0
ECMAScript 规定全局对象叫做 global,但是浏览器把 window 作为全局对象(浏览器先存在的),window 就是一个哈希表,有很多属性。window 的属性就是全局变量。
window中有一些是ECMAScript规定了的函数:Number、String、Boolean、Object。
用这些函数声明变量一般都有两种形式,以Number为例:
1)Number('1')2)varn=newNumber(1)
上述两种方法可以用Number()来构造一个对象,这里构造处理数值1对象,与普通数值是有不同的。
varn1=1;varn2=Number('1');
n1和n2虽然数值都是1,但n2的类型属于'object',n1则为'number',身为基本类型number的n1直接指向了数字1,而n2指向了一个地址,这个地址中存放了数值1,这就是对象和基本类型的区别。
n2中有属性toString是对象默认存在的,但数值类型的n1也可以调用toString属性,那是因为调用n1.toString时,系统生成了一个临时对象,而这个对象中就有toString这个属性供n1调用,不够调用后系统立马删除了这个临时对象。所以会有以下一个情况:
n1.xxx=1;console.log(n1);//undefined
因此引申出了一个共用对象的概念,大致是因为所有对象都有toString()和valueOf()属性,如果每个对象中都存放太占内存,所以专门用了一块空间来放置这些共用属性,当对象需要使用时可以直接调用。在声明对象时,会默认产生一个隐藏属性'proto',这个属性存放的地址指向了对象的共用属性。于是就有了下面这个情况:
varo1={},o2={}; o1===o2// falseo1.toString === o2.toString// true
对象有属于对象的共用属性,其他几个函数也有各自的共用属性,但要怎么将他们联系起来呢?那就要说到大家常说的一句话了,js中一切都可以看作是一个对象!
也就是说所有的类型都可以调用对象的共用属性,但中间会存在一层关系:
varn1=1;
n1.proto===Number的共用属性,Number的共用属性也是一个对象,所以它里面存在一个隐藏属性__proto*__指向了对象的共用属性。这也是前面有说number类型的n1能调用toString的基本原理了。
而对于共用对象来说是独自存在于内存中的一块空间,并不归某个具体的对象或者变量所属,但是如果没有被引用的话是会被系统垃圾回收的,故而引申出了一个prototype属性,前面提到的:Number、String、Boolean、Object四个函数都具有这个默认属性,而这个属性指向正是指向他们的共用对象,保证共用对象不被垃圾回收。
看到这里会发现'proto'和'prototype'很像,都是指向共用属性,但其实他们的意义是不同的,区别在于'prototype'一直存在与window中(即使没有写任何代码),防止共用属性被回收,它是函数的属性;'proto'则是当声明了对象后才存在与对象中,并引用prototype所指向的共用属性,它是对象的属性,基本关系可以通过下图来理解:
image.png
它们之间存在一种引用关系,这种引用关系形成了一个链条,这就是我们标题所说的原型链,原型的话就是这些共用属性了。
可以发现所有的原型链最终都指向了Object的共用对象,而Object的共用对象本身也是一个对象,它也有隐藏的'proto'属性,但与其他'proto'属性不一样,这个指向的是null。
升级一下:
var 对象 = new 函数对象 这个声明形式可以引申出:
对象.proto ===构造函数.prototype(本身也是个对象),下面是次关系衍生出的关系:
函数.proto ===Function.prototype
Function.proto === Function.prototype
Object.proto === Function.prototype //Objec也是个函数,函数都是由Function构造出来的。
Number.proto === Function.prototype
构造函数.prototype.proto ===Object.prototype
Function.prototype.proto ===Object.prototype
Number.prototype.proto ===Object.prototype
Object.proto .proto ===null
理解了以上的关系后,'proto'是对象的属性、'prototype'是函数的属性这句话也就懂了。
以上。