本文固定连接:js中原型链理解_玖相逢的博客-CSDN博客
假设有这么一段代码:
function
fn
(){
this
.
prop
=
{};
}
var
o
=
new
fn()
;
console
.
log(
o
.
__proto__
===
fn
.
prototype)
;
//true
console
.
log(
fn
.
prototype
.
__proto__
===
Object
.
prototype)
;
//true
console
.
log(
Object
.
prototype
.
__proto__)
;
//null
从输出的结果可以看出来,整条原型链为:
1、o.__proto__ ---> fn.prototype,
2、fn.prototype.__proto__ ---> Object.prototype
3、Object.prototype.__proto__ ---null 原型链结束
![](https://i-blog.csdnimg.cn/blog_migrate/d12c6b44be851ada118cb700298f33a9.png)
如果存在继承关系,则子类的原型对象的__proto__属性(son.prototype.__proto__)会指向父类的原型对象(father.prototype),father.prototype.__proto__ 再继续指向父类的父类的原型对象,以此类推,最后指向Object.prototype
例如:
//es5中才有的Object.create,这里先这样兼容一下吧(可以参考最下方的参考链接查看兼容的浏览器)
if (
typeof
Object
.
create
!==
"
function
")
{
Object
.
create
=
function
(
proto
,
propertiesObject
)
{
if (
typeof
proto
!==
'
object
'
&&
typeof
proto
!==
'
function
')
{
throw
new
TypeError(
'
Object prototype may only be an Object:
'
+
proto)
;
}
else
if (
proto
===
null)
{
throw
new
Error(
"
This browser's implementation of Object.create is a shim and doesn't support 'null' as the first argument.
")
;
}
if (
typeof
propertiesObject
!=
'
undefined
')
throw
new
Error(
"
This browser's implementation of Object.create is a shim and doesn't support a second argument.
")
;
function
F
()
{}
F
.
prototype
=
proto
;
return
new
F()
;
};
}
function
grandpa
(
name
){
this
.
name
=
name
;
}
grandpa
.
prototype
=
{
getName
:
function
(){
console
.
log(
'
my name is
'
+
this
.
name)
;
}
}
function
father
(
name
){
grandpa
.
call(
this
,
name)
;
}
father
.
prototype
=
Object
.
create(
grandpa
.
prototype)
;
father
.
prototype
.
constructor
=
father
;
function
son
(
name
){
father
.
call(
this
,
name)
;
//这样写目的是让son的实例也拥有父类函数内部的属性与方法(非prototype);
};
son
.
prototype
=
Object
.
create(
father
.
prototype)
;
son
.
prototype
.
constructor
=
son
;
//这样的是将实例的construction指向son 即 实例.constructor 的值为 ‘function son(name){father.call(this,name);}’
var
sonModel
=
new
son(
'
son
')
;
console
.
log(
sonModel
.
name)
;
//son
sonModel
.
getName()
;
//my name is son
这段代码的意思是:son继承自father,father继承自grandpa(当然js可以实现多继承,但是针对多继承的情况,原型链在我认为来说是错误的,因为他只链了第一个继承的原型对象(用jquery的写法的话,也有可能连到其他父对象,但是只能链一个))
![](https://i-blog.csdnimg.cn/blog_migrate/6dae3e8e8facdb89f8dfa5b029ed16eb.jpeg)
原型链在属性搜索中的作用:
寻找一个属性会遍历整条原型链
Object
.
prototype
.
d
=
4
;
function
fn
(){
this
.
a
=
1
;
}
fn
.
prototype
.
b
=
2
;
fn
.
prototype
.
c
=
3
;
function
fn2
(){
fn
.
call(
this)
;
this
.
c
=
'
fn2中的c
'
;
}
fn2
.
prototype
=
Object
.
create(
fn
.
prototype)
;
var
fn2Model
=
new
fn2()
;
console
.
log(
fn2Model
.
c)
;
//fn2中的c
console
.
log(
fn2Model
.
d)
;
//4
上面这段代码,fn2Model对象本身只有a c两个属性(直接被注册到this上了),同时,在fn.prototype中b c两个属性被继承,但最后fn2Model.c的值为‘fn2中的c’,fn2Model.d的值为4,可以得出结论
属性的搜索机制:先搜索实例对象本身具有的属性(如果写法中在子类内部不写 父类.call(this) ,那么可以理解为是方法内部的属性),找到则返回,找不到则会找原型,一次顺着原型链依次向上查找,直到原型链结束。
包括枚举一个实例对象时候,也会通过原型链查找到原型链结束 即Object.prototype.__proto__
Object
.
prototype
.
d
=
4
;
function
fn
(){
this
.
a
=
1
;
this
.
b
=
2
;
}
fn
.
prototype
.
c
=
3
;
fn
.
prototype
.
getName
=
function
(){
console
.
log(
this
.
a
+
this
.
b
+
this
.
c
+
this
.
d)
;
};
var
o
=
new
fn()
;
for(
var
item
in
o)
{
console
.
log(
item)
;
//打印结果 a b c getName d
}
o
.
getName()
;
//10
从输出的结果来看,枚举的属性还包括了d,而fn函数本身是没有这个属性的,且fn.prototype.__proto__最终是指向Object.prototype,所以最终枚举的属性包含了d。
本文固定连接:js中原型链理解_玖相逢的博客-CSDN博客
参考链接:
继承与原型链 - JavaScript | MDN
Object.create() - JavaScript | MDN