1.每一个构造函数都有一个prototype属性,默认指向一个空Object对象(原型对象)
function fun(){
}
console.log(fun.prototype ) //{constructor: ƒ}3.可以向原型对象添加一些方法
function fun(){}
fun.prototype.test = function(){console.log('test')}4.每一个原型对象中有一个属性constructor,它指向构造函数
function fun (){
}
console.log(fun.prototype.constructor === fun) //true5.构造函数与它的原型对象有一个相互引用的关系

6.原型对象上添加的方法用于实例对象上使用
每一个实例对象都有一个__proto__属性,称之为隐式原型 对象的隐式原型的值为其对应构造函数的显示原型的值
function Fn(){}
var fn = new Fn()
console.log(Fn.prototype === fn.__proto__) // truefunction Fn(){}
console.log(Fn.prototype)
var fn = new Fn()
console.log(fn.__proto__)
console.log(Fn.prototype === fn.__proto__)
Fn.prototype.test = function(){
console.log('test')
}
fn.test()对象属性的查找规则 原型链本质上是从隐式原型链
function Fn(){
this.test1 = function(){
console.log('调用了test1()')
}
}
Fn.prototype.test2 = function (){
console.log('调用了test2()')
}
var fn = new Fn()
//
fn.test1() // 调用了test1()
fn.test2() //调用了test2()
console.log(fn.toString()) //[object Object]
fn.test3() //Uncaught TypeError: fn.test3 is not a function代码简易的内存结构如下

当执行 fn.test1()时先对象自身查找发现有,直接调用test1()
当执行fn.test2()时,自身对象上没有test2,接下来看构造函数的原型对象上是否有test2,发现有直接调用test2
当执行fn.toString(),时,自身对象没有,接下来查找它构造函数的原型对象上是否有toString(),发现没有,接下来又继续沿着Fn原型对象的构造函数的原型对象上查找找到toString()
当执行fn.test3()时,查找自身对象没有,它直接的构造函数对象的原型对象上也没有,接下来沿着Fn原型对象的构造函数的原型对象的构造函数的原型对象上查找,这里已经找到原型链的尽头,Object原型对象的proto指向null,
因此fn.test3()抛出异常
