【问题标题】:Does a new object in Javascript have a prototype property?Javascript 中的新对象是否具有原型属性?
【发布时间】:2011-12-17 06:25:19
【问题描述】:

这是一个纯粹的学术价值微不足道的问题:

如果我创建一个新对象,可以这样做:

var o = { x:5, y:6 };

var o = Object.create({ x:5, y:6 });

当我查询o.prototype 属性时,我得到undefined。我认为任何新创建的对象都会自动继承Object.prototype 原型。

此外,在该对象上调用toString(),(Object.prototype 的方法)工作得很好,这意味着o 确实继承自Object.prototype。那我为什么会得到undefined

【问题讨论】:

  • 对象“o”的“原型”属性不是运行时系统找到其原型对象的方式。有内部属性可以跟踪它;这一切都非常令人困惑。这个问题被问了很多,如果我能找到一篇关于这个主题的好博客文章,我会链接它。
  • 您的对象是一个实例,而函数是具有可用prototype 属性的构造函数。如果要获取实例的原型,请使用Object.getPrototypeOf(o)
  • @Alex Nabokov:使用`,例如`test` 将产生test。 (从字面上理解,就是逃避它们。)
  • @pimvdb 所以我继续使用Object.getPrototypeOf(o) 方法:x = Object.getPrototypeOf(o); for (prop in x) { console.log(x); } ,我得到了一些非常奇怪的行为,我为每个属性返回object Object,而不是x 和y。奇怪的是做同样的事情,但做 console.log(x[prop]) 返回 5 和 6。

标签: javascript prototype-programming


【解决方案1】:

实例和它们的构造函数是有区别的。

在创建像{a: 1} 这样的对象时,您正在创建Object 构造函数的实例。 Object.prototype 确实可用,并且该原型内的所有功能都可用:

var o = {a: 1};
o.hasOwnProperty === Object.prototype.hasOwnProperty; // true

但是Object.create 做了一些不同的事情。它创建了一个实例(一个对象),但插入了一个额外的原型链:

var o = {a: 1};
var p = Object.create(o);

链将是:

Object.prototype  -  o  -  p

这意味着:

p.hasOwnProperty === Object.prototype.hasOwnProperty; // true
p.a === o.a; // true

要在实例“下”获取原型,您可以使用Object.getPrototypeOf

var o = {a: 1};
var p = Object.create(o);

Object.getPrototypeOf(p) === o; // true
Object.getPrototypeOf(o) === Object.prototype; // true

(以前,您可以使用 o.__proto__ 访问实例的原型,但现在已弃用。)

请注意,您还可以按如下方式访问原型:

o.constructor === Object; // true

所以:

o.constructor.prototype === Object.prototype // true
o.constructor.prototype === Object.getPrototypeOf(o); // true

这对于 Object.create-created 对象失败,因为它们没有构造函数(或者更确切地说,它们的构造函数是 Object,而不是您传递给 Object.create 的内容,因为构造函数不存在)。

【讨论】:

  • 感谢您的详细回答。我不太明白的一件事是为什么o.prototype(正如你上面所说的是 Object 构造函数的一个实例)返回undefined,而Object.getPrototypeOf(o) 返回原型。它们在理论上不是同一个东西,应该指向 o 的同一个原型对象吗?
  • @Alex Nabokov:不——构造函数有.prototype,实例有Object.getPrototypeOf。所以对象oObject.prototype(构造函数)和Object.getPrototypeOf(o)(实例)。这两个 do 指的是同一个东西。
  • 您说“在创建像 {a: 1} 这样的对象时,您正在创建 Object 构造函数的实例”。说“...您正在创建一个新实例使用 Object 构造函数”不是更正确吗?我不是要抨击你的回答,而是要理解这种该死的语言 Javascript。
【解决方案2】:

不是直接的答案,而是每个在 Javascript 中处理继承的人都应该具备的知识。

Javascript 中的原型继承是一个棘手的概念。到目前为止,创建一个空对象是不可能的(空我的意思是缺少通过原型形成的对象的属性)。所以这意味着创建一个新对象总是有一个指向原始对象原型的链接。但是,根据规范,对象实例的原型链是不可见的,但一些供应商决定实现自己的专有对象属性以便您可以遵循它,但强烈建议不要在生产代码中使用它。

以下示例代码仅演示了创建对象实例的两种方法。

var someObject = {};
var otherObject = new Object();
var thirdObject = Object.create({});

即使您不手动将对象属性添加到空花括号中,您仍然会自动添加原型链。第二个例子也是如此。为了更好地显示它,您可以在 Chrome 控制台中键入这些行,然后输入 someObjectotherObjectthirdObject 以查看详细信息。 Chrome 通过添加专有属性 __proto__ 来显示原型链,您可以扩展该属性以查看继承的内容和来源。如果你执行了类似

Object.prototype.sayHello = function() {
  alert('hello');
};

您可以通过执行otherObject.sayHello() 在所有实例上调用它。

但是,使用最近实现的东西(因此并非所有浏览器都支持),您实际上可以创建一个真正的空对象实例(甚至不从 Object 本身继承)。

var emptyObject = Object.create(null);

当你将它输入到 Chrome 控制台然后展开 emptyObject 以查看它的原型链时,你可以看到它不存在。所以即使你在Object原型上实现了sayHello函数,也不可能调用emptyObject.sayHello(),因为emptyObject不是继承自Object原型。

希望对总体思路有所帮助。

【讨论】:

  • +1 您以前可以这样做:var o = {}; o.__proto__ = null;,但无论如何它已被弃用。
  • @pimvdb 据我所知__proto__ 既不标准化也不被所有浏览器支持。
【解决方案3】:

JavaScript 有两种类型的对象:函数对象和非函数对象。从概念上讲,所有对象都有一个原型不是原型属性)。在内部,JavaScript 将对象的原型命名为 [[Prototype]]

获取任何对象(包括非函数对象)的[[prototype]]有两种方法:Object.getPrototypeOf()方法和__proto__强>属性。许多浏览器和 Node.js 都支持 __proto__ 属性。它将在 ECMAScript 6 中标准化。

只有函数(可调用)对象具有原型属性。此原型属性是常规属性,与函数自身的 [[prototype]] 没有直接关系。当用作构造函数时(在 new 运算符之后),函数的原型属性将分配给新创建的对象的 [[Prototype]]。在非函数对象中,原型属性是 undefined 。例如,

var objectOne = {x: 5}, objectTwo = Object.create({y: 6});

objectOne 和 objectTwo 都是非函数对象,因此它们没有 prototype 属性

【讨论】:

    猜你喜欢
    • 2020-06-21
    • 2013-09-26
    • 1970-01-01
    • 2013-04-09
    • 2015-07-21
    • 2014-05-08
    • 2023-03-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多