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
Related
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.
I'm making a digital library with three classes: Library, Shelf & Book. Shelves have their contents as an array of books. Books have two methods, enshelf and unshelf. When a book gets unshelfed it's supposed to set delete the instance of itself from the shelf it's on and then set it's location property to null. How can I modify the shelf it's sitting on? In the constructor if I change this.location, it will just give that property a new value instead of modifying the variable it points to. I feel like this is really simple and I'm overlooking something super basic.
var _ = require('lodash');
//books
var oldMan = new Book("Old Man and the Sea", "Ernest Hemingway", 0684801221);
var grapes = new Book("The Grapes of Wrath", "John Steinbeck", 0241952476);
var diamondAge = new Book("The Diamond Age", "Neal Stephenson", 0324249248);
//shelves
var shelf0 = new Shelf(0);
var shelf1 = new Shelf(1);
//libraries
var myLibrary = new Library([shelf0, shelf1], "123 Fake Street");
//these need to accept an unlimited amount of each
function Library(shelves, address) {
this.shelves = shelves; //shelves is an array
this.address = address;
this.getAllBooks = function() {
console.log("Here are all the books in the library: ");
for (var i = 0; i < this.shelves.length; i++) {
console.log("Shelf number " + i + ": ");
for (var j = 0; j < this.shelves[i].contents.length; j++) {
console.log(this.shelves[i].contents[j].name);
}
}
}
}
function Shelf(id) {
this.id = id;
this.contents = [];
}
function Book(name, author, isbn) {
this.name = name;
this.author = author;
this.isbn = isbn;
this.location = null;
this.enshelf = function(newLocation) {
this.location = newLocation;
newLocation.contents.push(this);
}
this.unshelf = function() {
_.without(this.location, this.name); //this doesn't work
this.location = null;
}
}
console.log("Welcome to Digital Library 0.1!");
oldMan.enshelf(shelf1);
myLibrary.getAllBooks();
oldMan.unshelf();
myLibrary.getAllBooks();
Small issue with your unshelf method, easily remedied:
this.unshelf = function() {
this.location.contents =
_.without(this.location.contents, this);
this.location = null;
}
Consider, however, that shelf and unshelf should be methods of Shelf, and not of Book. Also, if you must have this method, surround it with a guard, like so:
this.unshelf = function() {
if (this.location) {
this.location.contents =
_.without(this.location.contents, this);
this.location = null;
}
}
Couple of small issues:
without works on arrays and returns a copy of the array with the elements removed - the original is untouched. So you need to pass location.contents instead of just location and reassign it back to location.contents.
Also you add the whole book to the Shelf, then try to remove it by name, so it doesn't match and get removed. So just pass this to without:
this.unshelf = function() {
if (this.location) {
this.location.contents = _.without(this.location.contents, this);
this.location = null;
}
}
Why is this not working??
var sheep = function(options){
this.options = {sizes: 100,
eat: 100,
colors: 'white',
running: function () {
return this.sizes + this.eat;
}
}
};
var blacksheep = new sheep({colors:'black'});
alert('blackcsheep color is ' + blacksheep.colors);//error undefined
alert('blackcsheep color is ' + blacksheep.options.colors);// it return white
alert('blackcsheep running is ' + blacksheep.running());//error
The syntax:
var sheep = {sizes:100, eat:100, colors:'white',running:function(){
return this.sizes+this.eat;
}
};
is an object literal. It defines an instance of an object, but not the class that defines it. Therefore, there is no way to "new-up" another instance of the object.
Take a look at jQuery's extend functionality:
var blacksheep = {
}
$.extend(blacksheep, sheep, { color: black });
This will copy all the properties of sheep into blacksheep, then merge the third parameter into blacksheep, effectively achieving what you want.
To make another black sheep based on sheep, in this scenario you could do (using jQuery):
var blacksheep = $.extend(sheep, { color: 'black' });
You can create a sheep object like this.
function Sheep(sizes,eat,colors){
this.sizes = sizes;
this.eat = eat;
this.colors = colors;
this.running = function (){
return this.sizes+this.eat;
}
}
Alternatively you can write like this also
function Sheep(sizes,eat,colors){
this.sizes = sizes;
this.eat = eat;
this.colors = colors;
}
sheep.prototype.running = function(){
return this.sizes + this.eat;
}
var sheep1 = new Sheep('100','100','white');
var sheep = function(){
this.sizes = 100;
this.eat = 100;
this.colors = 'white';
this.running = function(){
return this.sizers + this.eat;
}
}
You don't declare objects in JavaScript in the same way as you do in strongly-typed languages. You declare objects by using functions like this:
function sheep() {
this.color = "white";
this.size = 200;
this.speed = 100;
this.running = function () {
return "the sheep is running!";
};
}
var blacksheep = new sheep();
alert('sheep size is ' + blacksheep.size);
alert('sheep running is ' + blacksheep.running());
Your new object does not work because you are creating a new object with a sub-object called options. options contains all of your methods. As such only the second of these three lines that you gave will give you the correct response:
alert('blackcsheep color is ' + blacksheep.colors);
alert('blackcsheep color is ' + blacksheep.options.colors); // Only this one correctly references `options`.
alert('blackcsheep running is ' + blacksheep.running());
in your case sheep is already an object you can not create object of an object.
you can directly use that object with property.
But i think you want something like this
var sheep = {sizes:100, eat:100, colors:'white', running:function(){
return this.sizes+this.eat;
}
}; Object.defineProperty(sheep, 'colors', { value: 'black'
, writable: true });
Thanks
Javascript is prototype based not class based. It does not use classes and is also object orientated.
var whitesheep =new sheep("100","100","white","running");
var blacksheep =new sheep("100","100","black","running");
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.