JSON.stringify ignore some object members - javascript

Heres a simple example.
function Person() {
this.name = "Ted";
this.age = 5;
}
persons[0] = new Person();
persons[1] = new Person();
JSON.stringify(persons);
If I have an array of Person objects, and I want to stringify them. How can I return JSON with only the name variable.
The reason for this is, I have large objects with recursive references that are causing problems. And I want to remove the recursive variables and others from the stringify process.
Thanks for any help!

the easiest answer would be to specify the properties to stringify
JSON.stringify( persons, ["name"] )
another option would be to add a toJSON method to your objects
function Person(){
this.name = "Ted";
this.age = 5;
}
Person.prototype.toJSON = function(){ return this.name };
more: http://www.json.org/js.html

If you're only supporting ECMAScript 5 compatible environments, you could make the properties that should be excluded non-enumerable by setting them using Object.defineProperty()[docs] or Object.defineProperties()[docs].
function Person() {
this.name = "Ted";
Object.defineProperty( this, 'age', {
value:5,
writable:true,
configurable:true,
enumerable:false // this is the default value, so it could be excluded
});
}
var persons = [];
persons[0] = new Person();
persons[1] = new Person();
console.log(JSON.stringify(persons)); // [{"name":"Ted"},{"name":"Ted"}]

I would create a new array:
var personNames = $.map(persons,function(person){
return person.name;
});
var jsonStr = JSON.stringify(personNames);

see this post specify the field you'd like to include.
JSON.stringify(person,["name","Address", "Line1", "City"])
it is match better then what suggested above!

Related

Clone an instantiated object with JavaScript?

