JavaScript原型链的行为异常

时间:2019-07-12 12:17:17

标签: javascript prototype prototypal-inheritance

这是我的代码:

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的原因。那么为什么会这样呢?我不能从Function访问john原型属性吗?

2 个答案:

答案 0 :(得分:3)

有空的时候

var Person = new Function()

您会得到一个不执行任何操作且不返回任何内容的空函数,例如

function Person() {
}

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

.bar

尝试创建一个函数实例真的很奇怪,但是如果您愿意,我想您可以通过让function Person() { } const john = new Person(); console.log( Object.getPrototypeOf(john) === Person.prototype, Object.getPrototypeOf(Person.prototype) === Object.prototype );返回一个Person实例来获得所需的内容:< / p>

Function

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

如果您想要一个(奇数)继承链

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

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

然后您可以使用Object -> Function -> Person -> john

Object.create

答案 1 :(得分:1)

请考虑以下从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

使用Person关键字创建new的实例时,该实例对象继承自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);

希望能清除一切。