Default values for objects in Javascript - javascript

Javascript Code
var a = {};
a.test += 1; //NaN
++a.test; //NaN
Instead
var a = {};
a.test = 0;
++a.test; //1
a.test += 1; //2
I wonder if there could be anyway that can make first code sample work the same as second, i.e without an explicit assignment to 0. As in assigning default value for any property of an object to 0 instead undefined. I'm trying to do this in node.js. So, no problem of cross browser things and old ECMA Specs.
var i;
for(i = 0; i<10; i++) {
if(a.test) {
++a.test;
} else {
a.test = 0;
++a.test;
}
//a.test = a.test || 0; (1)
//++a.test;
}
If it is possible then the inner if/else or the assignment statement(1) in the above code can be eliminated.

Javascript by default defines all new variables as undefined ( if not explicitly defined ) , which is different from Number object, which you are trying to define. So you should use smth like :
for (i=0; i<10; i++) {
a.test = a.test || 0;
++a.test
}

There's no way to do this for any arbitrary undefined property.
For a known property name, there is a way, but DO NOT USE IT !! 1
Object.prototype.test = 0;
This will give every object an implicit .test property with that value in it, and the first time you attempt to modify it the result will be stored in your own object:
> Object.prototype.test = 0
> a = {}
> a.test++
> a.test
1
1 Adding stuff to Object.prototype will break stuff, including for (key in obj)

This is where prototypes come in useful in javascript:
function Demo() {
}
Demo.prototype.x = 0;
> a = new Demo();
> a.x += 1
> a.x
1
> b = new Demo()
> b.x
0

In the first code, you can't. Any number added to a non-number or NaN value will always result in NaN
var a = {};
a.test += 1; // undefined + 1 = NaN
++a.test; // ++(undefined) = NaN
as for the inner if
for(i = 0; i<10; i++) {
a.test = a.test || 0; //use existing value, or if undefined, 0
++a.test; //increment
}

I think this would do:
var a = {"test":0};
a.test += 1;

Using standard JS it's not possible to do what you're asking. Unless you prototype I guess? But I'm not experienced with Prototype.And I don't think prototyping works with Node.js
The reason for this is because js is not a typed language (i.e. we only use var to declare a variable, not int a or string b), so in order to use the ++ operator, the variable needs to be given a type through assignment.
hope that helps

Related

Multiplication Loop not multiplying

