Prototype属于比较底层的知识,学习之前我要先说一句话.
构造函数.prototype 是个对象(有唯一例外,Function.prototype),
__proto__
指向创建他的构造函数的原型对象。
如果没理解这句话,就说明没有理解原型。
开门见图,很关键!!
下面很多知识点都是重复的,就当巩固了吧。
万物皆对象,每个对象都有一个属性叫 __proto__
,但是prototype
属性只有通过Function方式新建的对象才有,这种对象称为函数对象,他们会有一个prototype
属性。
function foo(){} 或者
let foo = new Function();
其他创建方式,比如
function foo(){} //前提
let a = new foo() 或者
let a = new Object(); 或者
let a = {}
都没有prototype
属性。那这两个属性是什么意思呢?
答:prototype
指向函数的原型对象,__proto__
指向创建它的构造函数的原型对象。看代码。
function foo(){}
foo.prototype 为 Object(即原型对象)[注:这里指的是,是个对象而不是foo.prototype === Object]
let foo1 = new foo(); //创建foo1的构造函数是foo
foo1.__proto__ => foo.prototype;
function foo(){} foo就是一个构造函数
let foo1 = new foo();
let a = {}//等同于 new Object()
foo1.constructor===foo //true
a.constructor===Object //true a为执行方法得到的结果,Object为方法本身
上述代码可知:实例的构造函数指向构造函数(有点像屁话)。
foo.prototype.constructor === foo
foo1.constructor === foo
foo1.__proto__===foo.prototype
foo1.prototype undefined 前面说了,只有通过Function方式新建的对象才有`prototype`
稍微总结一下:构造函数的原型对象是构造函数的一个实例,是一个对象。
问:foo.prototype.__proto__
是什么?
答:foo.prototype是一个foo的实例对象,所以他的构造函数是Object,
所以答案是Object.prototype
这里升华一下,让我们看看构造的起源在哪里?
JS中有两个根构造器,Object
、Function
.他们的__proto__
都是Function.prototype
,自定义一个构造器
function foo(){}
foo.__proto__
也是Function.prototype。因为Function是foo的构造函数。
最后
Function.prototype.__proto__ === Object.prototype
这里说一句,Function.prototype是一个对象,构造函数是Object,所以等式成立。
- 作用:
原型对象主要是用来实现继承的。
function cat(food){this.food = food}
cat.prototype.say = function(){
alert("I love eat"+this.food);
}
var test = new cat("fish");
test.say(); //I love eat fish
cat.say(); //undefined
test从原型链继承了say方法。而且从上面cat.say();//undefined 来看,原型是服务于继承的属性,本身是访问不到的。__proto__
的源头是Object.prototype
,内置函数都定义在其中。
Function.prototype
下面看代码。foo.__proto__ === Function.prototype
然后打印Function.prototype发现是一个空函数{这是唯一一个.prototype为函数的存在}
然后你再打印一个
Function.prototype.__proto__ 你会发现这个里面存在着需要的所有方法,这些都是继承下来的!!
所有的追根溯源都是通过__proto
来进行的,当读取变量或函数时,顺序如下
foo1.name
foo1.__proto__.name 即 foo.prototype.name
foo1.__proto__.__proto__.name =>Object.prototype.name
foo1.__proto__.__proto__.__proto__=>null 读到null为顶端
最后说一句话,当你探索的时候,过程是痛苦的,但是等到你探索成功之后,你会发现所有的困惑都会慢慢趋向清晰。