I would like to override toString using ES5. Given the following function which returns a complex number:
function complex(real, imaginary){
var z = Object.create(complex.prototype);
z.real = real;
z.imaginary = imaginary;
return z;
}
In order to override toString inherited from Object I do the following:
complex.prototype.toString = function(){ return this.real + " + " + this.imaginary + "*i";};
TEST:
var z = complex(1,1);
console.log(z);
RESULT:
{ real: 1, imaginary: 1 }
Do I miss something?
There are two things going on:
In many environments (including most browsers), console.log doesn't use toString, and
Your complex function doesn't return an object that uses complex.prototype as its prototype, so it doesn't have your toString. You're creating the object you return using {}, which creates an object directly inheriting from Object.prototype.
If you want to call complex without new, you need to explicitly use complex.prototype when creating your object, for instance via Object.create(complex.prototype). (And then when logging, trigger toString on purpose, either calling it directly or converting to string in various other ways.)
Example:
function complex(real, imaginary){
var z = Object.create(complex.prototype);
z.real = real;
z.imaginary = imaginary;
return z;
}
complex.prototype.toString = function(){ return this.real + " + " + this.imaginary + "*i";};
var z = complex(1, 1);
console.log(String(z));
You could call complex via new if you like (but I'm guessing you chose not to on purpose). Just FWIW:
function Complex(real, imaginary){
this.real = real;
this.imaginary = imaginary;
}
Complex.prototype.toString = function(){ return this.real + " + " + this.imaginary + "*i";};
var z = new Complex(1, 1);
console.log(String(z));
or even
class Complex {
constructor(real, imaginary) {
this.real = real;
this.imaginary = imaginary;
}
toString() {
return this.real + " + " + this.imaginary + "*i";
}
}
const z = new Complex(1, 1);
console.log(String(z));
Side note: I've changed "imagenary" to "imaginary" above, which is the correct spelling in English. (Most of the text in your code seemed to be in English, but apologies if it's just that you translated the code in the question from another language and just forgot to translate "imagenary".)
Related
New to JS here, so I apologize if I'm missing something obvious. Trying to build a random number generator (it works in a nested manner, so something like a list of tuples of random number), but I get a OOM error with this code. (Say, if i try to do something like generateList(6))
function generateList(num){
var arr = [];
for(i=0;i<num;i++){
arr.push(generateTuple());
}
return arr;
}
function generateTuple(){
var tuple = [];
for(i=0;i<3;i++){
tuple.push(Math.floor(Math.random() * 300));
}
return '(' + tuple[0] + ',' + tuple[1] + ',' + tuple[2] + ')';
}
OTOH, if I just generate the random numbers individually and return them (instead of using a list), it works without errors. Can anyone enlighten me as to what is going on here?
function generateTuple(){
var a = Math.floor(Math.random() * 300);
var b = Math.floor(Math.random() * 300);
var c = Math.floor(Math.random() * 300);
return '(' + a + ',' + b + ',' + c + ')';
}
EDIT: So basically if you run the code, it gets stuck in some loop, and after a period of time in the console it returns the OOM error. So I assume it's some memory overflow or something somewhere.
You are creating global i by declaring it without var or let, then you loop with it. That creates unprecedented values for i, leading to the loop will never complete. Declare your variables correctly.
for(var i=0;i<num;i++) // better: let i = 0; ...
and
for(var i=0;i<3;i++) // better: let i = 0; ...
Your is are global variables. Always declare variables with const or let (or var) to avoid global pollution and unexpected behavior (like what's happening here).
Each time generateTuple is run, i gets set to 3 at the end of the for loop in generateTuple. So, the i referenced by generateList - which references the same global variable - never has a chance to get any higher than 4. So if you call generateList with higher numbers, you'll get an infinite loop.
Just declare your variables properly:
function generateList(num){
var arr = [];
for(let i=0;i<num;i++){
arr.push(generateTuple());
}
return arr;
}
function generateTuple(){
var tuple = [];
for(let i=0;i<3;i++){
tuple.push(Math.floor(Math.random() * 300));
}
return '(' + tuple[0] + ',' + tuple[1] + ',' + tuple[2] + ')';
}
console.log(generateList(10));
This is my current assignment :
Add a method that will increase the value of one of the numeric properties.
Add a method that will decrease the value of the same numeric property.
Create a for loop after creating an instance of the character. The loop will iterate 100 times.
Inside the loop call one of the methods based on a random number from zero to 3. Using a switch statement, if the value is 0 then call the method that losses; 1 don’t call anything; 2 call the method that gains.
Here is my current coding. I know I'm doing something wrong. I just can't figure out what I am doing wrong with the switch statement.
var BR = "<br />";
function person(name, sandwiches) {
this.name = name;
this.sandwiches = sandwiches;
function jump() {
var text = " leaps over an obstacle.";
return fname + text;
}
function run() {
var text = " runs as fast as they can";
return fname + text;
}
function dodge() {
var attack = math.random();
var att = math.round(attack);
var defense = math.random();
var def = math.round(defense);
if(att > def) {
return "You missed";
}
else {
return "You dodged";
}
}
function date() {
var today = new Date();
return today.toDateString();
}
function shout() {
var word = "Oh no";
return word.toUpperCase();
}
this.addSandwich = function (sandwiches) {
sandwiches = sandwiches + 1;
return sandwiches;
};
this.loseSandwich = function (sandwiches) {
sandwiches = sandwiches - 1;
return sandwiches;
};
}
var character = new person("Jerry", 1);
for(i=0; i < 100; i++) {
var random = Math.floor(Math.random() * 3);
switch(random) {
case 0:
character.loseSandwich(character.sandwiches);
console.log(sandwiches);
break;
case 1:
break;
case 2:
character.addSandwich(character.sandwiches);
break;
}
}
document.write("Name: " + character.name + BR);
document.write("Sandwiches: " + character.sandwiches + BR);
Math.floor(Math.random() * 3) is not what you want.
You want something like Math.random() % 3 to get 0, 1, or 2 every single time
Not sure if this is your problem, but it is at least one of them;
In a few places you have a lowercase math, for example:
function dodge() {
var attack = math.random();
JavaScript is case-sensitive, and it should be Math.random() not math.random()
Another issue is that these functions:
this.addSandwich = function (sandwiches) {
sandwiches = sandwiches + 1;
return sandwiches;
};
do not change the number of sandwiches. You get in a value of sandwiches, add or subtract 1, then return that changed number, but never use the returned result.
You are only changing the value of the variable that was passed in, not changing the number of sandwiches on the instance of the person.
Note that this.sandwiches (the variable on the instance of a person) is not the same variable as sandwiches (the function argument)
I dont think there is any reason to pass the number of sandwiches into those functions, and they could just do:
this.addSandwich = function () {
this.sandwiches = this.sandwiches + 1;
};
or more simply:
this.addSandwich = function () {
this.sandwiches++;
};
Another problem here:
character.loseSandwich(character.sandwiches);
console.log(sandwiches);
The console.log statement is trying to log sandwiches but that is not a variable at that point. You probably wanted console.log(character.sandwiches); However this wouldn't cause an exception, it would just always log undefined.
I´m trying to understand how Function.prototype.call() works.
I know what it does, and I can work with it, but I´m curious about how this method is implemented.
Is it possible to write a javascript-method from scratch that does exactly the same?
It's not possible to "unwrap" variable arguments without eval. If it's fine with you, you can try this:
function myCall(fun, obj) {
var args = [].slice.call(arguments, 2);
var arglist = args.map(function(_, n) { return "args[" + n + "]" }).join(',');
obj._tmp = fun;
return eval("obj._tmp(" + arglist + ")")
}
Example:
foo = {
x: 123
}
bar = function(y) { return this.x + y }
console.log(myCall(bar, foo, 444))
Suppose we define a function that simply increments its input by some stored value dd:
var obj={}
obj.dd=1
obj.f=function(x){
return x+this.dd
}
Alternatively you could create a closure for dd as follows but this would create a static increment as opposed to one that could be altered later:
var dd=1
var f=function(x){
return x+dd
}
We could alternatively store dd in the function itself:
var obj={}
obj.f=function(x){
return x+this.f.dd
}
obj.f.dd=1
I am curious as to whether it is possible for a function to retrieve a variable attached to itself without going through a parent object, something like a self keyword that would refer to the function itself and would allow the following:
var f=function(x){
return x+self.dd
}
f.dd=1
I know it is unnecessary to do such a thing but I think it would be cool if you could.
You can give function literals a name:
var f = function me(x) {
return x + me.dd;
};
f.dd = 1;
This doesn’t work properly in older versions of IE/JScript, though, as me and f don’t reference the same object. The (deprecated and not usable in strict mode) alternative is arguments.callee:
var f = function(x) {
return x + arguments.callee.dd;
};
f.dd = 1;
Also, your note about the closure isn’t quite right; it can be altered later, even through another function:
var dd = 1;
var f = function(x) {
return x + dd;
};
var setdd = function(_dd) {
dd = _dd;
};
A function is an object. If you reference the var holding the function:
var f = function (x) {
return x + f.dd
};
f.dd = 1;
alert(f(1));
result: 2
If the function is named, you can do the same:
function foo(x) {
return x + foo.dd;
}
foo.dd = 1;
alert(foo(1));
result: 2
I have this data response from an AJAX call:
{"18:00":{"twopersons":1,"fourpersons":0}}
Which gets stored into a variable by statsarray = data;
Now how can i loop through statsarray and output the twopersons value?
So I can alert:
18:00 - There's 2 x 2persons and 0 x 4persons
Here is the Ajax call:
var statsarray;
var currentloopeddate = test_date.toString('yyyy-MM-dd')
$.post("/home/sessions",
{ action: 'partner_calendar_checkseats', date: currentloopeddate },
function(data) { statsarray = data; }
);
Just do the following:
var twopersons = data["18:00"].twopersons;
var fourpersons = data["18:00"]["fourpersons"];
(Both variants are possible)
A variant would be:
var shorter = data["18:00"];
var twopersons = data.twopersons;
// ...
Something like:
var tst = {"18:00":{"twopersons":1,"fourpersons":0}};
for(k in tst) {
for(var z in tst[k]) {
console.log(k + ": Theres "+tst[k][z] + " X " + z);
}
}
You can try something like this:
(UPDATE: better example)
var statsarray = {"18:00":{"twopersons":1,"fourpersons":0}};
var hour, persons, line, array;
for (hour in statsarray) {
if (statsarray.hasOwnProperty(hour)) {
array = [];
for (persons in statsarray[hour]) {
if (statsarray[hour].hasOwnProperty(persons)) {
array.push(statsarray[hour][persons] + " x " + persons);
}
}
line = hour + " - There's " + array.join(' and ');
alert(line);
}
}
See: DEMO.
Unfortunately you have to test with .hasOwnProperty to make sure it will work with some libraries.
UPDATE: You have added the code from your AJAX call in your question and I noticed that you declare the statsarray variable outside the callback function, but assign some value to that variable inside the callback. Just keep in mind that you have to run your iteration code inside the function that is the AJAX callback, where you have: statsarray = data; - just after this line, to make sure that you actually have some values to iterate over.