5

I am trying to maximize the reuse of some code. On my custom javascript object (I'll use PhoneNumber as an example for the sake of simplicity), I am setting a prototype function like this:

var Map = {
    write: function() {
        alert('My object is ' +this);
    }
};

function PhoneNumber(number) {
    this.number = number;
}

PhoneNumber.prototype = Map;

//I can call the write function like so
var phoneObject = new PhoneNumber('1234567894');
phoneObject.write(); //ALERT My Object is Object{number:'1234567894'}

Everything works fine except for the fact that for some reason it turns my Phone Number object into a generic Object instead of keeping its PhoneNumber constructor. If I actually place the write function inside the objects prototype like this, it works perfectly.

function PhoneNumber(number) {
    this.number = number;
}

PhoneNumber.prototype.write = function() {
    alert('My object is ' +this);
}

var phoneObject = new PhoneNumber('1234567894');
phoneObject.write(); //ALERT My object is PhoneNumber{number:'1234567894'}

But I'd really rather not have to do it this way because multiple objects use the write function and they all perform the exact same way. How can I avoid my objects converting themselves into generic constructors? Apparently I'm setting the Map object on the prototype the wrong way, but its quite important that I not have to copy the code directly from Map into the object prototype function. Any ideas?

David Hoerster
  • 28,421
  • 8
  • 67
  • 102
ryandlf
  • 27,155
  • 37
  • 106
  • 162
  • This proves why the whole `new`/`.constructor`/`.prototype` thing is a big mess and a really leaky syntax sugar for the elegant prototype inheritance mechanism underneath, and `Object.create` is the true way to go. QED :) – Kos Jan 11 '12 at 15:08

4 Answers4

2

You forgot to set PhoneNumber.prototype.constructor

When you do PhoneNumber.prototype = Map you destroy the constructor property

PhoneNumber.prototype = Map;
PhoneNumber.prototype.constructor = PhoneNumber;

Of course that won't work because your just doing Map.constructor = PhoneNumber which breaks if you use Map as multiple prototypes. So you should just have PhoneNumber inherit from map

PhoneNumber.prototype = Object.create(Map, {
  constructor: { value: PhoneNumber }
});
Raynos
  • 166,823
  • 56
  • 351
  • 396
  • Is Object.create() a cross browser solution? I'm having a little trouble understanding how it works? – ryandlf Jan 11 '12 at 16:32
  • @ryandlf [Object.create](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/create) cross browser -> yes, legacy browser -> no. – Raynos Jan 11 '12 at 16:45
  • Why is it a better option to use your Object.create method as opposed to the way Umesh is doing it in another answer? I'm just curious and trying to fully understand the whole Object.create thing. It seems to me that Object.create is more or less used to replace the "new" keyword when creating new objects, not adding functions to an existing prototype. With your method, I will still be able to call phoneObj.write()? – ryandlf Jan 11 '12 at 16:54
  • @ryandlf `Object.create` does not invoke the constructor. `phoneObj.write()` still works – Raynos Jan 11 '12 at 17:07
  • Just got a chance to test. And this method is the only one that works. Thanks. – ryandlf Jan 12 '12 at 01:50
0

I get My object is [object Object] with both versions in Firefox.

You might want to take a look at this older post:

How do I get the name of an object's type in JavaScript?

Specficially, the part about the constructor and checking for object type using instanceof. Remember that there is no such thing as a class in JavaScript, so once you instantiate an object it really has no sense of 'type,' and things like instanceof are sort of hacks to get around this.

Community
  • 1
  • 1
Jonathan Rich
  • 1,740
  • 10
  • 11
  • Getting My Object is Object is what I do not want. It should be PhoneNumber (or whatever constructor I am using). I know how to get the constructor name, that is the problem is I can't get the actual constructor because for some reason it converts it to a generic object. – ryandlf Jan 11 '12 at 14:49
0
function PhoneNumber(number) {
    this.number = number;
}
var Map={
    write:function(){        
        console.log('My object is ' +this.number);
    }
}
PhoneNumber.prototype.write = Map.write;

var phoneObject = new PhoneNumber(1234567894);
phoneObject.write();

It works here. but here, By any way you need to tell the Map object that Object has number as its variable.

Umesh Patil
  • 10,475
  • 16
  • 52
  • 80
-1

It seems that the Object returned is PhoneNumber just without a toString method. Try this:

var Map = {
    write: function() {
        alert('My object is ' +this);
    }
};

function PhoneNumber(number) {
    this.number = number;
    this.toString = function(){return "PhoneNumber"}
}

PhoneNumber.prototype = Map;

//I can call the write function like so
var phoneObject = new PhoneNumber('1234567894');
phoneObject.write(); //ALERT My Object is Object{number:'1234567894'}
Shlomi Schwartz
  • 8,693
  • 29
  • 109
  • 186