前言
原型和原型链是js中的重难点,你是否经常看见prototype
、__proto__
与constructor
这三个搞怪的家伙,并对此有很多疑惑,今天我们就来搞定他们.
说明:
__proto__
是两边各有两个下划线构成,实际上,该属性在ES标准定义中的名字应该是[[Prototype]]
,谷歌浏览器的实现就是将[[Prototype]]
命名为__proto__
,所以大家不用担心他们是没有功能差异的.
原型
我们先来看一个原型的例子.
//创建一个构造函数
function Foo(name,age){
this.name = name;
this.age = age;
}
//所有的函数都有一个'prototype'属性,这个属性也是一个对象
Foo.prototype={
showName:function(){
console.log(this.name);
},
showAge:function(){
console.log(this.age);
}
}
var fn = new Foo('小华',20);
//当你想得到一个对象的属性时,如果这个对象本身不存在这个属性,那么就会到他构造函数的'prototype'属性中查找.
fn.showName(); //小华
fn.showAge(); // 20
以上代码表示创建一个构造函数Foo()
,并用new
关键字实例化该构造函数得到一个实例化对象fn
.
虽然代码很简单,但在其背后的关系却很复杂.不着急,我们一个一个研究.
prototype 属性
定义
原型(prototype)是function对象的一个属性,它定义了[构造函数]构造出的对象的公共祖先。通过该构造函数产生的对象,可以继承该原型的属性和方法。
重点
- 首先我们必须知道,'prototype'属性是函数独有的!'prototype'属性是函数独有的!'prototype'属性是函数独有的!重要的事情说三遍.它是从一个函数指向一个对象。
- 当代码读取某个对象的某个属性的时候,都会执行一遍搜索,目标是具有给定名字的属性,搜索首先从对象实例开始,如果在实例中找到该属性则返回,如果没有则查找prototype,如果还是没有找到则继续递归prototype的prototype对象,直到找到为止,如果递归到object仍然没有则返回错误。(向上查找)
- 如果在实例中定义如prototype同名的属性或函数,则会覆盖prototype的属性或函数。
__proto__属性
定义
在官方的es5中,定义了一个名叫[[prototype]]的属性,每个对象都拥有这样一个属性,这个属性是一个指针,它指向一个名叫原型对象的内存堆。而原型对象也是对象,因此又含有自己的[[prototype]]的属性,又指向下一个原型对象。 那么终点是哪? 当然是我们的Object.prototype对象。
重点
- 上面我们得知'prototype'属性是函数独有的.,而__proto__属性是对象所独有的.(通过上面的代码段我们也知道,'prototypt'也是对象属性),所以它是由一个对象指向另一个对象.
- 从中我们可以引入原型链的解释:
当fn调用showName()和showAge()时,JS发现fn中没有这个方法,于是它就去Foo.prototype中去找,找到了,就调用此方法;如果没找到,就继续向上查找Object.prototype,如果还没找到就继续向上...这就是原型链,fn能够调用Foo.prototype中的方法正是因为存在原型链的机制。
'constructor'属性
定义(重点)
'constructor'(构造器),也是对象才拥有的,它是从一个对象指向一个函数,含义就是指向该对象的构造函数.所有函数(此时看成对象了)最终的构造函数都指向Function。
总结
- null和undefined没有原型.
- 如果在实例中定义如prototype同名的属性或函数,则会覆盖prototype的属性或函数。
- 所有普通对象都有内置的Object.prototype属性,指向原型链的顶端,如果在原型链中找不到指定的属性就会停止.
prototype
是函数所独有,__proto__
和constructor
是对象独有的.但是函数也是对象,所以函数拥有以上三个属性的特质.
引用
[js中的原型和原型链]((47条消息) JS中的原型和原型链(图解)_d_ph的博客-CSDN博客_js 原型链)