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.bar
和 john.bar
成为 "boo"
Person.bar // boo
john.bar // undefined
所以发生了什么事?我深入研究发现 john.__proto__
是 Person 的原型,但 john.__proto__.__proto__
不是 Function
的原型,它是 Object
的原型,所以我丢失了一条链(小说)。这就是 john.bar
是 undefined
的原因。那么为什么会这样呢?我不应该能够从 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
而不是 Person
或 Person.__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);
希望一切都过去了。
这是我的代码:
var Person = new Function() // same as function Person(){}
var john = new Person()
现在我有这样的原型链:Object -> Function -> Person -> john
现在我正在做类似的事情:
Function.prototype.bar = "boo"
所以我希望 Person.bar
和 john.bar
成为 "boo"
Person.bar // boo
john.bar // undefined
所以发生了什么事?我深入研究发现 john.__proto__
是 Person 的原型,但 john.__proto__.__proto__
不是 Function
的原型,它是 Object
的原型,所以我丢失了一条链(小说)。这就是 john.bar
是 undefined
的原因。那么为什么会这样呢?我不应该能够从 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
而不是 Person
或 Person.__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);
希望一切都过去了。