Javascript 原型链行为异常

Javascript prototype chain behaves unexpectedly

这是我的代码:

var Person = new Function() // same as function Person(){}
var john = new Person()

现在我有这样的原型链:Object -> Function -> Person -> john

现在我正在做类似的事情:

Function.prototype.bar = "boo"

所以我希望 Person.barjohn.bar 成为 "boo"

Person.bar  // boo
john.bar    // undefined

所以发生了什么事?我深入研究发现 john.__proto__ 是 Person 的原型,但 john.__proto__.__proto__ 不是 Function 的原型,它是 Object 的原型,所以我丢失了一条链(小说)。这就是 john.barundefined 的原因。那么为什么会这样呢?我不应该能够从 john 访问 Function 原型属性吗?

当你有

var Person = new Function()

你得到一个什么都不做的空函数,return什么也不做,例如

function Person() {
}

当您使用 new 创建 Person 的实例时,新创建的对象将查看 Person.prototype,并且由于 Person.prototype 继承自 Object(不是 Function), 你不会看到 .bar 属性.

function Person() {
}
const john = new Person();
console.log(
  Object.getPrototypeOf(john) === Person.prototype,
  Object.getPrototypeOf(Person.prototype) === Object.prototype
);

尝试创建一个函数的实例真的很奇怪,但如果你愿意,我想你可以通过 Person return a Function实例:

Function.prototype.bar = "boo"
function Person() {
  return new Function();
};

const john = new Person();
console.log(john.bar);

不过,我强烈建议不要尝试创建这样的 Function 实例。

如果你想要一个

的(奇数)继承链
Object -> Function -> Person -> john

那么你可以使用 Object.create:

//const Person = Object.create(Function);
// or
const Person = new Function();

const john = Object.create(Person);
Function.prototype.foo = 'foo';
console.log(john.foo);

考虑以下来自 this answer 的图片。

如您所见,当您在 JavaScript 中创建一个函数时,也会自动创建一个新的原型对象。

function Person() {}

因此,上面的代码实际上是:

function Person() {}
Person.prototype = { constructor: Person };

现在,你应该也明白函数的__proto__ 属性和它的prototype 属性.

是不一样的

function Person() {}

console.log(Person.__proto__ === Function.prototype); // true
console.log(Person.prototype !== Function.prototype); // true

当您使用 new 关键字创建 Person 的实例时,该实例对象继承自 Person.prototype 而不是 PersonPerson.__proto__

function Person() {}

const john = new Person;

console.log(john.__proto__ !== Person);           // true
console.log(john.__proto__ !== Person.__proto__); // true
console.log(john.__proto__ === Person.prototype); // true

通过调用 new Function.

创建的函数也是如此

const Person = new Function;

console.log(Person.__proto__ === Function.prototype); // true
console.log(Person.prototype !== Function.prototype); // true

这就是为什么 john 没有继承自 Function.prototype 的原因。 john的原型链如下

      __proto__                     __proto__                     __proto__
john -----------> Person.prototype -----------> Object.prototype -----------> null

Person的原型链如下:

        __proto__                       __proto__                     __proto__
Person -----------> Function.prototype -----------> Object.prototype -----------> null

证明如下:

const Person = new Function;
const john   = new Person;

console.log(john.__proto__                     === Person.prototype); // true
console.log(john.__proto__.__proto__           === Object.prototype); // true
console.log(john.__proto__.__proto__.__proto__ === null);             // true

console.log(Person.__proto__                     === Function.prototype); // true
console.log(Person.__proto__.__proto__           === Object.prototype);   // true
console.log(Person.__proto__.__proto__.__proto__ === null);               // true

这是因为Person.prototype !== Person.__proto__.


现在,您可能会问为什么我们同时拥有 prototype__proto__ 属性。这样做的原因是因为 JavaScript 中的一个对象(我们称之为 derived)继承自另一个对象(我们称之为 base)当且仅当 derived.__proto__ = base。考虑以下代码:

const base = { foo: 10 };

const derived = {};

derived.__proto__ = base; // derived now inherits from base

console.log(derived.foo); // 10

const newBase = { bar: 20 };

derived.__proto__ = newBase; // derived no longer inherits from base, it inherits from newBase

console.log(derived.foo); // undefined
console.log(derived.bar); // 20

现在,当您创建一个函数的实例时,该实例实际上是从函数的 prototype 继承的。它不继承自函数。

function Person() {}

const john = new Person;

以上代码等价于:

function Person() {}
Person.prototype = { constructor: Person };

const john = { __proto__: Person.prototype };
Person.call(john);

希望一切都过去了。