79

For example, I already have this object somewhere in the code, it is a generic object:

var person1={lastName:"Freeman",firstName:"Gordon"};

I have the constructor for a Person object:

function Person(){
 this.getFullName=function(){
  return this.lastName + ' ' + this.firstName;
 }
}

Is there a simple syntax that allows us to convert person1 to an object of type Person?

1
  • 11
    There is no casting in JavaScript so ... short answer is no. Longer answer is ... still no. This is because the [[prototype]] can only be set when an object is created. However, one can monkey-patch on (copy over) methods/properties from Person to person1, which is an approach used by some "class frameworks" anyway. I would likely just create a new Person from person1 in a "copy-constructor". Commented Jan 5, 2012 at 2:28

7 Answers 7

71

Nowadays we can use Object.assign (credits to @SayanPal's solution) & ES6 syntax:

class Person {
  constructor(obj) {
    obj && Object.assign(this, obj);
  }
  
  getFullName() {
    return `${this.lastName} ${this.firstName}`;
  }
}

Usage:

const newPerson = new Person(person1)
newPerson.getFullName() // -> Freeman Gordon

Old answer

You can use the copy-constructor way like @user166390 said in the comments.

function Person(obj) {
    for (var prop in obj) {
        // for safety you can use the hasOwnProperty function
        this[prop] = obj[prop];
    }
}

Usage:

var newPerson = new Person(person1);
console.log(newPerson.getFullName()); // -> Freeman Gordon

Using a shorter version, 1.5 liner:

function Person() {
    if (arguments[0]) for (var prop in arguments[0]) this[prop] = arguments[0][prop];
}

jsfiddle

Sign up to request clarification or add additional context in comments.

4 Comments

Props for the "1.5 liner" version, love it.
But this answer is in effect just writing the extend function most frameworks have in there... And Object.assign is the replacement for that function... As of today. only Internet Explorer and Safari <= 9 don't support it. What I would do is grab an Object.assign polyfill and use it when the real Object.assign is not there. In my project I have a piece of code that checks the features needed and if any are missing, loads a second script with polyfills in it for these features.
@StijndeWitt I must agree on using Object.assign over this solution. See @SayanPal's solution which uses the assign method. I will update this answer sometime ;)
I don't like the question. JS doesn't use classes or casting, it uses functions to create objects -constructors-, it uses prototypes instead of classes. I like the Object.assign approach which is a function that copies the properties from one object to another. I'd like to say that sometimes you only need the @type, see JSDoc.
8

No.

But if you're looking to treat your person1 object as if it were a Person, you can call methods on Person's prototype on person1 with call:

Person.prototype.getFullNamePublic = function(){
    return this.lastName + ' ' + this.firstName;
}
Person.prototype.getFullNamePublic.call(person1);

Though this obviously won't work for privileged methods created inside of the Person constructor—like your getFullName method.

Comments

7

This is not exactly an answer, rather sharing my findings, and hopefully getting some critical argument for/against it, as specifically I am not aware how efficient it is.

I recently had a need to do this for my project. I did this using Object.assign, more precisely it is done something like this:Object.assign(new Person(...), anObjectLikePerson).

Here is link to my JSFiddle, and also the main part of the code:

function Person(firstName, lastName) {
  this.firstName = firstName;
  this.lastName = lastName;

  this.getFullName = function() {
    return this.lastName + ' ' + this.firstName;
  }
}

var persons = [{
  lastName: "Freeman",
  firstName: "Gordon"
}, {
  lastName: "Smith",
  firstName: "John"
}];

var stronglyTypedPersons = [];
for (var i = 0; i < persons.length; i++) {
  stronglyTypedPersons.push(Object.assign(new Person("", ""), persons[i]));
}

3 Comments

This syntax is very nice and efficient. Probably the way to go too. Too bad some browsers don't support it yet.
@A1rPun pollyfill can be used in those cases: kangax.github.io/compat-table/es6/…
This is the best answer. The differences between assign() and create() are 1) assign works with non-object properties; 2) assign ignores unknown properties.
2

This borrows from a few other answers here but I thought it might help someone. If you define the following function on your custom object, then you have a factory function that you can pass a generic object into and it will return for you an instance of the class.

CustomObject.create = function (obj) {
    var field = new CustomObject();
    for (var prop in obj) {
        if (field.hasOwnProperty(prop)) {
            field[prop] = obj[prop];
        }
    }

    return field;
}

Use like this

var typedObj = CustomObject.create(genericObj);

1 Comment

I used a custom class extended from a standard one. Now, when a global listener's callback completed it returns a standard classed object as a parameter. What was me doing is I tried all the answers matching my needs. I.e. TO EMBED that 'standard' object to one designed by me. . Finally this answer helped!
2

This is just a wrap up of Sayan Pal answer in a shorter form, ES5 style :

var Foo = function(){
    this.bar = undefined;
    this.buzz = undefined;
}

var foo = Object.assign(new Foo(),{
    bar: "whatever",
    buzz: "something else"
});

I like it because it is the closest to the very neat object initialisation in .Net:

var foo = new Foo()
{
    bar: "whatever",
    ...

Comments

2

This worked for me. It's simple for simple objects.

class Person {
  constructor(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
  }
  getFullName() {
    return this.lastName + " " + this.firstName;
  }

  static class(obj) {
    return new Person(obj.firstName, obj.lastName);
  }
}

var person1 = {
  lastName: "Freeman",
  firstName: "Gordon"
};

var gordon = Person.class(person1);
console.log(gordon.getFullName());

I was also searching for a simple solution, and this is what I came up with, based on all other answers and my research. Basically, class Person has another constructor, called 'class' which works with a generic object of the same 'format' as Person. I hope this might help somebody as well.

1 Comment

Be wise, avoid the reserved word class for the name of your conversion method! I'd suggest going for something like Person.fromObject(obj) instead.
0

Here have a way if you like. 1st make an object with your all desire properties. Then Call this object with your custom values. Here is link to the JSFiddle, and also the main part of the

 function Message(obj) {
  this.key = Date.now();
  this.text = "";
  this.type = "client";
  this.status = 0;
  this.senderID = "";
  this.name = "";
  this.photoURL = "";
  this.metaData = [];
  this.time = new Date().toISOString();
  
  for (var prop in obj) {
    if (this.hasOwnProperty(prop)) {
      this[prop] = obj[prop];
    }else{
        this.metaData = [ ...this.metaData, {[prop]: obj[prop]} ];
    }
  }
}

 const getAllMessages = function (messages=[]) {
  var newMessages = [];
  for (var i = 0; i < messages.length; i++) {
    newMessages.push(new Message(messages[i]));
  }
  return newMessages;
};

var messages = [{
  name: "Jhon",
  text: "Hello 1"
}, {
  name: "Smith",
  text: "Hello 2",
  meta1: "meta data 1"
}];

console.log("Single Instances", new Message(messages[0]));

console.log("Multiple Instances",getAllMessages(messages));

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.