Can not use class in a function as a parameter (JScript) - javascript

I am trying to do a small JavaScript Lab. In the lab, first I created an Animal object :
function Animal(species, nature) {
this.species = species;
this.nature = nature;
var preys = new Array();
Animal.prototype.getSpecies = function() {
return species;
}
Animal.prototype.getNature = function() {
return nature;
}
Animal.prototype.getPreys = function () {
return preys;
}
Animal.prototype.setNature = function (newNature) {
nature = newNature;
}
Animal.prototype.setSpecies = function (newSpecies) {
species = newSpecies;
}
Animal.prototype.setPrey = function (newPreys) {
preys = newPreys;
}
}
Then, I created a World object which will basically store a number of animal object and separate them according to their nature.
/// <reference path="Animal.js" />
function World() {
var animals = new Array();
animals.push(new Animal("Wolf", "Carnivore"));
animals.push(new Animal("Crocodile", "Carnivore"));
animals.push(new Animal("Sheep", "Omnivore"));
World.prototype.getOmnivores = function () {
return animals.filter(getOmnivores());
}
function getOmnivores(animal) {
}
}
In my getOmnivors function, I can not use the Animal class as a variable. It is a little bit complicated for me cause I am new in JavaScript and regardless of their types we are using var keyword (Or not using in some places such as parameters in functions).
What did I do wrong and how can I fix it? I could not reach the Animal class in my private function getOmnivores. I think program does not understand that it is the class called Animal
I hope I explained well. Have a nice day!
EDIT
Error picture :

Animal is the Class name, you don't need it there. When using filter each element of the array is automatically passed on to the callback function as the first parameter of that function.
Since each element of the array is an instance of the class Animal you can use it straight away.
Also, the syntax {ClassName}.Prototype.{functionName} should not be used within that same Class, because by the time the interpreter reaches that line the Animal Class has not yet been defined. That syntax is used on already existing and defined classes. Use this.{functionName} instead.
function Animal(species, nature) {
this.species = species;
this.nature = nature;
this.preys = new Array();
this.getSpecies = function() {
return this.species;
}
this.getNature = function() {
return this.nature;
}
this.getPreys = function () {
return this.preys;
}
this.setNature = function (newNature) {
this.nature = newNature;
}
this.setSpecies = function (newSpecies) {
this.species = newSpecies;
}
this.setPrey = function (newPreys) {
this.preys = newPreys;
}
}
function World() {
var animals = new Array();
animals.push(new Animal("Wolf", "Carnivore"));
animals.push(new Animal("Crocodile", "Carnivore"));
animals.push(new Animal("Sheep", "Omnivore"));
this.getOmnivores = function () {
return animals.filter(this.filterOmnivores);
}
this.filterOmnivores= function(animal) {
return animal.getNature()=='Omnivore';
}
}
myworld = new World();
console.log(myworld.getOmnivores());
A working fiddle at https://jsfiddle.net/47dyg1q9/

The filter method takes a function as a paramter.
You must provide the function but in your code you are instantly calling the function:
World.prototype.getOmnivores = function () {
return animals.filter(getOmnivores());
}
Remove the parentheses to provide just the function without calling it, or insert an anonymous function:
World.prototype.getOmnivores = function () {
return animals.filter(getOmnivores);
}
// or
World.prototype.getOmnivores = function () {
return animals.filter(function (animal) {
return animal.nature === "omnivore";
});
}

You need to pass the function as an argument, not what it returns.
return animals.filter(isOmnivore);
And isOmnivore becomes
function isOmnivore(animal) {
animal.nature == 'Omnivore';
}

Related

Call method overridden in child class, from the parent class [PHP -> JS]

