原型是JavaScript面向对象编程中非常重要的概念。今天就一次性battle明白~~~~走起~

开始之前先理解几个关键点

  • 所有的引用类型(数组,函数,对象)可以自由扩展属性(除了null以外)
  • 所有的引用类型都有一个__proto__属性(也叫隐式原型,是一个普通对象)
  • 所有的函数都有一个prototype属性(也叫显试原型,也是一个普通对象)
  • 所有的引用类型,__proto__属性都指向它的构造函数的prototype属性
  • 当试图得到一个对象的属性时,如果整个对象的本身不存在整个属性,那么它就会去找它的__proto__属性,也就是它的构造函数的prototype属性中找。

要点说完了,根据要点理解

先上一张图,如果你看明白这张图了,基本就能解释出__proto__和prototype的关系和区别了。看不懂的继续走起~

protobuf类型对应java类型 proto prototype_构造函数


先来一个铺垫再解释

构造函数

使用构造函数来创建一个对象

function Person(){
	
}
var person = new Person;
person.name = '张三'
console.log(person.name)   //张三

Person就是一个构造函数,通过new创建了person对象实例。
其实构造函数和普通函数没有多大区别,首字母大写只是约定俗成的的事情。关键是调用它的方式——通过new,那么这里又有了新的问题,使用new调用之后内部会执行哪些操作呢?

进入正题分割线------------------------------------------

prototype

//Person是一个构造函数
funtion Person(){
	this.age = 18;
	this.showName = function(){
		console.log	('I am' + this.name)
	}
}
Person.prototype.name = '张三';
var person1 = new Person()
var person2 = new Person()
console.log(person1.name)   //张三
console.log(person2.name)    //张三

从这段代码不难看出,每一个函数都有一个prototype属性,这个属性是一个指针,指向一个对象,只有函数才有。

如果我们要通过Person创建很多个对象,属性和方法都写在Person里面,那么我们通过实例对象创建的每一个对象里面都有showName方法,会占用很多资源。

prototype属性指向一个对象,那么这个对象是什么呢?

根据开篇第一张图可以清晰的看到,prototype指向Person.prototype。没错Person.prototype就是原型对象,也就是person1和person2的原型

所以构造函数和原型之间的关系为

protobuf类型对应java类型 proto prototype_prototype_02

__ proto__

从开篇第一张图我们会看见,person1和person2实例对象下面有一个[[prototype]],其实没有标准的访问方式可以访问到它,但是主流浏览器在每个对象上都支持一个属性,就是__proto__,这个属性会指向该对象原型

function Person(){

}
var person = new Person()
console.log(person.__proto__ === Person.prototype)   //true

so~~~我们得出总结:__proto__就是将对象与该对象的原型相连

在所有实现中都无法访问到[[prototype]],但是可以通过一些方法来确定对象之间是否存在这种关系

instanceof,这个操作符只能处理实例对象person和函数(带.prototype引用的Person)之间是否存在这种关系

person1 instaceof Person   //true

isPrototypeOf,如果[[prototype]]指向调用此方法的对象,那么这个方法就会返回true

Person.prototype.isPrototypeOf(person1) // true
Person.prototype.isPrototypeOf(person2) // true

constructor

这个属性其实就是将原型对象指向关联的构造函数

function Person(){
}
Person.prototype.constructor === Person  //true

再看下面的代码

function Person(){
}
var person = new Person()
person.constructor === Person   //true

又有了新的疑惑,这不是实例对象person也有constructor属性了吗?其实是:通过原项链在原型Person.prototype上面找到的。

protobuf类型对应java类型 proto prototype_引用类型_03


首先,fn的构造函数是Foo()。所以:

fn.__proto__=== Foo.prototype

又因为Foo.prototype是一个普通的对象,它的构造函数是Object,所以:

Foo.prototype._ _ proto _ _=== Object.prototype

通过上面的代码,我们知道这个toString()方法是在Object.prototype里面的,当调用这个对象的本身并不存在的方法时,它会一层一层地往上去找,一直到null为止。

到这里差不多就能理解__proto__和prototype的关系和区别了。

整点相关的题外话----------------------------------------

原型链

他俩的关系我们探索完了,研究研究原型和原型链都是什么东东?
其实原型链就是依托__proto__和prototype连接起来的