每个对象拥有一个原型对象
如何访问对象的原型对象:
function?Foo()?{}
let?foo?=?new?Foo();
const?log?=?console.log;
log(foo.__proto__);
log(Object.getPrototypeOf(foo));
log(Foo.prototype);
log(Foo.prototype?===?foo.__proto__);?//?true
log(Foo.prototype?===?Object.getPrototypeOf(foo));?//?true
log(foo.__proto__?===?Object.getPrototypeOf(foo));?//?true
普通函数的 prototype 上有两个属性:constructor 和 __proto__,前者指向构造函数自身,后者指向这个原型对象(Foo.prototype)的原型对象(也就是 Object.prototype)。
Object 的 prototype 中没有 __proto__,直接打印 Object.prototype.__proto__ 输出 null
doSomething.prototype.foo = "bar"; vs doSomething.foo = "bar";
这两种写法肯定不一样,前者 instance 可以访问到,后者 instance 无法访问(返回 undefined)。在原型链上的区别是:前者将 foo 作为 prototype 的一个属性,而后者将 foo 作为 constructor 的一个属性。
实例的 constructor 属性
每个实例对象都从原型中继承了一个constructor属性,该属性指向了用于构造此实例对象的构造函数。
原型的 constructor 属性
从 2 可以看到,每个构造函数的原型上有一个 constructor 属性,这个属性也有 prototype 和 __proto__ 属性。
另一方面,Person()函数是Person.prototype的构造函数
来自 <https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript/Objects/Inheritance>
其中,prototype 属性指向 Bar.prototype,也就是一个递归的过程。
而 __proto__ 属性指向 Function.prototype。
因此,下面的表达式输出 true:
通过 6 可以知道,Bar.prototype 的 constructor 就是指这个原型对象的构造函数,也就是 Bar() 函数。
所以,Bar.prototype.constructor.prototype 也就是 Bar()(Bar.prototype.constructor) 的原型了。
再所以,Bar.prototype.constructor.__proto__ 也就是 Bar()(Bar.prototype.constructor)这个函数本身(就是一个函数,和它的原型没有关系)的 __proto__(原型)自然是指向 Function.prototype,也就是 8 所解释的内容。
而 Bar.prototype 的 __proto__ 属性指向这个原型对象的原型对象,也就是 Object.prototype,这里的 __proto__ 其实已经和 Bar 没有关系了。
所有的函数都是 Function 构造函数的一个实例,所以函数也有 __proto__ 属性
不同变量的位置
位置 | 结果 |
---|---|
定义在构造函数内 | 出现在实例上 |
定义在构造函数名上 | 出现在原型的 constructor 属性上 |
定义在原型对象上 | 出现在原型上 |
function?Foo()?{
??this.width?=?200;
??this.height?=?300;
}
Foo.bar?=?‘haha‘;
Foo.prototype.width?=?400;
Foo.prototype.weight?=?500;
let?foo?=?new?Foo();
const?log?=?console.log;
log(foo);
log(foo.bar);?//?undefined
log(foo.width);?//?200
log(foo.height);?//?300
log(foo.weight);?//?500
原文:https://www.cnblogs.com/ainsliaea/p/13238203.html