var Car = function(name, year) {
this.name = name;
this.year = year;
this.print = function() {
console.log(name+" "+year);
}
}
var tesla = new Car("tesla", 2018);
tesla.print();
tesla = JSON.parse(JSON.stringify(tesla));
console.log(tesla);
tesla.print(); // Uncaught TypeError: tesla.print is not a function
How can i add the print function to the object after the parse? Is there an elegant solution for this?
You could create a prototype for printing and call the method with an object for binding.
function Car(name, year) {
this.name = name;
this.year = year;
}
Car.prototype.print = function() { // add prototype
console.log(this.name + " " + this.year); // take this as reference to the instance
};
var tesla = new Car("tesla", 2018);
tesla.print();
tesla = JSON.parse(JSON.stringify(tesla));
console.log(tesla);
Car.prototype.print.call(tesla); // borrow method from class, take own object
A clean approach is to add a function deserialize as prototype which takes an object and assign all properties to the instance.
function Car(name, year) {
this.name = name;
this.year = year;
}
Car.prototype.print = function() {
console.log(this.name + " " + this.year);
};
Car.prototype.deserialize = function(object) {
Object.entries(object).forEach(([k, v]) => this[k] = v);
};
var tesla = new Car("tesla", 2018);
tesla.print();
tesla = JSON.parse(JSON.stringify(tesla));
console.log(tesla);
var tesla2 = new Car;
tesla2.deserialize(tesla);
tesla2.print();
The JSON data format does not support functions (which would be very unhelpful if you generated some JSON from a JavaScript object and then tried to parse it with C#!).
A sensible approach to this would be to change the Car constructor function so that it can accept an object as the first argument.
var Car = function(name, year) {
if (typeof name === "object") {
// use properties of `name` to set everything in this object
} else {
// Treat name and year as a string and number just like you are now
}
...
Then you can:
tesla = new Car( JSON.parse(JSON.stringify(tesla)) );
… which will also generate an object with the correct prototype.
Related
I want to set the weapon with "setWeapon" by creating the "weapon" property too. Example call: "archer.setWeapon (bow);"
function Weapon(name,damage) {
this.name = name;
this.damage = damage;
}
Weapon.prototype.toString = function () {
return this.name + this.damage + " damage"; // method to show weapon
};
var bow = new Weapon('Golden bow, ', 20); // create weapon
function Character() {
this.health = 100;
this.basicDamage = 10;
this.toString = function () {
return this.name + this.type; // add and show weapon bow
};
Character.createArcher = function () { // create hero
var hero = new Character;
hero.name = "Legolas";
return hero;
};
Character.setWeapon = function () {
var weapon = new Character();
weapon.type = Weapon;
return weapon;
};
var archer = new Character.createArcher();
archer.setWeapon(bow); // set the selected weapon
console.log(archer.toString());
One way is to extend prototype of Character with setWeapon and setters just sets the value - they don't return values. You can write getWeapon() for that. This way you pass actual weapon and assign to the archer. Hope that helps. (Weapon is an object so you can access archer.weapon.type)
var bow = new Weapon('Golden bow, ', 20); // create weapon
Character.prototype.setWeapon = function (weapon) {
var me = this;
me.weapon = weapon; // set the weapon
};
var archer = new Character.createArcher();
archer.setWeapon(bow); // set the selected weapon
console.log(archer.toString()); // add to string also property weapon
I am using defineProperty to create an object properties,.Does the descriptor parameter in the function necessarily need to be an object. Here is the code:
var config=new Object();
var defineProp = function ( obj, key, value ){
config.value = value; // why should this parameter be an object?
Object.defineProperty( obj, key, config );
};
Why do we have to pass an Object to the Descriptor parameter
I have below two code pieces, where I am making a constructor and then creating objects using it.Both the codes return the same output in console. Does using .prototype.Methodname change anything?
1
function Car( model, year, miles ) {
this.model = model;
this.year = year;
this.miles = miles;
}
Car.prototype.toString = function () {
return this.model + " has done " + this.miles + " miles";
};
// Usage:
var civic = new Car( "Honda Civic", 2017, 30000 );
console.log( civic.toString() );
2
function Car( model, year, miles ) {
this.model = model;
this.year = year;
this.miles = miles;
this.toString = function () {
return this.model + " has done " + this.miles + " miles";
};
}
var civic = new Car( "Honda Civic", 2017, 30000 );
console.log( civic.toString() );
The code usage is as follows:
var civicSport= Object.create( person );
defineProp(civicSport, "topSpeed", "120mph");//function created above
console.log(civicSport);
The descriptor parameter refers to the property being defined or modified, so we need to refer it as a key value pair( key= property being defined/modified, value= modified or assigned value to property). Thus descriptor must be an Object
For more details, please see MDN docs
I’ve made a little sandbox using the p5.js library : http://gosuness.free.fr/balls/
I’m trying to implement a way to deal with the options on the side, which are toggled using keyboard shortcuts.
This is what I tried to do :
var options =
{
Option: function(name, value, shortcut)
{
this.name = name;
this.shortcut = shortcut;
this.value = value;
this.show = function ()
{
var texte = createElement("span",this.name + " : " + this.shortcut + "<br />");
texte.parent("options");
texte.id(this.name);
}
},
toggle: function(shortcut)
{
for (var o in this)
{
console.log(o);
if (o.shortcut == shortcut)
{
o.value = !o.value;
changeSideText("#gravity",gravity);
addText("Toggled gravity");
}
}
}
};
I instantiate each option inside the object options thus :
var gravity = new options.Option("gravity", false,"G");
var paintBackground = new options.Option("paintBackground",false,"P");
When I call the function options.toggle, console.log(o) gives me "Option" "toggle". but what I want is to get for (var o in this) to give me the list of properties of the object options, which are in this case gravity and paintBackground
How do I do that ?
Thanks !
When You create a instance of Option, its not kept within the variable options, but in the provided variable.
var gravity = new options.Option("gravity", false,"G");
Creates an instance of Option located under gravity variable.
Your iterator for (var o in this) iterates over options properties, with the correct output of the object's methods.
If You want your code to store the new instances of Option within options variable, you can modify code like
var options =
{
instances: [],
Option: function(name, value, shortcut)
{
this.name = name;
this.shortcut = shortcut;
this.value = value;
this.show = function ()
{
var texte = createElement("span",this.name + " : " + this.shortcut + "<br />");
texte.parent("options");
texte.id(this.name);
}
options.instances.push(this);
},
toggle: function(shortcut)
{
for (var i in this.instances)
{
console.log(this.instances[i]);
if (this.instances[i].shortcut == shortcut)
{
this.instances[i].value = !this.instances[i].value;
changeSideText("#gravity",gravity);
addText("Toggled gravity");
}
}
}
};
this is your example working as You intend it to, but i wouldnt consider this as a reliable design pattern.
I'm doing some Javascript R&D and, while I've read Javascript: The Definitive Guide and Javascript Object Oriented Programming, I'm still having minor issues getting my head out of class based OOP and into lexical, object based OOP.
I love modules. Namespaces, subclasses and interfaces. w00t. Here's what I'm playing with:
var Classes = {
_proto : {
whatAreYou : function(){
return this.name;
}
},
Globe : function(){
this.name = "Globe"
},
Umbrella : new function(){
this.name = "Umbrella"
}(),
Igloo : function(){
function Igloo(madeOf){
this.name = "Igloo"
_material = madeOf;
}
// Igloo specific
Igloo.prototype = {
getMaterial : function(){
return _material;
}
}
// the rest
for(var p in Classes._proto){
Igloo.prototype[p] = Classes._proto[p]
}
return new Igloo(arguments[0]);
},
House : function(){
function House(){
this.name = "My House"
}
House.prototype = Classes._proto
return new House()
}
}
Classes.Globe.prototype = Classes._proto
Classes.Umbrella.prototype = Classes._proto
$(document).ready(function(){
var globe, umb, igloo, house;
globe = new Classes.Globe();
umb = Classes.Umbrella;
igloo = new Classes.Igloo("Ice");
house = new Classes.House();
var objects = [globe, umb, igloo, house]
for(var i = 0, len = objects.length; i < len; i++){
var me = objects[i];
if("whatAreYou" in me){
console.log(me.whatAreYou())
}else{
console.warn("unavailable")
}
}
})
Im trying to find the best way to modularize my code (and understand prototyping) and separate everything out. Notice Globe is a function that needs to be instantiated with new, Umbrella is a singleton and already declared, Igloo uses something I thought about at work today, and seems to be working as well as I'd hoped, and House is another Iglooesque function for testing.
The output of this is:
Globe
unavailable
Igloo
My House
So far so good. The Globe prototype has to be declared outside the Classes object for syntax reasons, Umbrella can't accept due to it already existing (or instantiated or... dunno the "right" term for this one), and Igloo has some closure that declares it for you.
HOWEVER...
If I were to change it to:
var Classes = {
_proto : {
whatAreYou : function(){
return _name;
}
},
Globe : function(){
_name = "Globe"
},
Umbrella : new function(){
_name = "Umbrella"
}(),
Igloo : function(){
function Igloo(madeOf){
_name = "Igloo"
_material = madeOf;
}
// Igloo specific
Igloo.prototype = {
getMaterial : function(){
return _material;
}
}
// the rest
for(var p in Classes._proto){
Igloo.prototype[p] = Classes._proto[p]
}
return new Igloo(arguments[0]);
},
House : function(){
function House(){
_name = "My House"
}
House.prototype = Classes._proto
return new House()
}
}
Classes.Globe.prototype = Classes._proto
Classes.Umbrella.prototype = Classes._proto
$(document).ready(function(){
var globe, umb, igloo, house;
globe = new Classes.Globe();
umb = Classes.Umbrella;
igloo = new Classes.Igloo("Ice");
house = new Classes.House();
var objects = [globe, umb, igloo, house]
for(var i = 0, len = objects.length; i < len; i++){
var me = objects[i];
if("whatAreYou" in me){
console.log(me.whatAreYou())
}else{
console.warn("unavailable")
}
}
})
and make this.name into _name (the "private" property), it doesn't work, and instead outputs:
My House
unavailable
My House
My House
Would someone be kind enough to explain this one? Obviously _name is being overwritted upon each iteration and not reading the object's property of which it's attached.
This all seems a little too verbose needing this and kinda weird IMO.
Thanks :)
You declare a global variable. It is available from anywhere in your code after declaration of this. Wherever you request to _name(more closely window._name) you will receive every time a global. In your case was replaced _name in each function. Last function is House and there has been set to "My House"
Declaration of "private" (local) variables must be with var statement.
Check this out:
var foo = function( a ) {
_bar = a;
this.showBar = function() {
console.log( _bar );
}
};
var a = new foo(4); // _bar ( ie window._bar) is set to 4
a.showBar(); //4
var b = new foo(1); // _bar is set to 1
a.showBar(); //1
b.showBar(); //1
_bar = 5; // window._bar = 5;
a.showBar();// 5
Should be:
var foo = function( a ) {
var _bar = a;
// _bar is now visibled only from both that function
// and functions that will create or delegate from this function,
this.showBar = function() {
console.log( _bar );
};
this.setBar = function( val ) {
_bar = val;
};
this.delegateShowBar = function() {
return function( ) {
console.log( _bar );
}
}
};
foo.prototype.whatever = function( ){
//Remember - here don't have access to _bar
};
var a = new foo(4);
a.showBar(); //4
_bar // ReferenceError: _bar is not defined :)
var b = new foo(1);
a.showBar(); //4
b.showBar(); //1
delegatedShowBar = a.delegateShowBar();
a.setBar(6);
a.showBar();//6
delegatedShowBar(); // 6
If you remove the key word "this", then the _name is in the "Globe" scope.
Looking at your code.
var globe, umb, igloo, house;
globe = new Classes.Globe();
umb = Classes.Umbrella;
igloo = new Classes.Igloo("Ice");
house = new Classes.House();
At last the house will override the "_name" value in globe scope with the name of "My House".
So I'm getting this error; Object # has no method 'carName'
But I clearly do.
Pastebin
I've also tried referencing the car's "model" property with
player.car.model
but that doesn't work, I get a type error. Any ideas? Do you need more info?
function person(name, car) {
this.name = name;
this.car = car;
function carName() {
return car.model;
}
}
var player = new person("Name", mustang);
var bot = new person("Bot", mustang);
var bot2 = new person("Bot 2", mustang);
function makeCar(company, model, maxMPH, tireSize, zeroToSixty) {
this.company = company;
this.model = model;
this.maxMPH = maxMPH;
this.tireSize = tireSize;
this.zeroToSixty = zeroToSixty;
}
var mustang = new makeCar("Ford", "Mustang GT", 105, 22, 8);
var nissan = new makeCar("Nissan", "Nissan 360z", 100, 19, 6);
var toyota = new makeCar("Toyota", "Toyota brandname", 95, 21, 7);
It does not have the method. It has a function that is local to the variable scope of the constructor.
To give each object the function, assign it as a property...
function person(name, car) {
this.name = name;
this.car = car;
this.carName = function() {
return this.car.model;
};
}
Or better, place it on the prototype of the constructor...
function person(name, car) {
this.name = name;
this.car = car;
}
person.prototype.carName = function() {
return this.car.model;
};
Also, mustang isn't initialized when you're passing it to the person constructor.