JavaScript 是一门基于原型继承的语言,它使用原型链来实现继承。每个 JavaScript 对象都有一个 [[Prototype]] 内部属性,指向其原型对象。在访问对象属性时,如果该对象不存在该属性,则会沿着原型链向上查找,直到找到该属性或者到达原型链的顶端。
但是,在创建新的对象时,很多开发者会发现新对象的 prototype
属性是 undefined
,而不是指向其构造函数的 prototype
属性。这似乎与整个原型继承机制相矛盾,引起了人们的困惑和疑问。
为什么会出现这种情况?
这个问题的根源在于 JavaScript 中的构造函数。在 JavaScript 中,构造函数也是一种函数,可以通过 new
运算符来创建新的对象实例。当我们创建一个新的对象时,实际上是通过调用构造函数来创建的,并且新对象的 [[Prototype]]
属性指向构造函数的 prototype
属性。
例如:
function Person(name) { this.name = name; } const person1 = new Person('Alice'); console.log(person1.__proto__ === Person.prototype); // true
在这个例子中,我们创建了一个名为 Person
的构造函数,并通过 new
运算符创建了一个名为 person1
的新对象实例。由于 Person.prototype
是一个对象,因此新对象的 [[Prototype]]
属性指向 Person.prototype
。
然而,如果我们尝试直接访问构造函数的 prototype
属性,会发现它并不是对象类型,而是一个空对象:
console.log(Person.prototype); // {}
这是因为在 JavaScript 中,每个函数都有一个 prototype
属性,但只有当该函数被作为构造函数使用时,才会将其 prototype
属性赋值给新对象的 [[Prototype]]
属性。
因此,新对象的 prototype
属性是 undefined
,是因为它没有被赋值为构造函数的 prototype
属性。
如何解决这个问题?
虽然新对象的 prototype
属性是 undefined
,但它仍然可以通过原型链访问到构造函数的 prototype
属性中定义的方法和属性。因此,在大多数情况下,这个问题并不会对实际开发造成太大的影响。
但是,如果你需要在新对象上动态添加新的方法或属性,并希望它们能够在原型链中被访问到,那么你可以使用 Object.create()
来创建一个新的对象,并将其原型设置为构造函数的 prototype
属性。
例如:
function Person(name) { this.name = name; } const person2 = Object.create(Person.prototype); person2.name = 'Bob'; console.log(person2.__proto__ === Person.prototype); // true
在这个例子中,我们使用 Object.create()
方法创建了一个新对象 person2
,它的原型被设置为 Person.prototype
。然后,我们可以将 name
属性设置为 'Bob'
。由于新对象的原型指向 Person.prototype
,因此我们可以访问到 Person.prototype
中定义的属性和方法。
总结
JavaScript 中新对象的 prototype
属性是 undefined
,是因为它没有被赋值为构造函数的 prototype
属性。虽然这个问题可能会引起困惑,但在大多数情况下不会对实际开发造成太大影响。如果你需要在新对象上动态添加新的方法或属性,并希望它们能够在原型链中被访问到
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/25589