如何将方法添加到对象的原型中

时间:2017-10-27 20:30:48

标签: javascript

创建对象的方法有很多种。但是,我想知道为什么我使用这种方法出错(只是试图学习) - 错误信息中的'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());

2 个答案:

答案 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