In my Javascript there is a parent Base class that will be extended by others.
I'd like to:
define in it a method getSubject() that could be common to all children, when it is not overridden.
make getSubject() rely on a Base property, that eventually could be overridden as well.
always call the getSubject() method in the context of the caller (the children classes or the Base class)
To clarify (hopefully) what I want to do..
I wrote (non-valid) PHP code as an example.
<?php
class Base
{
const SUBJ_SELECTOR = 'input';
public function init()
{
$this->wrapper = ....;
$this->subject = $this->getSubj();
if ($this->subject.attr('data-active')) {
// ... do stuff
}
}
public function getSubj() // One definition in parent
{
return $this->wrapper.find(self::SUBJ_SELECTOR);
}
}
class Select extends Base
{
const SUBJ_SELECTOR = 'select' // Override just the selector
}
class Textarea extends Base
{
const SUBJ_SELECTOR = 'textarea[name=foo]';
public function getSubj() // Eventual overriding
{
$subjs = $this->wrapper.find(self::SUBJ_SELECTOR);
foreach ($subjs as $subj) {
if ($subj.attr('multiline')) {
return $subj;
}
}
return $subjs;
}
}
I'd like to achieve the same result with Javascript (and JQuery eventually).
Actually I wrote some code (that I still didn't test) as a sketch:
var Base = function() {
this.options = {};
this.subject_selector = 'input';
this.wrapper = $('.container');
};
Base.prototype.getSubject = function() {
return this.wrapper.find(this.subject_selector);
}
Base.prototype.init = function() {
subj = this.getSubject();
if(subj.attr('data-active')) {
// ... do stuff
}
}
var Select = function() {
this.subject_selector = 'select';
}
Select.prototype = new Base();
Select.prototype.constructor = Select;
var Textarea = function() {
this.subject_selector = 'textarea';
}
Textarea.prototype.getSubject = function() {
subjs = this.wrapper.find(this.subject_selector);
for (var i = subjs.length - 1; i >= 0; i--) {
if(subjs[i].attr('multiline')) {
return subjs[i];
}
};
return subjs;
}
Textarea.prototype = new Base();
Textarea.prototype.constructor = Textarea;
Would it work correctly? Is this a proper use of the inheritance model?
Am I callling the method in the right way and will I get the expected result when executing the init() method?

break large public javascript functions into smaller private functions

I have JavaScript class which have huge functions which are very difficult to maintain.
The 2 public functions are called at start and then on click. I want to create private functions inside these public functions say break into into some private functions scope to these public methods.
var searchResultView;
var SearchResultView = function () {
me = this;
this.init = function () {
// huge code
}
this.Search = function () {
// huge code
}
}
jQuery(function () {
searchResultView = new SearchResultView();
searchResultView.init();
searchResultView.Search();
}
What will best way to achieve this. I tried to use below approach but i think this nested function will not work well.
var searchResultView;
function searchResultView() {
me = this;
this.init = function () {
var declareControls = function () {}
var addEvents = function () {}
var fillControls = function () {}
declareControls();
addEvents();
fillControls();
}
this.Search = function () {
var validateAndCreateCriteria = function () {
if (!validateAandGetLocation()) {
alert("invalid location");
return false;
}
if (!validateAandGetCategory()) {
alert("choose search type");
return false;
}
var validateAandGetLocation = function () {}
var validateAandGetCategory = function () {}
}
validateAndCreateCriteria();
}
}
jQuery(function () {
searchResultView = new searchResultView();
searchResultView.init();
});
If I understood correctly, you should have the functions something like this:
var foo = (function() {
var privateBar = function() { // private function
},
privatefooBar = function() { // private function
};
return {
publicFoo : function() { //public function
/* use privateBar and privatefooBar functions here */
}
};
})();
Later you can access publicFoo function by using
foo.publicFoo();
But you can't access the inside functions which are privateBar() and privatefooBar() directly because they are private functions.
Updated Fiddle
Breaking up the function is easy:
function f(..) {
// many lines here
return ret_f;
}
if equivalent to
function f {
function f1(..) {
// not so many lines here
}
function f2(..) {
// not so many lines here
}
var ret_f1 = f1(..);
var ret_f2 = f2(..);
// calculate ret_f from ret_f1 and ret_f2
return ret_f;
}
or if you prefer this style using anonymous functions
function f {
var f1 = function(..) {
// not so many lines here
};
var f2 = function(..) {
// not so many lines here
};
var ret_f1 = f1(..);
var ret_f2 = f2(..);
// calculate ret_f from ret_f1 and ret_f2
return ret_f;
}
I fear however your real question is specific to your existing code and is about what useful smaller functions to extract there and how to combine them.
For this one would need to have your full code and understand it. That might be a bit much for this QA format.

javascript const in javascript library

I am trying to write a small javascript library as shown below. What I really want is when I call
console.log(tnd().pv);
it should output same number and not generate new number everytime. I know the issue is it calls Math.random everytime I console log. But how can I do so that it outputs same number?
(function () {
var tnd = function() {
return new tnlib();
};
var tnlib = function() {
this.version = function(){
console.log('1.0');
};
this.pv = Math.random()*10000000000000000;
};
if(!window.tnd) {
window.tnd = tnd;
}
})();
Don't execute Math.random() on each invocation of tnlib, but as a static variable:
(function () {
function tnd() {
return new tnlib();
}
function tnlib() {
}
tnlib.prototype.version = function(){
console.log('1.0');
};
tnlib.prototype.pv = Math.random()*10000000000000000;
if (!window.tnd) {
window.tnd = tnd;
}
}());
(or, if you really need to make pv an instance property):
var staticPv = Math.random()*10000000000000000;
function tnlib() {
this.pv = staticPv;
…
}

Custom object 'game' doesn't have specified method

I'm trying to call a method cardSelection() from a function game() but instead I'm getting an error report which throws back to me the whole function with a "has no method cardSelection()" The idea is to access the method through the click of a button, which HTML tag is as follows:
<img id="PlayerCard0" class="card" src="images/Cards/Mario.png" alt="Mario" title="Mario" onclick="game.cardSelection('PlayerCard0')">
I'm not posting the whole Javascript as I believe this to be the case of a mere declaration error, anyhow, game() and cardSelection() were declared as follows:
function game()
{
...
this.cardSelection = function(card)
{
var cardElem = document.getElementById(card);
var id = cardElem.getAttribute("id");
var call = document.getElementById("call");
var select = function(card)
{
var found = 0;
for (var card = 0, totalCards = 5; card < totalCards; card++)
{
if (document.getElementById("PlayerCard" + card + "selected"))
{found++}
}
if (found == 0)
{
call.setAttribute("onclick", "changeHand()");
call.childNodes[0].nodeValue = "Change";
}
if (found < 3)
{
id += "selected"
setAttributes(cardElem,
{
"id" : id,
"style": "position: relative; top: 1em;",
"onclick" : "cardSelection('" + id + "')"
});
}
else { return; }
}
var unselect = function (card)
{
cardElem.removeAttribute("style");
id = id.replace("selected","");
setAttributes(cardElem,
{
"id" : id,
"onclick" : "cardSelection('" + id + "')"
});
var cardNumber = 0;
var found = false;
while (cardNumber < 5 && !found)
{
if (document.getElementById("playerCard" + cardNumber + "selected"))
{found = true;}
cardNumber++;
}
if (!found)
{
call.setAttribute("onclick", "compareHands()");
call.childNodes[0].nodeValue = "Hold";
}
}
if (id.indexOf("selected") >= 0){unselect(card);}
else {select(card);}
}
...
}
How game() is called:
window.onload = function openingScreen()
{
var startGame = document.createElement("a");
startGame.setAttribute("onclick", "game()");
startGame.appendChild(document.createTextNode("Play"));
window.table = document.getElementById("table");
table.appendChild(startGame);
}
The problem you are experiencing is the result of confusion about Objects/Classes/Instances in javascript.
The critical point for you on this issue is the difference between new game() and game();
var foo = new game()
tells the JS engine to create a new object
point that object's Prototype (not prototype) at game's prototype
and then invoke the function game, but for the sake of the body of that function this will refer to the created object.
If the function doesn't return an object, assign our created object to foo (otherwise assign the function's return value to foo
Inside the body of your game function, you have this.cardSelection = function (....
If you simply invoke game as a function, so just game(), without the new keyword, this inside the body of the function will be the window object! So you'll add cardSelection to the window object.
Also importantly: game.cardSelection() is looking for a function named cardSelection as a property on the function game.
Here's an example of using that style that would work:
var foo = function () {
//do interesting stuff
}
foo.bar = function () {
//do interesting stuff related to foo
}
foo.bar();
What you seem to be expecting would need to be written this way:
var game = function () {
this.cardSelection = function () {
//perform card selection!
}
}
var aGame = new game();
aGame.cardSelection();
Or, if cardSelection does not need access to any private properties of the game, it could be written more efficiently as
var game = function () {
//setup the game
};
game.prototype.cardSelection = function () {
//perform card selection
};
var aGame = new game();
aGame.cardSelection();

How to create a javascript library using a closure

I have written some javascript that I would to encapsulate in a closure so I can use it elsewhere. I would like do do this similar to the way jQuery has done it. I would like to be able to pass in an id to my closure and invoke some functions on it, while setting some options. Similar to this:
<script type="text/javascript">
_snr("#canvas").draw({
imageSrc : someImage.png
});
</script>
I have read a lot of different posts on how to use a closure to do this but am still struggling with the concept. Here is where I left off:
_snr = {};
(function (_snr) {
function merge(root){
for ( var i = 1; i < arguments.length; i++ )
for ( var key in arguments[i] )
root[key] = arguments[i][key];
return root;
}
_snr.draw = function (options) {
var defaults = {
canvasId : 'canvas',
imageSrc : 'images/someimage.png'
}
var options = merge(defaults, options)
return this.each(function() {
//More functions here
});
};
_snr.erase = function () {};
})(_snr);
When ever I try to call the draw function like the first code section above, I get the following error, '_snr is not a function'. Where am I going wrong here?
EDIT
Here is what I ended up doing:
function _snr(id) {
// About object is returned if there is no 'id' parameter
var about = {
Version: 0.2,
Author: "ferics2",
Created: "Summer 2011",
Updated: "3 September 2012"
};
if (id) {
if (window === this) {
return new _snr(id);
}
this.e = document.getElementById(id);
return this;
} else {
// No 'id' parameter was given, return the 'about' object
return about;
}
};
_snr.prototype = (function(){
var merge = function(root) {
for ( var i = 1; i < arguments.length; i++) {
for ( var key in arguments[i] ) {
root[key] = arguments[i][key];
}
}
return root;
};
return {
draw: function(options) {
var defaults = {
canvasId : 'canvas',
imageSrc : 'images/someimage.png'
};
options = merge(defaults, options);
return this;
},
erase: function() {
return this;
}
};
})();
I can now call:
<script type="text/javascript">
_snr("#canvas").draw({
imageSrc : someImage.png
});
</script>
Because you declared _snr as an object and not a function. Functions can have properties and methods, so there's various ways to achieve what you want, for example one of them would be say...
_snr = function(tag) {
this.tag = tag;
}
_snr.foo = function() {
//Code goes here
}
You can also pass the outer context into a closure to hide your variables from accidentally polluting the global namespace, so like...
(function(global) {
var _snr = function(tag) {
this.tag = tag;
}
_snr.foo = function() {
//Code goes here
}
//export the function to the window context:
global._snr = _snr;
})(window);
window._snr('#tag').foo('wat');
Happy coding.
Because your _snr is an object, not a function. You have to call it like this:
_snr.draw({
canvasId: '#canvas',
imageSrc: 'someImage.png'
});
When you do _snr('#canvas') that is a function call which is why you're getting that error. _snr is an object with some methods attached to it such as draw() and erase(). The reason jQuery is able to pass arguments into the $ is because they return the $ as a function object which is why we're able to pass it various selectors as arguments.
You are going wrong at the first line _snr = {}
It needs to be
_snr = function(){
selector = arguments[0]||false;
//snr init on dom object code
return _snrChild;
}
Im on a mobile phone but when im on a pc I will maybe fix the whole code c:
Here you have a snr object and that has erase and draw methods. What you intend to do is to write a _snr function which will get an id and return a wrapper object. That returned object should have erase and draw methods. so you can do
var returnedObject = _snr("my_id");
returnedObject.draw("image.png");

Categories