一张图让你理清javascript中__proto__, prototype, 以及constructor之间的关系

如下图所示

画的有点不太好看, 但是关系还是很清楚的

这里写图片描述

此处有一点需要注意: Foo.prototype默认有一个公有并且不可枚举的属性.constructor, 这个属性引用的是对象关联的函数. 例如上图的例子f1 = new Foo(), 虽然f1.constructor确实指向Foo函数, 但是这个属性并不是表示f1Foo“构造”.

看起来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() 方法用于测试一个对象是否存在于另一个对象的原型链上。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 例子
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]]属性的值)

1
2
3
4
5
6
7
8
9
10
// 例
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。

越来越多的平台(微信公众平台,新浪微博,简书,百度打赏等)支持打赏功能,付费阅读时代越来越近,特此增加了打赏功能,支持微信打赏和支付宝打赏。坚持原创技术分享,您的支持将鼓励我继续创作!