Trying to loop the arguments entered and return the arguments as the total multiplication:
let lightCode = { //Creates Object.
Multiply: function() { //Multiplys all arguments.
const total = 0;
for(const i = 0; i < arguments.length; i++) {
console.log(arguments[i]);
total *= arguments[i];
}
return total;
}
}
lightCode.Multiply(12, 16)
You have two problems, one of which is that you can not reassign a value to a constant. Second you're setting total = 0 first. By doing that you'll be multiplying everything by 0.
So in order to solve your problem you need a if conditional to check if total is 0, if is 0 you assign the property total to the argument in the loop, if not you multiply it.
let lightCode = { //Creates Object.
Multiply: function() { //Multiplys all arguments.
let total = 0;
for(let i = 0; i < arguments.length; i++) {
if(total === 0) total = parseFloat(arguments[i]);
else total *= parseFloat(arguments[i]);
}
return total;
}
}
console.log(lightCode.Multiply(12, 16));
I recommend you to read about const, let, var and when to use them. There are (at least) two mistakes in your code:
const total = 0 => since total is declared using the const identifier, it means that its value is going to be constant during your program. And what does constant mean? That it stays the same. But the line total *= arguments[i]; wants to change it, resulting into an error. Also, initializing the total with 0 makes the final results to be 0 (remember that the multiplication identity element is 1).
const i = 0 => same thing; i++ wants to increment the value of i, but you declared it as const.
Running your code and opening the console you can clearly say an error message: "Uncaught TypeError: Assignment to constant variable.".
Cheers!
let lightCode = {
Multiply: function() {
var total = 1;
for (var i = 0; i < arguments.length; i++) {
console.log(arguments[i]);
total *= arguments[i];
}
return total;
}
}
lightCode.Multiply(12, 16)
As pointed in the comments, there is more than one error in the code, first you are assigning the variables as const which is not correct in this case, the rule of thumb is to use let every time you need to reassign a variable (meaning, when you need to use the =symbol again), otherwise use const. Also as pointed in the comments you should not initialize the variable with zero, otherwise the loop will always return zero.
Here is a working snippet:
const lightCode = { //Creates Object.
Multiply: function() { //Multiplys all arguments.
let total = 1; // can not be zero, otherwise the loop will always return zero
for(let i = 0; i < arguments.length; i++) {
console.log(arguments[i]);
total *= arguments[i];
}
return total;
}
}
lightCode.Multiply(12, 16)
Notice how I am using const for the lightCode variable, because this object is never reassigned (meaning, you won't use the = to assign a new value again) and instead for total I'm using let, because is reassigned on every loop interaction.

Javascript - see if object contains function, if so, return it

I have a function which takes in a String. The function checks if the object in the list has this function(functionName). If it contains that function, how can I return it? Obviously, return list[i].message would work, but thats not what im after. I want do use the parameter functionName in this case.
function message(){
return "hello";
}
function test(functionName);
listLength = list.length;
for(i = 0; i < listLength; i++){
if(list[i].hasOwnProperty(functionName}{
return (?)
}
}
var x = test("message");
alert(x);
Grateful for response
the comment from Pointy is right, but you have to consider that having a function detached by its owner will screw the scope, so you will no longer have access to the right this object
var test = {
number: 0,
testFunction: function() {
return this.number;
}
}
console.log(test.testFunction()); // output: 0
var x = test.testFunction;
console.log(x()); // output: undefined
maybe you should use
var y = test.testFunction.bind(test);
console.log(y()); // output: 0

Javascript: reverse an array of document.getElementByClassName

i have this variable that is:
var stars = this.parentNode.children
and its value is:
[span.rate, span.rate, span.rate.rated, span.rate.rated, span.rate.rated]
Now i want to reverse it, but if i try:
stars.reverse()
I obtain
Uncaught TypeError: stars.reverse is not a functionupdateRateStar # app.js:75(anonymous function) # app.js:98
I cannot understand why it works with an array like:
[1,2,3]
So if i try:
[1,2,3].reverse()
it works. Thus i cannot understand the problem
You can't call Array.prototype.reverse on NodeListCollection. Instead, you should use:
var stars = [].slice.call(stars, 0).reverse()
Use
var revArray = Array.prototype.slice.apply( a ).reverse()
The reason is that you have a NodeList and not an Array there. Both behave similarly in many cases, but the NodeList does not have the array methods.
With the
Array.prototype.slice.apply( a )
part, we convert the NodeList to an array, which can than be reversed.
It's a NodeList, which doesn't have a reverse. You can tell an object's prototype (like class in other languages) using:
Object.prototype.toString.call(stars)
Which returns [object NodeList]. An array would return [object Array].
If you own the prototypes (ie, this isn't a library), you can run:
NodeList.prototype.reverse = Array.prototype.reverse
then
stars.reverse()
Will work. Which is a lot more logical and pleasant to look at than constantly borrowing the method off Array.
Again, you own the prototypes here, be aware that it's on you to fix if the browser adds a prototype in future. You may prefer:
NodeList.prototype.sirkoReverse = Array.prototype.reverse
Which still reads nicely but is less likely to have conflicts.
It has different type , like NodeList and Array.
I suggest you to use this function:
var reverse = function(arr) {
var result = [];
for (var i = arr.length - 1;i !== 0;i--) {
result.push(arr[i]);
}
return result;
}
Second variation:
function xorSwapHalf(array)
{
var i = null;
var r = null;
var length = array.length;
for (i = 0; i < length / 2; i += 1)
{
r = length - 1 - i;
var left = array[i];
var right = array[r];
left ^= right;
right ^= left;
left ^= right;
array[i] = left;
array[r] = right;
}
return array;
}
There is another swap method called destructuring assignment: http://wiki.ecmascript.org/doku.php?id=harmony:destructuring
Destructuring assignment:
function destructuringSwap(array)
{
var left = null;
var right = null;
var length = array.length;
for (left = 0, right = length - 1; left < right; left += 1, right -= 1)
{
[array[left], array[right]] = [array[right], array[left]];
}
return array;
}

How to modify a function parameter at the same time new vars are created on a loop?

This is the code without any attempt to add var nn = 99 to the loop
//note that the 'i' is a parameter of the function
function myFunction(arr, i) {
for (i = i ? i + 5 : 1; i < arr.length; i++) {
//...
}
}
When I try to add a new var it do things I don't want:
Edit: it seems this is wrong
for (var nn = 99, i = i ? i + 5 : 1; i < arr.length; i++)
//created a new 'i'
or
for (i = i ? i + 5 : 1, var nn = 99; i < arr.length; i++)
//doesn't work :(
I know it is exactly the same if I move it outside. But one of the things I hate most, is to not be able to understand what I meant when reading a old code after some months. Moving that line inside the loop will make me understand that line easier.
You can't modify the function's parameter. As i is a primitive value (number), JavaScript will call-by-value, not by-reference.
And as you name your second argument "i", it will be available as a local variable from start on. Using the var keyword with "i" somewhere won't change anything.
((i = i ? i + 5 : 1) * 0) + 99
This will always equal 99. But that does not matter, since it is still unclear what you are trying to accomplish.
If your goal is to loop through an array from a designated start spot then you can do this.
for (; i<arr.length; i++) {}
If you can't guarantee that i is a number, then you will have to perform some sort of checking.
for (var index=(i?i:0); index < arr.length; index++) {}
Javascript will pass primitives by value, so you cannot modify the source value from inside this function. You can return the modified value if want.
ivar = func(arr, ivar);
function func(arr, i){
for (;i<arr.length; i++) {}
return i;
}

Programmatically setting the name of a variable

Is there a shortcut for writing the following 100 assignments?
variable_1 = 1;
variable_2 = 2;
variable_3 = 3;
...
variable_100 = 100;
I have tried
for(var i = 1; i <= 100; i++) {
variable_ + i = i;
}
but I get the error message "Invalid left-hand side in assignment". Any ideas?
Here are a few methods:
Method 1: use eval
Here is the most direct method:
for(var i = 1; i <= 100; i++) {
eval("var variable_" + i + " = " + i);
}
variable_1; // => 1
Disclaimer for the above method: I don't think this problem is a good candidate for using eval. If you do use eval, you should never allow user input to go into what you are evaling, or you could open your site to security risks. That mistake is the main reason people say eval is evil.
Method 2: use dynamically generated object properties
This is a much, much better way:
// If you want these variables to be global, then use `window` (if you're
// in a browser) instead of your own object.
var obj = {};
for(var i = 1; i <= 100; i++) {
obj["variable_" + i] = i;
}
obj.variable_1; // => 1
About the note in the comment about using window to create global variables: I would recommend against this, as it is a quick way to pollute your global scope and step on variables unwittingly.
Method 3: use an array
David suggested using an array. This is another great idea, and, depending on what you are trying to do, may be preferred:
var arr = [];
for(var i = 1; i <= 100; i++) {
arr.push(i);
}
arr[0]; // => 1
This will do it:
for(var i = 1; i <= 100; i++) {
eval("variable_" + i + " = " + i + ";");
}
eval is basically evil, but for such purpose it's OK to use it. (reference)
Live test case.
You are better off using an array
var variable = [];
for (var i=1; i <= 100; i++) {
variable[i] = i;
}
Later, you can access the values using variable[1], variable[2] etc.
If it is like that why not to define array of the objects
var a = new Array();
for(i=0;i<100;i+=)
a[i] = i;
Why not using an array instead like this?
<script language="javascript">
var arrayVar = new Array();
for (var i=0; i<100; i++) {
arrayVar["variable_" + i] = i;
}
</script>
Use an array:
var variable = [];
for(var i = 1; i <= 100; i++) {
variable[i] = i;
}
By way of analogy, you'd want to use an array instead of 100 variables for the same reason you'd want
<div class="variable"></div>
<div class="variable"></div>
<div class="variable"></div>
//and so on
instead of
<div id="variable_1"></div>
<div id="variable_2"></div>
<div id="variable_3"></div>
//and so on
<div id="variable_100"></div>
Invalid left-hand side in assignment
This error gets generated because variable_ + i is an expression. The interpreter thinks you are trying to add two variables instead of concatenating a variable name and a string. An expression cannot be on the left-hand side of an assignment operation.
for(var i = 1; i <= 100; i++) {
window["variable_" + i] = i;
}
alert( variable_50 );
alert( variable_34 );
Assuming you're on a browser you can do:
global[variable] = 'hello'
console.log(variable) -> hello

Categories

Resources