如下图所示
画的有点不太好看, 但是关系还是很清楚的
此处有一点需要注意: Foo.prototype
默认有一个公有并且不可枚举的属性.constructor
, 这个属性引用的是对象关联的函数. 例如上图的例子f1 = new Foo()
, 虽然f1.constructor
确实指向Foo函数, 但是这个属性并不是表示f1
由Foo
“构造”.
看起来f1.constructor === Foo
为真意味着f1
确实有一个指向Foo
的.constructor
属性, 但事实不是这样.
这是一个很不幸的误解. 实际上, .constructor
引用同样被委托给了Foo.prototype
, 而Foo.prototype.constructor
默认指向Foo.
把.constructor
属性指向Foo
看作是f1
对象由Foo
构造非常容易理解, 但这只不过是一种虚假的安全感. f1.constructor
只是通过默认的[[Prototype]]
委托指向Foo
, 这和构造毫无关系, 相反, 对于.constructor
的错误理解很容易对你自己产生误导.
举例来说, Foo.prototype
的.constructor
属性只是Foo
函数在声明时的默认属性. 如果你创建了一个新对象并替换了函数默认的.prototype
对象引用, 那么新对象并不会自动获得.constructor
属性.
那么我们怎么判断原型呢
1. ES3 isPrototypeOf()
isPrototypeOf()
方法用于测试一个对象是否存在于另一个对象的原型链上。
// 例子
function Foo() {}
function Bar() {}
function Baz() {}
Bar.prototype = Object.create(Foo.prototype);
Baz.prototype = Object.create(Bar.prototype);
var baz = new Baz();
console.log(Baz.prototype.isPrototypeOf(baz)); // true
console.log(Bar.prototype.isPrototypeOf(baz)); // true bar是baz的原型吗? 是就返回true
console.log(Foo.prototype.isPrototypeOf(baz)); // true
console.log(Object.prototype.isPrototypeOf(baz)); // true
2. ES5 Object.getPrototypeOf()
Object.getPrototypeOf()
方法返回指定对象的原型(内部[[Prototype]]
属性的值)
// 例
var proto = {};
var obj = Object.create(proto);
Object.getPrototypeOf(obj) === proto; // true
var reg = /a/;
Object.getPrototypeOf(reg) === RegExp.prototype; // true
// 这里再注意一下
Object.getPrototypeOf(Object) === Function.prototype; // true
3. ES6 __proto__
ES6规范更加直接,为对象添加了一个__proto__
属性,通过这个属性就可以获得对象的原型,所以在支持__proto__
的浏览器中,o.__proto__ === Object.prototype
也会返回true。