I have this function to create an object:
function Building(owner, type, hp) {
this.owner = owner;
this.type = type;
this.hp = hp;
}
So, every time I call it, a new object is created.
var barracks = new Building(player,bBarracks,"100");
But I have an another function which can be called several times.
function build() {
if (building == 1) {
$("."+xPos+"-"+yPos).addClass("building-powerplant").addClass("taken");
hudBuildings("powerPlant"); initialize();
hudBuildings("barracks");
...
} ... }
I want to create a new object every time build() is called and give it a name of "id"+[increased number], ex. id1, id2, ..., id10.
So every time I call function, an object is created. I tried increasing a number by 1 every time it is used, but I can't figure it out how to write it in. Honestly, that was kinda dumb:
objID++;
var id+(objID) = new Building(player,bPowPlant,"100");
Any ideas how to figure this out? :)
Could you keep the objects in an array? that way the "key" automatically sort of becomes the incremementing ID.
so you have earlier on:
var objects = [];
Then in the build function you do like
objects.push(new Building(player,bPowPlant,"100"))
Then in the objects variables you will have all of the objects you have created. Accessible by objects[0], objects[1] etc.
When you want to save a string as a variable name, you'll need to save it as an object key. You could build your own object, although a common method is to save to the window object using window[variableName]. As for the id number, you can save that to a higher scoped variable and then increment inside the build() function.
var objId = 0;
function build() {
if (building == 1) {
$("."+xPos+"-"+yPos).addClass("building-powerplant").addClass("taken");
hudBuildings("powerPlant"); initialize();
hudBuildings("barracks");
objId++;
...
} ... }
Then when you create a new object:
window["id"+objId] = new Building(player,bPowPlant,"100");
Related
Is it some way to assemble first two rows into one? I am not feeling comfortable to force users of MarkupPreprocessingHelper write two rows...
let markupPreprocessingHelper = new MarkupPreprocessingHelper(config);
let preprocessTemplates = markupPreprocessingHelper.takeCareAboutMarkupPreprocessing.bind(markupPreprocessingHelper);
gulp.task('Development run', gulp.series(
preprocessTemplates,
// ...
));
If you make a rebound copy of the function and save it as an instance property, you can then pass it around and users won't need to bind it manually:
function someClass(name){
this.name = name
// make a prebound copy of myFunction
this.preBound = this.myFunction.bind(this)
}
someClass.prototype.myFunction = function(){
console.log(this.name)
}
let p = new someClass("Mark")
// now you can pass a reference of it around without losing the binding
let fn = p.preBound
setTimeout(fn, 500)
I apologize for this question, just starting to learn Javascript.
I have 2 methods:
Manager.prototype.filters = function () {
var user = [];
...
Manager.prototype.filters_main = function () {
var user = [];
...
I need to make the property 'user' available to the 2 methods (filters, filters_main). So that they can use the shared variable (user).
How it is possible to write?
You have to understand the prototype-based inheritance here.
var Manager = function() {
this.user = [];
}
var manager = new Manager();
These lines will define a Manager constructor function and create a new object. When you call the new Manager(), what happens is:
a new, empty, object is created: {}.
the code inside the constructor will run with this new, empty, object being the value of this. So, it will set the user property of the new object ({}) to be an empty array.
the __proto__ property of the new object will be set to the value of Manager.prototype. So, this happens without you seeing: manager.__proto__ = Manager.prototype.
Then, you want to define new methods on your prototype objects, using the inheritance. Keep in mind that the prototype is a plain JS object. Not a constructor, but an object. So every object created from the Manager function will have its __proto__ property set to the same object.
Then, you start defining new methods on the prototype object, like the filters function. When you, later, call manager.filters(), it will first look up its own properties for the filters function and won't find it. So, then, it will go for its prototype properties, and there if will find it. manager will then run the filters function that was defined on the prototype, but using itself (manager) as the context, as the this inside the function.
So, to use your user property inside the filters function, all you have to do is:
Manager.prototype.filters = function () {
this.user = ...;
}
Manager.prototype.filters_main = function () {
this.user = ...;
}
and you'll be manipulating the same user property defined when the object was constructed.
Define the variable in your Manager definition:
function Manager() {
this.user = [];
}
And now you should be able to use it in your filter functions:
Manager.prototype.filters = function() {
// Use it:
if (this.user.indexOf(...) != -1) {
...
}
};
Then you can continue as normal:
var manager = new Manager();
manager.user = ["user1", "user2"];
var filters = manager.filters();
Add it to the body:
function Manager() {
this.user = [];
}
Manager.prototype.filters = function () {
alert(this.user)
}
var m = new Manager();
m.user = [11,22,33]
m.filters();
I have code like this:
function Food(type) {
this.type = type;
this.timesEaten = 0;
}
Food.prototype.eat = function() { // Dependent function
this.timesEaten++;
}
Food.prototype.pasta = function() { // In-dependent function
return new Food("pasta")
}
So, I want to be able to use the pasta function without defining a new food, like this:
var pasta = Food.pasta()
Buut, that doesn't work, you have to do like this:
var pasta = new Food().pasta()
Well "Food.pasta()" does work if you set up Food like this:
var Food = {
pasta: function() {
return {type: pasta};
}
}
But then new Food won't work, which means I'll have to use "return {type: pasta}".
I wonder, is there any way to create a Food that can be both dependent and independent?
A method like your .pasta() method that does not operate on any instance data is called a static method. You don't want it on the prototype because the prototype will only be in the lookup chain on an instantiated object (after creating an actual Food object by doing new Food()).
Instead, for a static method you can put it on the constructor function itself like this:
Food.pasta = function() {
return new Food("pasta");
}
The, you can call it like this:
var pasta = Food.pasta();
It's useful to remember that in javascript, Functions are objects too so they can have properties/methods and when you're looking for a place to put static functions or data that don't belong to a particular instantiated object or need to be called on a particular instantiated object, the Constructor object is often a good place to put them.
function Food(type) {
this.type = type;
this.timesEaten = 0;
}
Food.prototype.eat = function() { // Dependent function
this.timesEaten++;
}
Food.pasta = function() { // In-dependent function
return new Food("pasta")
}
Food.prototype functions are only available for objects of Food, while for Food.pasta Food is only a namespace object.
Usage:
Food.pasta();
I have been trying to learn OOP with JavaScript before I start attempting to learn backbone.js.
I want to be able to data bind but I can't seem to get it to work.
I've just made a simple protoype of a budget website that you can put in a budget and input how much you've spent, and it will show if you've gone over.
function BudgetItem(spent, budget){
this.setSpent = function(spent){
this.spent = spent;
}
this.setBudget = function(budget){
this.budget = budget;
}
this.getSpent = function(){
return this.spent;
}
this.getBudget = function(){
return this.budget;
}
}
function BudgetType(type){
this.getType = function(){
return type;
}
}
BudgetType.prototype = new BudgetItem();
$(document).ready(function(){
var food = new BudgetType('food');
$('.budget').html(food.getBudget());
$('.editbudget').change(function(){
food.setBudget($('.editbudget').data())
});
})
That's my code thus far. I'm not sure if I'm doing it right. Am I supposed to extend things? Also, can someone explain how to dynamically data bind without a library?
First I'll give you some theory. A Javascript function is a dynamic object, just like Object is, and a new instance can be created using the new keyword much like you are doing in your listener. When this happens, the function itself will run as a constructor while the this keyword will be bound to the newly created object. What you're doing above then is in fact adding new properties on the fly as you're passing in their values for the first time... which is fine, but not very clear to another reader.
Now for the tricky part. Every function has a link to a "hidden" Prototype object. This is an anonymous (not accessible by name) object created by the JavaScript runtime and passed as a reference to the user object through the prototype property. This Prototype object also has a reference to the function through its constructor property. To test what I'm saying for yourself, try the following:
BudgetItem.prototype.constructor === BudgetItem // true
Putting it all together, you can now think of functions as constructors to (hidden) classes that are created for you behind the scenes, accessible through the function's prototype property. So, you could add the fields to the Prototype object directly as so:
function BudgetItem(spent) {
this.spent = spent
}
BudgetItem.prototype.setSpent = function(spent) { this.spent = spent };
BudgetItem.prototype.getSpent = function() { return this.spent };
Another problem is inheritance and passing parameters to the constructor. Again, your version is valid but you lose the ability to pass the spent and budget values when initializing a BudgetType. What I would do is forget prototypes and go:
function BudgetType(type, spent) {
var instance = new BudgetItem(spent);
instance.type = type;
return instance;
}
This is close to what Scott Sauyet suggested above but more powerful. Now you can pass both parameters (and more) and have a more complicated inheritance tree.
Finally, what you can do is create private (or pseudo-private, more accurately) properties by providing a getter to an otherwise automatic variable (one passed as an argument or initialised inside the function). This is a special feature of the language and it works like so:
function BudgetType(type, spent) {
var instance = new BudgetItem(spent);
instance.getType = function() {
return type;
}
return instance;
}
Now you can access the 'type' passed in the constructor by obj.getType() but cannot override the initial value. Even if you define obj.type = 'New Value' the getType() will return the initial parameter passed because it has a reference to another context which was created when the object was initialised and never got released due to the closure.
Hope that helps...
if you want all instances of objects to reference the same members/values you can use a closure:
// create a constrctor for you object wrapped in a closure
myCon = (function() {
// define shared members up here
var mySharedObj = new function () {
this.member = "a";
}();
// return the actual constructor
return function () {
this.mySharedObj = mySharedObj;
}
}());
// create two instances of the object
var a = new myCon();
var b = new myCon();
// Altering the shared object from one
a.mySharedObj.member = "b";
// Alters it for all
console.log(b.mySharedObj.member);
If you want to build objects from other objects(sort of like other languages' class whatever extends baseClass), but do not want them to share values via reference(instead a clone of values), you can use something like the following:
Object.prototype.extendsUpon = (function (_prop, _args) {
return function (base) {
for (var key in base) {
if (_prop.call(base, key)) {
this[key] = base[key];
}
}
function con(child){
this.constructor = child;
}
con.prototype = base.prototype;
this.prototype = new con(this);
this.__base__ = base.prototype;
var args = _args.call(arguments);
args.shift();
base.constructor.apply(this, args);
}
}(Object.prototype.hasOwnProperty, Array.prototype.slice));
Then to build objects ontop of objects:
// Base Object Constructor
function Fruit(name) {
this.fruitname = name;
}
Fruit.prototype.yum = function() {
return "I had an " + this.fruitname;
}
// Object constructor that derives from the Base Object
function Favorite() {
// Derive this object from a specified base object:
// #arg0 -> Object Constructor to use as base
// #arg1+ -> arguments passed to the BaseObject's constructor
this.extendsUpon(Fruit, "apple");
// From here proceed as usual
// To access members from the base object that have been over-written,
// use "this.__base__.MEMBER.apply(this, arguments)"
}
Favorite.prototype.yum = function() {
return this.__base__.yum.apply(this) + " and it was my favorite";
}
var mmm = new Favorite();
// Outputs: "I had an apple and it was my favorite"
mmm.yum();
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.