js原型与原型链

js原型与原型链

在认识原型和原型链之前,先来看看几个基本知识:

ECMAScript 规定全局对象叫做 global,但是浏览器把 window 作为全局对象(浏览器先存在的),window 就是一个哈希表,有很多属性。window 的属性就是全局变量。

window中有一些是ECMAScript规定了的函数:Number、String、Boolean、Object。

用这些函数声明变量一般都有两种形式,以Number为例:

1)Number('1')
2)var n=new Number(1)

上述两种方法可以用Number()来构造一个对象,这里构造处理数值1对象,与普通数值是有不同的。

var n1=1;var n2=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__',这个属性存放的地址指向了对象的共用属性。于是就有了下面这个情况:

var o1={},o2={};
o1===o2 // false
o1.toString === o2.toString // true

对象有属于对象的共用属性,其他几个函数也有各自的共用属性,但要怎么将他们联系起来呢?那就要说到大家常说的一句话了,js中一切都可以看作是一个对象!

也就是说所有的类型都可以调用对象的共用属性,但中间会存在一层关系:

var n1=1;

n1.__proto__ ===Number的共用属性,Number的共用属性也是一个对象,所以它里面存在一个隐藏属性__proto__指向了对象的共用属性。这也是前面有说number类型的n1能调用toString的基本原理了。

而对于共用对象来说是独自存在于内存中的一块空间,并不归某个具体的对象或者变量所属,但是如果没有被引用的话是会被系统垃圾回收的,故而引申出了一个prototype属性,前面提到的:Number、String、Boolean、Object四个函数都具有这个默认属性,而这个属性指向正是指向他们的共用对象,保证共用对象不被垃圾回收。

看到这里会发现'__proto__'和'prototype'很像,都是指向共用属性,但其实他们的意义是不同的,区别在于'prototype'一直存在与window中(即使没有写任何代码),防止共用属性被回收,它是函数的属性;'__proto__'则是当声明了对象后才存在与对象中,并引用prototype所指向的共用属性,它是对象的属性,基本关系可以通过下图来理解:

它们之间存在一种引用关系,这种引用关系形成了一个链条,这就是我们标题所说的原型链,原型的话就是这些共用属性了

可以发现所有的原型链最终都指向了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'是函数的属性这句话也就懂了。

以上。

编辑于 2018-08-26