前言
什么是原型?
原型,汉语词语,读音为yuán xíng。指原来的类型或模型,特指文学艺术作品中塑造人物形象所依据的现实生活中的人。
狭义上将是原型人物。通常这样的解释,往往我们会觉得原型与产品之间,是在原型上破坏性的加工。
如果这样理解的话,那么将会对js的原型理解艰难,因为英文翻译过来是抽象的。
js的原型是扩展的意思,就像我们学数据结构的双向链表一样。
也就是说原型是扩展的对象的一个属性。
那么什么是原型链?
原型链指的是指向原型的这条连接,直到指向null为指,因为这个时候链接就断了。
好的概念理解完了,开始正文吧。下面理解,均为个人理解,如有不对望指出。
正文
上面写道扩展对象的一个属性指向了原型,那么这个属性是什么?
是__proto__。
proto 与 prototype
看一段代码:
var obj= new Object();
consoleProto(obj);
function consoleProto(obj){
if(obj!=null)
{
console.log(obj.__proto__);
consoleProto(obj.__proto__);
}
}
上文我通过递归的方式,把原型链打印了出来。
也就是说我创建一个对象,都会有一个属性__proto__指向另外一个对象。
现在我不关心null,我更关心的是红框中的对象到底是啥?
接来下我写了另一段代码:
var obj= new Object();
var obj2=new Object();
console.log(obj.__proto__===obj2.__proto__);
返回的结果为:true。
这个说明什么呢?说明任何一个对象的原型最终会基于一个公共原型对象。
也就是说new Object() 会把一个新的对象增加一个公共的对象引用。
那么new Object()是如何获取这个对象的呢?调用了什么函数可以获取到这个对象?或者说Object本身就带有这个公共属性?
我写下了另外一段代码:
<script>
var obj= new Object();
console.log(Object.prototype===obj.__proto__);
</script>
结果为true。
原来Obect本身就带有这个属性。
那么再往上推,Object是什么,Object是一个函数。
把Object 打印出来,然后提出疑问是否每个函数都具有prototype 属性?
function Object1(){
}
console.log(prototype);
console.log(Object1.prototype==Object.prototype);
打印出来是prototype 有值,后面的结果为false。
证明了每个函数,都具有prototype,但是Object比较特殊,其Object内置函数。
他们的关系如下:
console.log(Object1.prototype.__proto__==Object.prototype);
那么现在单独讨论Object1,Object1是一个函数但是同时也是一个对象,那么从对象的角度来看下,对象想到的是__proto__.
function Object1(){
}
console.log(Object1.__proto__==Function.prototype);
得出的结果为true。
如图:
那么上图中的原型对象是否就是原始对象。有两种方法可以证明一种就是没有原型,一种就是和原始对象做对比。
console.log(Object1.__proto__==Object.prototype);
我采用第二种,结果不是。同时说明Fuction 不是 Object的构造函数。
实际上是这样的:
console.log(Function.prototype==Function.prototype);
console.log(Function.prototype.__proto__==Object.prototype);
两者都为true。
上述结论图:
其中内置方法没有prototype,所以不是每个函数都有prototype。
再次__proto__ 与 prototype
上述提及的是内部的对象关系,那么我们书写的时候不用理会这么多了。
function Tree(){
}
var newtree=new Tree();
console.log(newtree.__proto__==Tree.prototype);
关系为:
constructor
既然构造函数能够知道原型,原型是否能够知道构造函数,也是可以的。
console.log(Tree==Tree.prototype.constructor);
两者相生相伴,一起出生。
为什么说原型链可以实现继承?
function Tree(){
}
Tree.prototype.name="白杨树";
var newtree=new Tree();
console.log(newtree.name);
这时候打印出来的是“白杨树“。也就是说如果newtree找不到,则会去根据原型链找原型,一直找下去,知道找到为止。
同样:
console.log(newtree.contructor==Person);
也就是因为newtree没有这个属性,只好找原型了。
最后一笔
console.log(Tree.prototype.__proto__.constructor);
修改一下:
总结
以上皆为个人理解,如有不对,望请指点。