看到别人问这个问题,自己输入了一下发现输出的是a,感觉和想象中的不一样于是分析了一下,顺便回顾一下关于原型链的知识点。
首先,我们很多人都知道一般情况下,一个对象如果本身没有这个属性,就会去它的原型链上去找。
1. prototype和__proto__
的区别
最开始太久没有看这方面的知识点就有点混淆了prototype和__proto__
。所以先把这两个概念区分开来。
[[Prototype]](也就是__proto__
):是一个特殊的内置属性,几乎所有对象在创建的时候就有了这个[[Prototype]],在有些浏览器下会通过__proto__
暴露出来(否则要通过Object.getPrototypeof()来获取)。
而这里说的对象,是不限于平时所说的Object类型,而是通过一个构造函数创建出来的都算,他们都有__proto__
。
像 String、Number、Boolean这些基本类型,同样也是通过构造函数创建出来的。
var a = 'string';
事实上就和var a = new String('string')
一样都是通过String函数创建出来的。number,boolean同理。包括array和function也一样。所以他们都有__proto__
。
prototype: 是函数才有的属性。它的值是一个对象,包含一个constructor属性。constructor指向这个函数本身。类似下面这样。
a.prototype = {
constructor: a
}
但是为什么打印出来还能看到一个__proto__
属性呢,是因为prototype本身是一个对象,对象都有__proto__
。
大概总结来说就是
__proto__
大家都有,prototype函数才有
2. __proto__
指向
除了用Object.create 创建的对象,其他对象的__proto__
指向这个对象的构造函数的prototype。
3. 回到题目
function Person() { }
这个函数的__proto__
是指向它的构造函数的prototype的,而函数的构造函数就是Function
,所以,如果我们输出Person.a,Person自身没有a这个属性就去__proto__
也就是Function.prototype上找:
console.log(Person.a) // a1
而对于ibtool,它的__proto__
指向它的构造函数Person
的prototype,而Person
的prototype上没有a这个属性,就往Person
的prototype,这个对象的__proto__
上找。因为上面说过prototype本身是一个对象,对象都有__proto__
,一个object的__proto__
指向它的构造函数(Object
)的prototype,所以
console.log(ibtool.a) // a
再假如去掉Function.prototype.a = 'a1'
这行,那Person.a
也会等于a,因为Function
的prototype也是个对象,这个对象的__proto__
也指向Object
的prototype。
注意:如果是通过Object.create的方式实现函数间的继承,那么就不一定了。
例如
function LivingThing () {}
LivingThing.prototype.a = 'a2'
function Person () {}
Person.prototype = Object.create(LivingThing.prototype)
// Object.create()方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__
// 也就是Person.prototype这个对象的__proto__指向的是LivingThing.prototype
var ibtool = new Person()
console.log(ibtool.a) // a2
补充:关于Object.prototype 和 Function.prototype
我的理解是:
Object.prototype
是一切对象的爸爸
Function.prototype
是一切函数的爸爸
下面有几个问题:
1.Function.prototype
指向哪?
输出出来是这样一段,应该是浏览器引擎创建的,最初始的,一切的源头。
Object.__proto__
指向哪?
Object也是个函数,它的构造函数是Function,Object.__proto__
就指向Function.prototype
,也就是第一问的内容。Function.__proto__
指向哪?
同理也Function是个函数,它的构造函数也是Function,Function.__proto__
就指向Function.prototype
,也就是第一问的内容。-
Object.prototype
是什么?
Object.prototype
也是一个对象, Object.prototype.__proto__
指向哪里?
一般来说一个对象的__proto__
指向它的构造函数的prototype,如果按照这个规则,Object.prototype.__proto__
应该指向对象的构造函数Object
的prototype,这样就形成了一个循环。
所以这里是一个例外,Object.prototype.__proto__
默认是指向null的。