一,函数的prototype属性
每个函数都有一个prototype属性,它默认指向它的原型对象
而原型对象中,又有一个属性constructor,它指向原本函数对象。也就是说函数和它的原型对象之间相互引用。
<script type="text/javascript">
console.log(Date.prototype) //Object
console.log(Date.prototype.constructor===Date) //true
</script>
二,显示原型和隐式原型的理解
1,每个函数function都有一个prototype,即显式原型(属性)
2,每个实例对象都有一个–proto–,可称为隐式原型(属性)
三,原型链的理解
原型链:
访问一个对象的属性时,先在自身属性中查找,找到即返回。
如果没有,再沿着–proto–这条链向上查找,找到返回
如果最后没有找到,返回undefined
因为是沿着–proto–这条链查找的,所以原型链实际上是隐式原型链!!
存在的作用是查找对象的属性和方法
<script type="text/javascript">
function Fn(){ //构造函数
this.test1=function(){
console.log("test1()")
}
}
console.log(Fn.prototype)
Fn.prototype.test2=function(){
console.log("test2()")
} //将方法定义在原型对象上
var fn=new Fn()
fn.test1() //直接在fn中找到了
fn.test2() //fn中没找到,就去原型对象中找,找到了就调用
console.log(fn.toString()) //存放再在Object的原型对象中的方法
// fn.test3() //undefined
</script>
四,函数的原型链
- 函数有prototype属性,函数的实例对象有–proto–属性。
- 函数(我们自己定义的函数和内置函数Function,Number,ArrayBoolean,String)的显示原型都指向各自默认的空Object实例对象(Object例外)。在这里面,有两个特殊的点,一个是Object的原型对象中的–proto–值为null,是原型链的尽头。另一点是Function可以看作Function自身的实例,所以它的显示原型和隐式原型都指向Function.prototype。
- 任何对象都是Object的instance,因为原型链的顶端都指向Object.prototype。
- Object也是个函数,而任何函数都是Function的实例对象,比如Array,String,Number,Boolean,当然Object和Function自身也包括在内,它们都是Function的实例,也就是说,他们都同时存在prototype和–proto–属性。且prototype指向各自的原型对象,而–proto–都指向Function的原型对象。也就是Function.prototype。
- 一个构造函数创建的实例的–proto–都指向这个函数的显示原型。
<script type="text/javascript">
function Fn(){ //构造函数
this.test1=function(){
console.log("test1()")
}
}
console.log(Function.prototype===Fn.__proto__) //true
console.log(Function.prototype===Function.__proto__) //true
console.log(Function.prototype===Object.__proto__) //true
console.log(Function.prototype===Number.__proto__) //true
console.log(Function.prototype===Array.__proto__) //true
console.log(Function.prototype===String.__proto__) //true
console.log(Function.prototype===Boolean.__proto__) //true
console.log(Function.prototype===Fn.prototype) //false
var fn=new Fn()
console.log("--------")
console.log(fn.__proto__ ===Fn.prototype) //true
</script>
到这里就可以知道,原型链为啥又称为隐式原型链了!
如果把属性/方法事先定义在Function内部,因为Fn(直接)和fn(间接)都是通过它创建的实例,其内定义的属性/方法会继承下来,fn们可以访问到。但若是定义在Function.protype内,因为不在fn们的原型链上,就访问不到了!!
五,原型链的属性问题
- 读取对象的属性值时,会自动到原型链中查找
- 设置对象的属性值时,并不会查找原型链,如果当前对象中没有此属性,则直接添加此属性并设置其值。
3.于是我们一般把方法设置在原型中,然后把属性通过构造函数定义在对象本身上。
<script type="text/javascript">
function Fn(){ //构造函数
}
var fn1=new Fn()
var fn2=new Fn()
Fn.prototype.a="设置a属性在原型对象上"
console.log(fn1.a,fn1) //从原型链中查找
fn2.a="设置属性,只设置在当前对象上,不会查找原型链"
console.log(fn2.a,fn2)
</script>