先亮题
function D() {}
D.prototype.proto = "D"
Function.prototype.func = "Function"
Object.prototype.obj = "Object"
var d = new D();
console.log(d.proto,d.func,d.obj); // D undefined Object
console.log(D.proto,D.func,D.obj); // undefined 'Function' 'Object'
console.log(Function.proto,Function.func,Function.obj); // undefined 'Function' 'Object'
先说为什么会是这个结果
console.log(d.__proto__ === D.prototype) // true
console.log(d.__proto__.__proto__ === Object.prototype) // true
console.log(D.__proto__ === Function.prototype) // true
console.log(D.__proto__.__proto__ === Object.prototype) // true
这四个等式就解释了d和D查找原型属性的过程,所以得到上面的打印
一、原型属性
1.原型与原型链
每个实例对象(object)都有一个私有属性(称之为__proto__ )指向它的构造函数的原型对象(prototype)。该原型对象也有一个自己的原型对象(即__proto__),层层向上直到一个对象的原型对象为 null。根据定义,null 没有原型,并作为这个原型链中的最后一个环节。
几乎所有 JavaScript 中的对象都是位于原型链顶端的 Object 的实例。
上面的话也可以理解为__proto__的作用主要用来指向创建这个对象的函数(构造器:constructor)的prototype,寻找__proto__的关系,直到找到Object的原型对象为null,这就是整个原型链
这段话里面有两个关键的词,__proto__和prototype,推荐大家读一下知乎上的这个问答。
可以解释为__proto__即(隐式原型)与prototype(显式原型)
__proto__的作用是作为一个指针指向自己构造函数的原型,而prototype的作用主要是用来实现基于原型的继承与属性的共享
2.怎么去查找原型
实例对象的原型__proto__会指向构造函数的原型对象prototype
console.log(d.__proto__ === D.prototype) // true
console.log(D.prototype.__proto__ === Object.prototype) // true
在这里可以清晰的看到从d到原型链顶点的查找过程,其中主要的疑问应该是存在于第二个等式,我们怎么找到D.prototype.__proto__的指向,首先要找到D.prototype是什么
console.log(D.prototype)
/* {proto: 'D', constructor: ƒ}
proto: "D"
constructor: ƒ D()
[[Prototype]]: Object
obj: "Object"
constructor: ƒ Object()
hasOwnProperty: ƒ hasOwnProperty()
isPrototypeOf: ƒ isPrototypeOf()
propertyIsEnumerable: ƒ propertyIsEnumerable()
toLocaleString: ƒ toLocaleString()
toString: ƒ toString()
valueOf: ƒ valueOf()
__defineGetter__: ƒ __defineGetter__()
__defineSetter__: ƒ __defineSetter__()
__lookupGetter__: ƒ __lookupGetter__()
__lookupSetter__: ƒ __lookupSetter__()
__proto__: Object
get __proto__: ƒ __proto__()
set __proto__: ƒ __proto__()
*/
D.prototype的原型打印结果是这样的,D.prototype的__proto__属性指向的是Object.prototype。
换一种推论方式也就是D继承自Function,那么依照继承的方式D.prototype = new Function()
,此时问题转换为找内建对象Functionde的实例的__proto__,对于内建对象的原型,几乎所有 JavaScript 中的对象都是位于原型链顶端的 Object 的实例。由此就得到了上面的等式。
二、NOTE
通过Function.prototype.bind方法构造出来的函数是个例外,它没有prototype属性
console.log(Function instanceof Object) // true
console.log(Object instanceof Function) // true
参看文章:一张图看懂Function和Object的关系及简述instanceof运算符
知识所限,有些地方还是说的不够明白,以后再补充吧!