创建对象的方法有很多种。但是,我想知道为什么我使用这种方法出错(只是试图学习) - 错误信息中的'undefined'是什么意思? 问题与首次实例化对象无关,因为我尝试了var Obj = {};并获得相同的结果。 THX。
'use strict';
var Obj=Object.create(null);
var descriptor={
value: 37, writable: true, enumerable: true, configurable: true};
Object.defineProperty(Obj, 'p0' , descriptor);
// Next line causes an error: Cannot set property 'f' of undefined
Obj.prototype.f = function() { //define a method f() on Obj PROTOTYPE
return (`hello ${this.p0}`);
};
console.log(Obj.f());
答案 0 :(得分:3)
所以,基本上,我认为这归结为对prototype
的基本误解。对象的各个实例没有.prototype
,而是有一个内部链接指向从中创建对象实例的构造函数的原型。这之前被称为.__proto__
(AKA dunder-proto),但此后一直被正式弃用。
最近,为了引用对象实例的构造函数的原型,您可以访问名为.constructor
的属性。 (* 注意* :.constructor
可能未定义,具体取决于对象的创建方式)。从这里,您可以访问.prototype
。
同样,您可以使用Object.getPrototypeOf(obj)
和Object.setPrototypeOf(obj)
,其中obj
是对象的实例。
例如:
var x = Object.create(null);
console.log("x.prototype", x.prototype);
var y = Object.create({a: "foo"});
console.log("y.prototype:", y.prototype);
.prototype
在两种情况下都是未定义的,因为对象实例没有原型属性,只有对象构造函数。
话虽这么说,我们可以使用.constructor.prototype
属性访问创建对象实例的原型,如下所示:
function myObj (){
this.a = "foo";
}
// myObj is a constructor function, which has a prototype that we can set properties on
myObj.prototype.b = "bar";
// obj is an instance of an object, which does not have a prototype property
var obj = new myObj();
console.log("obj.prototype:", obj.prototype);
console.log("Object.getPrototypeOf(obj):", Object.getPrototypeOf(obj));
console.log("obj.constructor.prototype:", obj.constructor.prototype);
答案 1 :(得分:2)
OP的有趣示例值得仔细检查,以便最好地掌握产生的错误以及如何改进代码。
将null传递给Object.create()会产生一个未定义的对象,从而导致错误发生。更正涉及传递原型对象,例如Object。结果:Obj拥有一个有效且定义的对象,其中包含Object原型的所有方法。
变量描述符包含一个有效的对象,其原型偶然可以descriptor.constructor.prototype
访问。有关构造函数here的更多信息。
向Obj添加属性的语句是正确的,但用途有限。它直接向Obj添加属性而不是其原型。出于这个原因,将方法 f 添加到原型是很尴尬的,因为它只能访问特定对象 Obj 的属性 p0 ,因为不属于 Obj 原型的属性。最后的陈述表明当下面的代码执行时,方法f()对于 Obj 正常工作:
'use strict';
// creates undefined object
var Obj=Object.create(null);
console.log("Obj is " + Obj.constructor);
// instantiate Obj of type Object
Obj = Object.create( Object );
console.log("Obj is now instance of Object? " + (Obj instanceof Object));
var descriptor={
value: 37, writable: true, enumerable: true, configurable: true};
// directly add property to object Obj
Object.defineProperty(Obj, 'p0', descriptor);
// adding new method to Obj prototype
Obj.prototype.f = function() {
return ("hello " + Obj.p0);
};
console.log(Obj.f());
OP可能希望修改代码如下:
'use strict';
var descriptor =
{
value: 37,
writable: true,
enumerable: true,
configurable: true
};
/* instantiate Obj of type Object
* like this:
* var Obj = Object.create( Object );
* Or:
*/
var Obj = Object.constructor;
// make p0 a property of the Obj prototype
Obj.prototype.p0 = descriptor;
// add method to Obj prototype
Obj.prototype.f = function() {
return ("hello " + this.p0.value);
};
console.log( Obj.f() );
第二个例子的优点是从Obj原型实例化的所有对象都将具有f方法和p0属性。
注意:在'use strict'语句中,应该注意并非所有浏览器都支持它;见here。