I was pondering something earlier. I wanted to check if a function had already been put into an array. If so throw an exception. I did this little test with the console...
So I guess I could say that the objects are always just references, and after setting a as x I could change x and a would be effected as well?
Would this mean that the condition x = a no matter what, which is what I want.
Using this to check if the function/object is already in the array I could just do this correct...
Is there a better way to do this?
Would this also mean that if I pass a variable to a function and mutate it in that function it will be mutated outside of that function as well?
EDIT
I guess I am right about the mutation with this little test. But I don't get why its bar in the first log in the second example
EDIT END
Example 1:
var x = function(){console.log("hello")}; var a = function(){console.log("hello")};
console.log(x == a); //comes out false
//Set a as x
a = x;
console.log(x == a); //comes out true
Example 2:
Array.prototype.Contains = Array.prototype.Contains || function (obj) {
return this.indexOf(obj) != -1;
};
var x = function(){console.log("hello")}; var a = function(){console.log("hello")};
var z = a;
console.log(x == a); //comes out false
var l = [];
l.push(x);
//Set a as x
a = x;
l.push(a);
console.log(x == a); //comes out true
console.log(l.Contains(x)); //Should come out true
console.log(l.Contains(a)); //Should come out true
console.log(l.Contains(z)); //Should come out false
Your question isn't entirely clear to me but I'll try to answer as best I can.
Improving the function
Your function could be simplified to leverage the indexOf function.
Array.prototype.Contains = Array.prototype.Contains || function (obj) {
return this.indexOf(obj) >= 0;
};
Also I want to point out that in your implementation you're looping through everything when you could exit early by returning inside the if.
Array.prototype.Contains = Array.prototype.Contains || function (obj) {
var i;
for (i = 0; i < this.length; i += 1) {
if (this[i] === obj) {
return true;
}
}
return false;
};
x == a
I think you understand but just want to clarify, x and a are different originally because they are referencing different functions. When you set x = a they are both pointing at the function declared originally in x and are therefore the same. Even thought the functions are identical in terms of implementation, they were both constructed and then placed in different parts of memory.
When you do this:
var x = function(){console.log("hello")}; var a = function(){console.log("hello")}
x and a point to different functions. Even if you compare them for equality, they are not equal as all equality checking does here is see if they point to the same function or not - there is no attempt made to see if they would produce the same output when run or not (that is almost impossible to do in general, after all).
When you do something like x = a, x now references whatever a is referencing - the same object. So now they compare equal.
If you need to see if a function already exists in an array, I suggest instead of just placing arrays in a big list, you create a dictionary (hashmap, hashtable, whatever you want to call it) that uses strings as keys as function as values. The key would be the 'name' of a function - whenever you make that function you'd use the same name, and names in different places in memory but with the same characters in them WILL compare equal.
You're really confused. Everything in JavaScript (except for primitive data types, null and undefined) is an object, and objects are stored in variables as reference. Read the following answer to know more about the differences between the two: https://stackoverflow.com/a/13268731/783743
When you define two identical functions (in your case x and a) JavaScript sees them as separate functions. This is because in addition to the function body a function also maintains its own environment and state. Hence x and a are not the same function which is why x === a returns false.
By setting x = a you're essentially copying the reference stored in a into x. Hence they now point to the same function (which is the function a was originally referring to). The function x was originally referring to is now lost and will eventually be garbage collected. Thus x === a now returns true.
BTW you don't need to create a special Contains function to check whether an object is already inside an array. Just use indexOf:
var array = [];
function x() {}
array.indexOf(x); // returns -1
array.push(x);
array.indexOf(x); // returns 0
If the index is less than 0 the object is not in the array.
If you want to check whether the function body of two functions is the same then use this function:
function sameFunctionBody(a, b) {
return String(a) === String(b);
}
Now console.log(sameFunctionBody(x, a)) will return true as long as both the functions are exactly the same (including whitespace, parameters, function name, etc).
Related
consider the following code:
let logged = 1;
let x = {logged} //{logged: 1}
x['logged']; // 1
x['logged']['index']; //undefined
x['logged']['index'] = 0;
x; // {logged: 1}
x['logged']['index']; //undefined
So, my questions are:
isn't
x[logged]['index'] doing something like 1['index']. Shouldn't
which give something like cannot index a numeric literal kind of
error?
x[logged]['index'] = 0;, this doesn't throw any error, as if the
element is stored somewhere, but, where is this value being stored?
As shown in line 6, the value of x is still {logged: 1}. And why does it not throw error?
and why is x[logged]['index'] is still undefined?
I tested this on a nodejs terminal, with node version 14.16.0
Not sure if my comments above actually fully illuminated the issue for you.
I have written a small program that may be helpfull to visualize what happens. Note I'm doing a method lookup on a primitive value rather than a regular property lookup - but this is all just the same and allows to illustrate what happens better.
function captureThis() {
return this
}
(function setUpObjectPrototype() {
if (Object.prototype.captureThis !== undefined) throw new Error("Couldn't set up Object prototype properly.")
Object.prototype.captureThis = captureThis
process.nextTick(() => delete Object.prototype.captureThis)
})()
var number = 1
var thisObject = number.captureThis()
console.log("Is thisObject an object? " + (typeof thisObject == "object"))
console.log("Is number still just a number? " + (typeof number == "number"))
console.log("Is thisObject an instance of Number? " + (thisObject instanceof Number))
// Output
// Is thisObject an object? true
// Is number still just a number? true
// Is thisObject an instance of Number? true
Note that at no point is the number variable actually coerced to an object - a temporary object is created that wraps the value contained in the number variable. This object is never actually assigned to a variable - unless it is captured like it is in this little program.
Hopefully that helps.
This question already has answers here:
Javascript using prototype how can I set the value of "this" for a number?
(3 answers)
Closed 6 years ago.
I try to set a number directly from a prototype method.
Usually, a new value is returned.
this of a number object, is also an object. But I guess not a reference. (?)
I have this:
Number.prototype.bitSet = function(bit) {
return this | (1<<bit);
};
But want this:
Number.prototype.bitSet = function(bit) {
this.value = this | (1<<bit);
};
this.value is a pseudo property. Becuase this sould be a reference of the number and without that, you'll overwrite it. But the question is: Is this really a reference to the source number? Is it possible to do that? Assign the value directly to the number who called this method?
var num = 0;
num.bitSet(9);
console.log(num); // num = 512
Btw. chrome console prints [[PrimitiveValue]] for the number.
TL;DR - You can't do that, your initial version of bitSet is how you need to define it. You'll need to save its return value when you use it, e.g., x = x.bitSet(2). You can create your own mutable number object, though, if you like. (More on that below.)
Just for clarity (you probably know this): JavaScript has both number primitives and Number objects. Normally, you're dealing with primitives. The reason Number.prototype works is that a temporary object is created using the primitive's value when a method is called on it. Unless something explicitly saves the object, though, it's as though we were just dealing with primitives.
Numbers are not mutable in JavaScript.1 So your bitSet method cannot change the numeric value of what it's called on; instead, it has to return a new number with the changes made (e.g., your original version).
Note that even if you could change a Number object's value, you're almost never dealing with a number object in code outside functions you've assigned to Number.prototype. For instance:
Number.prototype.bitSet = function(bit) {
return this | (1<<bit);
};
var x = 32;
x = x.bitSet(2);
console.log(x); // 36
console.log(typeof x); // "number", not "object"
var o = new Number(36);
console.log(typeof o); // "object"
In the above, when x = x.bitSet(2); is executed, the number primitive is converted to a temporary Number object, your bitSet method is called, and then the result is whatever your bitSet method returns; unless bitSet does something to store this somewhere, the temporary object is then thrown away. (That's the theory; in fact, your JavaScript engine may well optimize away the object entirely, if it can determine that the code in your function only uses the number as though it were a primitive number.)
So suppose in my code above, we did something to change the state of the Number object in that x.bitSet(2) line. Since that object is temporary and not stored anywhere (unless we store it; it's not in x, x contains a primitive number), whatever we stored on the object would be lost. We can even prove that:
Number.prototype.test = function() {
this.foo = Math.random();
console.log("this.foo", this.foo); // some number
};
var x = 42;
x.test();
console.log(typeof x); // "number", not "object"
console.log("x.foo", x.foo); // undefined
this was definitely an object, we added a property to it and used that property. But x still had the primitive.
You could have your own mutable number type, though:
function MyNumber(value) {
this.value = typeof value === "number" ? value : 0;
}
MyNumber.prototype.bitSet = function(bit) {
this.value = this.value | (1 << bit);
};
MyNumber.prototype.valueOf = function() {
return this.value;
};
MyNumber.prototype.toString = function() {
return this.value.toString();
};
// Usage:
var m = new MyNumber(42);
m.bitSet(2);
console.log(String(m)); // "46"
var n = m + 5;
console.log(n); // 51
The valueOf function is called any time the JavaScript engine needs to convert your number object to a number. toString is called when the JavaScript engine needs to convert your number object to a string.
Or in ES2015:
class MyNumber {
constructor(value) {
this.value = typeof value === "number" ? value : 0;
}
bitSet(bit) {
this.value = this.value | (1 << bit);
}
valueOf() {
return this.value;
}
toString() {
return this.value.toString();
}
}
// Usage:
var m = new MyNumber(42);
m.bitSet(2);
console.log(String(m)); // "46"
var n = m + 5;
console.log(n); // 51
1 "Numbers are not mutable in JavaScript" Technically, that's not true. Primitive numbers are not mutable, but Number objects are — but their underlying numeric value (what the spec calls its [[NumberData]]) cannot be changed. (Number objects can have other properties with state that can be changed, just not their numeric value.) So "Numbers are not mutable in JavaScript" is a reasonable shorthand statement, if not perfectly correct.
I have this:
var g = [{a:'a'},{a:'2'},{a:'3'}]
var c = [{a:'4'},{a:'2'},{a:'5'}]
The following statement:
g[1] == c[1]
Returns false, even though the objects look the same. Is there any way I can compare them literally so it will return me true instead of false?
You could encode them as JSON:
JSON.stringify(g[1]) == JSON.stringify(c[1])
You might also be interested in the answers to this related question on identifying duplicate Javascript objects.
For a more complex option, you might look at the annotated source code for Underscore's _.isEqual() function (or just use the library).
The == operator checks for reference equality. The only way to do what you want would be a memberwise equality test on the objects.
This ought to work:
function memberwiseEqual(a, b) {
if(a instanceof Object && b instanceof Object) {
for(key in a)
if(memberwiseEqual(a[key], b[key]))
return true;
return false;
}
else
return a == b;
}
Be wary of cases like these:
var a = {};
a.inner = a; //recursive structure!
here you compare the reference in the memory ,not its value try this and you will get true :
g[1]['a'] === c[1]['a']
In JavaScript variables which are objects (including arrays) are actually references to the collection. So when you write var x = { a: 2 } and var y = { a: 2 } then x and y become references to two different objects. So x will not equal y. But, if you did y = x then they would (because they would share the same reference). But then if you altered either object the other would be altered too.
So, when dealing with objects and arrays, by saying == you are checking if the two references are the same. In this case they are not.
This is so simple I am baffled. I have the following:
var x = 'shrimp';
var stypes = new Array('shrimp', 'crabs', 'oysters', 'fin_fish', 'crawfish', 'alligator');
for (t in stypes) {
if (stypes[t] != x) {
alert(stypes[t]);
}
}
Once the values have iterated it starts returning a dozen functions like
function (iterator, context) {
var index = 0;
iterator = iterator.bind(context);
try {
this._each(function (value) {iterator(value, index++);});
} catch (e) {
if (e != $break) {
throw e;
}
}
return this;
}
What the heck is going on?
Edit: In these scripts I am using http://script.aculo.us/prototype.js and http://script.aculo.us/scriptaculous.js I remember now reading about the way prototype extends arrays and I am betting this is part of it. How do I deal with it?
The for enumeration is going to go over every member of the object you passed it. In this case an array, which happens to have functions as members as well as the elements passed.
You could re-write your for loop to check if typeof stypes[t] == "function" or yada yada. But IMO you are better off just modifying your looping to only elements..
for(var i = 0, t; t = stypes[i]; ++i){
if (t != x) {
alert(t);
}
}
Or
for(var i = 0; i < stypes.length; ++i){
if (stypes[i] != x) {
alert(stypes[i]);
}
}
I wanted to migrate my last comment up to the answer to add the notice of the a caveat for the first type of loop.
from Simon Willison's "A re-introduction to JavaScript"..
for (var i = 0, item; item = a[i]; i++) {
// Do something with item
}
Here we are setting up two variables.
The assignment in the middle part of
the for loop is also tested for
truthfulness - if it succeeds, the
loop continues. Since i is incremented
each time, items from the array will
be assigned to item in sequential
order. The loop stops when a "falsy"
item is found (such as undefined).
Note that this trick should only be
used for arrays which you know do not
contain "falsy" values (arrays of
objects or DOM nodes for example). If
you are iterating over numeric data
that might include a 0 or string data
that might include the empty string
you should use the i, j idiom instead.
you want to do:
for (var i in object) {
if (!object.hasOwnProperty(i))
continue;
... do stuff ...
}
As for..in enumeration iterates over all properties (enumerable or otherwise) that exist on both the object and its prototype chain. The hasOwnProperty check restricts iteration to just those properties on the actual object you want to enumerate.
ES5 makes things a little better for library developers (and help avoid this stuff) but we won't see that ina shipping browser for quite a while :-(
[edit: replacing return with continue. lalalalala ;) ]
Since prototype has extended the array for your convenience you should take advantage of it. Your example could be rewritten as:
var x = 'shrimp';
var stypes = new Array('shrimp', 'crabs', 'oysters', 'fin_fish', 'crawfish', 'alligator');
stypes.without(x).each(alert);
It should be
for (t in stypes) {
if (t != x) {
alert(t);
}
}
This question already has answers here:
how do I compare 2 functions in javascript
(6 answers)
Closed 6 years ago.
how to compare two static functions in javascript equal or not equal?
String(f1) === String(f2)
var f1 = f2 = function( a ){ return a; };
here, you can use f1 === f2 because they're pointing to the same memory and they're the same type
var f1 = function( a ){ return a; },
f2 = function( a ){ return a; };
here you can use that byte-saver Andy E used (which is implicitly converting the function to it's body's text as a String),
''+f1 == ''+f2.
this is the gist of what is happening behind the scences:
f1.toString( ) == f2.toString( )
Edit: Looking back on this post over a year after, I agree with #kangax - you should probably never do this.
Whenever I need to compare functions I make sure there is no scope ambiguity and use the same function object.
Say I have some a pair of library functions that take a callback as one of the parameters. For the sake of this example create1minuteCallback function will set a 1 minute timer and call the callback on each tick. kill1minuteCallback will turn off the callback and you must pass the same callback function as you did for create1minuteCallback.
function create1minuteCallback(callback){
//implementation
}
function kill1minuteCallback(callback){
//implementation
}
Quite clearly this will not work as the function we are passing is different on the second line:
create1minuteCallback(function(){alert("1 minute callback is called");});
kill1minuteCallback(function(){alert("1 minute callback is called");});
I normally do this:
function callbackFunc(){alert("1 minute callback is called");}
create1minuteCallback(callbackFunc);
kill1minuteCallback(callbackFunc);
Well, as simply as that - if you are going to compare functions, you do it for a reason I assume. What is your reason?
My reason was to not run a certain function twice.
I did it this way (just snippet code to get the idea)
var x = function(){
console.error("i am a functionX");
}
var y = function(){
console.error("i am a functionX");
}
var z = function(){
console.error("i am a functionZ");
}
var x2= x;
var obj = new Object();
obj[x] = "";
obj[x2] = "";
obj[y] = "";
obj[z] = "";
obj.abc = "xaxa";
for (prop in obj) {
if (obj.hasOwnProperty(prop)) {
console.error(obj[prop] + " hello " + prop);
}
}
Function x and y are the same, even though they have different whitespaces. x and y are not the same as z, since z has a different console.error.
Btw open your firebug console to see it in the jsbin example