Couldn't find an answer dealing with cloning instantiated objects in JavaScript. What's the best way to clone an existing instantiated object? E.g.,
function Person() {
}
Person.prototype.setName = function(name) {
this.name = name;
}
var person = new Person();
person.setName('Charles Xavier');
function cloneInstantiated(instantiatedObject) {
var clone = ... new Person ... ????
return clone;
}
var clone = cloneInstantiated(person);
console.log(clone.name); // Charles Xavier
if(clone !== person) {
console.log('Success! We have cloned Charles Xavier into a different memory address.');
}
There's no native or universal way as far as I know. I prefer to write .clone method for my pseudo classes and use it:
Person.prototype.clone = function() {
var clone = new Person()
clone.name = this.name;
}
You could loop through own properties of the object to clone them while not copying stuff inherited from other objects:
for(var i in this) {
if(this.hasOwnProperty(i)) {
clone[i] = this[i];
}
}
This will copy everything that was added to your object after instantiating (eg. won't copy the prototype properties which were already added by calling new Person.
Object.getPrototypeOf
thanks to Bergi
This method allows you to retrieve the prototype of any object. So instead of new Name you can use:
var clone = Object.create(Object.getPrototypeOf(this))
That's an universal solution which can save you lot of work. You must then proceed with copying own properties using for(var i in ...).
Object.create (supported since node V8) (MDN)
Finally, you could create a person that inherits from the original object:
var clone = Object.create(this);
That can be useful in special cases, but normally I wouldn't recommend it.
.toSource (Node.js module) (MDN)
It's also interesting to know that you can (in certain browsers firefox only) override method .toSource which is defined for all objects, even the native ones:
In certain cases, you might want to do:
Person.prototype.toSource = function() {
//Assuming name can be given in constructor
return "new Person("+this.name.toSource()+")";
}
Further reading
Aside from the linked docs, I found this nice article about javascript object inheritance:
Prototypal Inheritance - How To Node - NodeJS
This works perfectly... Fiddle
function Person() {
}
Person.prototype.setName = function(name) {
this.name = name;
}
var person = new Person();
person.setName('Charles Xavier');
function cloneInstantiated(instantiatedObject) {
var clone = {};
for (key in instantiatedObject) {
clone[key] = instantiatedObject[key];
}
return clone;
}
var clone = cloneInstantiated(person);
console.log(clone.name); // Charles Xavier
if(clone !== person) {
console.log('Success! We have cloned Charles Xavier into a different memory address.');
}

JavaScript creating new instance of objects

So I am designing a grade book interface and I have a course defined as:
<script>
course = new Object();
var name;
var gradingareas;
var finalgrade;
</script>
then later I want to create a new instance:
var gradingareas = new Array("Homework", "Classwork", "Exams");
course1 = new course("CS1500", gradingareas, 85);
I have also tried without the var in front to no avail. I get an "Uncaught TypeError: Object is not a function" I am very new to javascript so I don't even know if Im going about this the correct way. Any help is appreciated Thanks.
Your existing code:
// Creates a new, empty object, as a global
course = new Object();
// Creates three new variables in the global scope.
var name;
var gradingareas;
var finalgrade;
There is no connection between the variables and the object.
It looks like you want something more like:
function Course(name, gradingareas, finalgrade) {
this.name = name;
this.gradingareas = gradingareas;
this.finalgrade = finalgrade;
}
Then:
var course1 = new Course("CS1500", gradingareas, 85);
Note the use of a capital letter for naming the constructor function. This is a convention in the JS community.
JS is prototypical, rather than class based and if you are new to it there are advantages to learning this immediately rather than trying to mush classical inheritance models from it, however, classical inheritance is alive and well in JS.
Anyhow, to answer how you would access your variables:
course1.name works fine with the example above.
If you wanted to privatise your data you could take this approach using closure:
var Course = function(name, grade) {
// Private data
var private = {
name: name,
grade: grade
}
// Expose public API
return {
get: function( prop ) {
if ( private.hasOwnProperty( prop ) ) {
return private[ prop ];
}
}
}
};
Then instantiate a new object:
var course = new Course('Programming with JavaScript', 'A');
and start using all that private data:
course.get('name');
Of course, you'd probably want setters to manipulate that data too ;)
The code that you described does the following:
// Declares a memory variable called course and stores and object in it
var course = new Object();
// Declares three variables
var name;
var gradingareas;
var finalgrade;
These declared variables aren't automatically connected to the object. If you want these properties declared on the object you have 2 options:
Declare them as properties of the object
Declare them on the prototype of of the object
Example1: declare them as properties of the object:
// Declares a memory variable called course and stores and object in it
var course = new Object();
// Access or create new properties with . or [] operator
course.name = 'math';
course.gradingareas = 'muliple';
course['finalgrade'] = 'A'
console.log(course);
Example2: Declare them on the prototype:
// Create a constructor function
function Course (name, grade) {
this.name = name;
this.grade = grade;
}
// course is added on the prototype
Course.prototype.gradingareas = 'some gradingareas';
// the name and the grade are added on the object itself
var course = new Course ('willem', 10);
console.log(course);
To create a very simple object with constructor and default values, you can do :
//My object with constructor
var myObjectWithConstrutorFunction = {
//construtor function with default values in constructor
myConstrutor: function(Name = 'bob', Age = 18){
this.Name = name;
this.Age = age;
}
};
// instance
var myInstance = new myObjectWithConstrutorFunction.myConstrutor();
// show on console
console.log('object with constructor function: ', myInstance);
// show properties
console.log(myInstace.Name, myInstance.Age);
PS : It's a good practice create a constructor's name with the same name of the class, if you are creating a external class.

Casting plain objects to class instances in javascript

function Person() {
var self = this;
self.personName="";
self.animals=[];
}
function Animal(){
var self=this;
self.animalName="";
self.run=function(meters){
.....
}
}
Server response:
[{personName:John,animals:[{animalName:cheetah},{animalName:giraffe}]} , {personName:Smith,animals:[{animalName:cat},{animalName:dog}]} ]
I'm getting Person array from server. I want to cast generic Person array to typed Person array. So I can use
persons[0].Animals[2].Run();
I founded Javascript's
Object.create(Person,person1);
But I want cross-browser version of it with array support
ObjectArray.create(Person,persons);
or
Object.create(Person[],persons);
Creating an object in JavaScript requires the invocation of its constructor. So, at first you will need to find the correct arguments, which may not always be just properties. After that, you can reassign all public properties from the JSON-parsed object to the created instances.
A general solution would be that every constructor accepts any objects that look like instances (including real instances) and clones them. All the internal logic needed to create proper instances will be located in the right place then.
Or even better than overloading the constructor might be to create a static method on your class that takes objects and creates instances from them:
Person.fromJSON = function(obj) {
// custom code, as appropriate for Person instances
// might invoke `new Person`
return …;
};
Your case is very simple, as you don't have any arguments and only public properties. To change {personName:John,animals:[]} to an object instance, use this:
var personLiteral = ... // JSON.parse("...");
var personInstance = new Person();
for (var prop in personLiteral)
personInstance[prop] = personLiteral[prop];
You can also use Object.assign functionality (or e.g. jQuery.extend pre-ES6) for this:
var personInstance = Object.assign(new Person(), personLiteral);
The creation of the Animal instances works analogous.
As JSON does not transport any information about the classes, you must know the structure before. In your case it will be:
var persons = JSON.parse(serverResponse);
for (var i=0; i<persons.length; i++) {
persons[i] = $.extend(new Person, persons[i]);
for (var j=0; j<persons[i].animals; j++) {
persons[i].animals[j] = $.extend(new Animal, persons[i].animals[j]);
}
}
Btw, your run methods seems likely to be added on the Animal.prototype object instead of each instance.
It seems like you have classes that have some prototype methods and you'd just like to be able to make your objects use those methods. http://jsfiddle.net/6CrQL/3/
function Person() {}
Person.prototype.speak = function() {
console.log("I am " + this.personName);
};
Person.prototype.runAnimals = function() {
this.animals.each(function(animal){
animal.run();
})
};
function Animal() {}
Animal.prototype.run = function() {
console.log("My Animal " + this.animalName+ " is running");
}
var untypedPersons = [{personName:"John",animals:[{animalName:"cheetah"},{animalName:"giraffe"}]} , {personName:"Smith",animals:[{animalName:"cat"},{animalName:"dog"}]} ];
function fromArray(arr, constructor) {
return arr.map(function(obj){
var typed = Object.create(constructor.prototype);
// Now copy properties from the given object
for (var prop in obj) {
typed[prop] = obj[prop];
}
return typed;
});
}
var persons = fromArray(untypedPersons, Person);
// Attach prototype to each animals list in person
persons.each(function(person){
person.animals = fromArray(person.animals, Animal);
});
persons.each(function(person){
person.speak();
person.runAnimals();
});
​This could all be a lot easier (and we could avoid all the copying) if everybody supported the __proto__ property http://jsfiddle.net/6CrQL/2/
persons.each(function(person){
person.__proto__ = Person.prototype;
person.animals.each(function(animal){
animal.__proto__ = Animal.prototype;
});
});
persons.each(function(person){
person.speak();
person.runAnimals();
});​
First of all: In JavaScript you don't have classes like in C++, Java or C#. So you cannot really have a typed array.
What you are doing should basically work for variables, but not for functions. So you would have to add the functions first. Have a look at the following code to get an idea.
<script type="text/javascript">
function Person() {
var self = this;
self.personName="";
self.animals=[];
}
function Animal(){
var self=this;
self.animalName="";
self.run=function(meters){
7/... do something
}
}
var persons = [{personName:"John",animals:[{animalName:"cheetah"},{animalName:"giraffe"}]} , {personName:"Smith",animals:[{animalName:"cat"},{animalName:"dog"}]} ];
//use this to assign run-function
var a = new Animal();
//assign run-function to received data
persons[0].animals[0].run = a.run;
//now this works
persons[0].animals[0].run();
</script>
How about creating a Static method on Person Class, which will accept your server response and create required variables.
This is just an idea. Please see if this fits in your problem.
//Static method
Person.createObjects = function( response ) {
var persons = [];
for ( var p = 0; p < response.length; p++ ) {
//Create Person
var person = new Person( response[p].personName );
//Create Animals
for ( var a = 0; a < response[p].animals.length; a++ ) {
var animal = new Animal( response[p].animals[a].animalName );
//Push this animal into Person
person.animals.push ( animal );
}
//Push this person in persons
persons.push ( person );
}
//Return persons
return persons;
}
//Now Create required persons by passing the server response
var persons = Person.createObjects ( response );

Javascript: How to turn a JSON array of object back in to the Object type sharing prototypes?

If you have an array of product objects created from JSON, how would you add a prototype method to the product objects so that they all point to the same method? How would you train JavaScript to recognize all product objects in an array are instances of the same class without recreating them?
If I pull down a JSON array of Products for example, and want each product in the array to have a prototype method, how would I add the single prototype method to each copy of Product?
I first thought to have a Product constructor that takes product JSON data as a parameter and returns a new Product with prototypes, etc. which would replace the data send from the server. I would think this would be impractical because you are recreating the objects. We just want to add functions common to all objects.
Is it possible to $.extend an object's prototype properties to the JSON object so that each JSON object would refer to exactly the same functions (not a copy of)?
For example:
var Products = [];
Products[0] = {};
Products[0].ID = 7;
Products[0].prototype.GetID = function() { return this.ID; };
Products[1].ID = 8;
Products[1].prototype = Products[0].prototype; // ??
I know that looks bad, but what if you JQuery $.extend the methods to each Product object prototype: create an object loaded with prototypes then $.extend that object over the existing Product objects? How would you code that? What are the better possibilities?
For one, you're not modifying the Products[0].prototype, you're modifying Object.prototype, which will put that function on the prototype of all objects, as well as making it enumerable in every for loop that touches an Object.
Also, that isn't the proper way to modify a prototype, and ({}).prototype.something will throw a TypeError as .prototype isn't defined. You want to set it with ({}).__proto__.something.
If you want it to be a certain instance you need to create that instance, otherwise it will be an instance of Object.
You probably want something like:
var Product = function(ID) {
if (!this instanceof Product)
return new Product(ID);
this.ID = ID;
return this;
};
Product.prototype.GetID = function() {
return this.ID;
};
Then, fill the array by calling new Product(7) or whatever the ID is.
First, one problem is that prototype methods are associated when the object is created, so assigning to an object's prototype will not work:
var Products = [];
Products[0] = {};
Products[0].prototype.foo = function () { return 'hello' } // ***
Products[0].foo(); // call to undefined function
(*** Actually, the code fails here, because prototype is undefined.)
So in order to attach objects, you'll need to assign actual functions to the object:
Products[0].foo = function () { return 'hello'; };
You can create a helper function to do so:
var attachFoo = (function () { // Create a new variable scope, so foo and
// bar is not part of the global namespace
function foo() { return this.name; }
function bar() { return 'hello'; }
return function (obj) {
obj.foo = foo;
obj.bar = bar;
return obj; // This line is actually optional,
// as the function /modifies/ the current
// object rather than creating a new one
};
}());
attachFoo(Products[0]);
attachFoo(Products[1]);
// - OR -
Products.forEach(attachFoo);
By doing it this way, your obj.foos and obj.bars will all be referencing the same foo() and bar().
So, if I'm getting this all correctly, this is a more complete example of KOGI's idea:
// Create a person class
function Person( firstName, lastName ) {
var aPerson = {
firstName: firstName,
lastName: lastName
}
// Adds methods to an object to make it of type "person"
aPerson = addPersonMethods( aPerson );
return aPerson;
}
function addPersonMethods( obj ) {
obj.nameFirstLast = personNameFirstLast;
obj.nameLastFirst = personNameLastFirst;
return obj;
}
function personNameFirstLast() {
return this.firstName + ' ' + this.lastName;
}
function personNameLastFirst() {
return this.lastName + ', ' + this.firstName;
}
So, with this structure, you are defining the methods to be added in the addPersonMethods function. This way, the methods of an object are defined in a single place and you can then do something like this:
// Given a variable "json" with the person json data
var personWithNoMethods = JSON.parse( json ); // Use whatever parser you want
var person = addPersonMethods( personWithNoMethods );
You could do this...
function product( )
{
this.getId = product_getId;
// -- create a new product object
}
function product_getId( )
{
return this.id;
}
This way, although you will have several instances of the product class, they all point to the instance of the function.
Could try doing something like this (without jquery)
Basic prototypal object:
function Product(id){
this.id = id;
}
Product.prototype.getId() = function(){return this.id;};
var Products = [];
Products[0] = new Product(7);
Products[1] = new Product(8);
Products[2] = new Product(9);
alert(Products[2].getId());
IMO I found a pretty good answer right here:
Return String from Cross-domain AJAX Request
...I could serialize my
data in the service as a JSON string
and then further wrap that in JSONP
format? I guess when it comes over to
the client it would give the JSON
string to the callback function.
That's not a bad idea. I guess I would
also have the option of sending a
non-JSON string which might allow me
to just use eval in the callback
function to create new Person objects.
I'm thinking this would be a more
efficient solution in both speed and
memory usage client-side.

How to use JSON to create object that Inherits from Object Type?

I know how to use JSON to create objects, but there doesn't seem to be away to use JSON to create an object that is of a specific object type.
Here's an example of an Object and creating an instance of it:
Person = function() { };
Person.prototype = {
FirstName: null,
GetFirstName: function() {
return this.FirstName;
}
};
//Create an instance of the Person Object
var me = new Person();
me.FirstName = "Chris";
alert(me.GetFirstName()); //alert the FirstName property
Now, I would like to use JSON to create a new Person object so that the GetFirstName function works on it.
Here's something like that I'm looking to do (but this code doesn't work):
var you = new Person() { FirstName: "Mike" };
// OR
var you = new Person{ FirstName: "Mike" };
Is there anyway to use JSON to create an object that is of a specific type?
UPDATE: My sample with the Person object is just to simplify the question. In fact, I am unable to modify the constructors of the actual objects that I need to create instances of. The objects are part of a third-party library.
UPDATE: Using some of the suggestions below, I was able to figure out a way to create an object that inherits from the original, and accept JSON in it's constructor. This is neat!
personWrapper = function(obj){
for(var o in obj){
this[o] = obj[o];
}
};
personWrapper.prototype = new Person();
var you = new personWrapper({FirstName: "Chris"});
alert(you.GetFirstName());
alert(you instanceof Person); // returns True - we are successfully inheriting from Person!
I don't imagine so. I'd create a function on the Person class to initialise from a JSON object if I were you.
function Person() {
this.loadFromJSON = function(json) {
this.FirstName = json.FirstName;
};
}
If you didn't know what class the JSON object was representing beforehand, perhaps add an extra variable into your JSON.
{ _className : "Person", FirstName : "Mike" }
And then have a 'builder' function which interprets it.
function buildFromJSON(json) {
var myObj = new json["_className"]();
myObj.loadFromJSON(json);
return myObj;
}
Update: since you say the class is part of a third-party library which you can't change, you could either extend the class with prototyping, or write a function which just populates the class externally.
eg:
Person.prototype.loadFromJSON = function(json) {
// as above...
};
or
function populateObject(obj, json) {
for (var i in json) {
// you might want to put in a check here to test
// that obj actually has an attribute named i
obj[i] = json[i];
}
}
You could allow new Person() to accept an object to populate attributes with as a parameter.
var you = new Person({ firstName: 'Mike' });
You can derive an object from theirs. Your constructor can accept the object you want, but call their constructor in an unaffected fashion:
function yourWrapper(obj) {
theirObject.call(this);
for (var s in obj) {
this[s] = obj[s];
}
}
yourWrapper.prototype = new theirObject();
Or something like that :)

Categories

Resources