Javascript 对象(一) 对象原型
-
每个对象拥有一个原型对象
如何访问对象的原型对象:
- prototype:构造函数的一个属性
- __proto__属性(已弃用):定义在对象实例上
- Object.getPrototypeOf()
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
参考: