5

Let's say I have the following JSON with person objects.

[
  {
     "name": "Alice",
     "age": 28,
  },
  {
     "name": "Bob",
     "age": 33
  }
]

If I parse this, I will get an array with two JavaScript objects. Let's say, I want to equip these two objects with a method called introduce, that does something like this

function introduce() {
  return "My name is " + this.name + " and I am " + this.age + " years old.";
}

Now, I could iterate over my two people and call

person.constructor.prototype.introduce = introduce

However, this will expose the introduce function in ALL JavaScript objects, not just the two above.

I could also manually attach the function to each object, but if I want to extend my people with additional functions, I will have to iterate over all people again.

Ideally, I would like a prototype that I can fit with the introduce method and then attach this prototype to all my people, so if I later extend the prototype, my people will gain additional functions as well.

The question is: how?

5
  • 1
    just do person.prototype.introduce = introduce and get rid of the constructor part. Commented Apr 17, 2014 at 14:26
  • 1
    why dont just make a Person class, parse json to make Person. Anytime add any function to Person prototype. Commented Apr 17, 2014 at 14:27
  • @BrianGlaz: I think person is his reference to the object itself, so person.prototype won't exist. Commented Apr 17, 2014 at 14:28
  • mshsayem, I think it's a bit verbose and it seems inefficient to throw thousands of newly deserialized objects away just to create identical copies with a different prototype. It perplexes me that you cannot specify a prototype when parsing an array of objects. Commented Apr 17, 2014 at 14:49
  • @NielsB. You could easily write a wrapper around JSON.parse for this specific purpose, using Object.setPrototypeOf (check my answer). Commented Apr 17, 2014 at 14:50

7 Answers 7

3

I suggest you to create a class:

JSBin

var Person = (function () {
    function Person(person) {
        this.person = person;
        this.name = person.name;
        this.age = person.age;
    }
    Person.prototype.introduce = function () {
        return "My name is " + this.name + " and I am " + this.age + " years old.";
    };
    return Person;
})();
Sign up to request clarification or add additional context in comments.

2 Comments

Hey! Might be a silly question but what's the reason for wrapping this in an IIFE?
@Aegis Private variables and methods!
3

You're question is a little fuzzy to understand. But I think you don't want your "person" to be a regular object, but rather a separate person "class:"

var Person = function(obj){
    this.name = obj.name;
};

Person.prototype.introduce = function(){
  return console.log('hi, I\'m '+this.name);
};

var personA = new Person({ name:'a' });
var personB = new Person({ name:'b' });

personA.introduce();  // "hi, I'm a"
personB.introduce();  // "hi, I'm b"

3 Comments

So basically the conclusion is that it's not possible to gracefully assign prototypes to existing (literal) objects. Instead, new objects must be created using a constructor function.
@NielsB. Well, while it may be possible, you do not want to do that, since you only want introduce available to certain objects, in my example a Person instance.
Yes, I know. I don't want to replace the prototype for ALL objects, but it intuitively seems more efficient to iterate over an array and replace the prototype reference instead of creating a whole new set of objects.
3

Make a simple Person class:

function Person(name,age){
    this.name = name; 
    this.age = age
}

Say, you have this array:

var people = [
  {
     "name": "Alice",
     "age": 28,
  },
  {
     "name": "Bob",
     "age": 33
  }
];

Convert people to Person array:

people = people.map(function(p){
    return new Person(p.name,p.age)
});

Add the method to prototype:

Person.prototype.introduce = introduce

Comments

3

You could use the deprecated __proto__ property or the ES6 method Object.setPrototypeOf. Note that it is strongly discouraged to mutate the prototype of an object (c.f. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto) but it seems to be a legitimate usecase.

var you = { name: "Niels B." }
you.__proto__ = { hello: function () { console.log(this.name) } }
you.hello()

So for your specific problem:

function Person() {}
Person.prototype = {
  introduce: function () {
    return "My name is " + this.name + " and I am " + this.age + " years old.";
  }
}

Then for each person:

person.__proto__ = Person.prototype;
// or
Object.setPrototypeOf(person, Person.prototype);

Here's a relevant JSPerf: http://jsperf.com/parse-json-into-an-object-and-assign-a-prototype

Related thread: https://groups.google.com/forum/#!topic/ringojs/PxS1O5jMx-8

10 Comments

This adds the method to Object.prototype. The question states that he doesn't want to add the method to all objects.
@cookiemonster pretty sure it doesn't, it only mutates the prototype of the object.
@cookiemonster try it in a repl, the method is only added to this specific object.
@cookiemonster mmh you're right, sorry. When I tried it in the chrome console it didn't seem to affect other objects. My bad.
@rgthree thanks for pointing it out! (although people who use IE should die, imo).
|
2

Create a person class and use Person.prototype :

function Person(name, age){
    this.name = name;
    this.age= age;
}

function introduce() {
  return "My name is " + this.name + " and I am " + this.age + " years old.";
}

Person.prototype.introduce = introduce;

p1 = new Person ("bob", 33);
p1.introduce();

Comments

1

I would suggest creating a structure for these people.

var Person = function Person(init){
 this.name = init.name;
 this.age = init.age;
};
Person.constructor = Person;

And then iterating to build the people.

var people = [];
for(var i = 0; i < yourJson.length; i++){
 people.push(new Person(yourJson[i]));
}

Now that the people are built, perhaps you would like to allow them to be able to introduce themselves. You can simply extend your Person "class" (definition).

Person.prototype.introduce = function() {
  return "My name is " + this.name + " and I am " + age + " years old.";
}

which will allow them to use this function

for(var i = 0; i < people.length; i++){
 console.log(people[i].introduce());
}

Comments

1

If you don't want to re construct every time you could try this:

var people =[
  {
     "name": "Alice",
     "age": 28,
  },
  {
     "name": "Bob",
     "age": 33
  }
],
i=-1,len=people.length,tmp
,proto={
  sayName: function(){
    console.log("from sayname",this.data.name);
  }
};
while(++i<len){
  tmp=Object.create(proto);
  tmp.data=people[i];
  people[i]=tmp;
}
people[0].sayName();
proto.sayName=function(){console.log("changed it");};
people[1].sayName();

If your JSON objects have many members then this could save you from having to copy them in your constructor function but I'm not sure if you're getting more performance out of it.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.