The following is unintuitive behavior in javascript,
function function1 () {};
function function2 () {};
var class_a_functions = {function1:true, function2:true};
var contained = function1 in class_a_functions;//false
var equals = function1.name in class_a_functions;//true
Why does the in containment test fail even though I have inserted the functions, not their names, into the dictionary?
EDIT:
If it isn't obvious, I am aware that function1.name is "function1". This is why I asked why the test fails "even though I have inserted the functions, not their names".
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/in
// Arrays
var trees = new Array("redwood", "bay", "cedar", "oak", "maple");
0 in trees // returns true
3 in trees // returns true
6 in trees // returns false cause there's no 6th key in trees Array
"bay" in trees // returns false (you must specify the
// index number, not the value at that index)
"length" in trees // returns true (length is an Array property)
That's why it returns false
On the other case, class_a_functions[0] is the reference to the stored function in Array that's why equality returns true cause fn1() === fn1()
Now after your edited question the above seems like nonsense so I'll answer further:
var class_a_functions = {function1:true, function2:true};
Is now and object where function1 and function2 are simple Properties holding true as Value.
var contained = function1 in class_a_functions;//false
The above returns false cause there's no "function1" Function inside the Object reference class_a_functions
var equals = function1.name in class_a_functions;//true
The above... well, let's go back to MDN, says:
Summary:
The in operator returns true if the specified property
is in the specified object.
So you have a property of function1 Now let's see if is present in the Object class_a_functions ... Yes. So TRUE
I'm not sure why most of the answers are so trivial and don't really address the underlying issue motivating the question, which is that getting the memory address/object hash/object id in javascipt is "impossible", and therefore the equality testing by object reference is also "impossible".
How can I get the memory address of a JavaScript variable?
A solution for that containment problem is to monkey-patch an object to contain a unique property/string that can be used as a key.
The in is used to identify the key not the value.
The in operator tests if a property is in an object. function1 is not a property of the array, it's a member.
There should be
'function1' in class_a_functions;//true
This is because
In a dictionary
obj = {key:5}
this is equal to
obj = {"key":5} // so it will be stored as string
If you will see the docs it says prop is A string or numeric expression representing a property name or array index.
Related
According to the MDN document. the in operator can check whether a specified value is in a specified object.
The in operator returns true if the specified property is in the specified object or its prototype chain
I have the below code:
var array = [1.1,2.1];
var status = 1.1 in array;
console.log(status);
the output is false. However, I expect to get the true instead.
another code:
var array = [1,2];
var status = 1 in array;
console.log(status);
the output is true.
Question
why integer can work well with the in operator and the floating numbers can't?
what is the working mechanism of the in operator?
According to the MDN document. the in operator can check whether a specified value is in a specified object
No. It says property, not value.
There is no array[1.1]. The members of the array have integer property names (0 and 1 for an array of length 2).
e.g.
var array = [1.1, 2.1];
console.log("length" in array, array.length);
console.log(0 in array, array[0]);
console.log("find" in array, array.find);
// And it works perfectly well for floats if there is a matching property to find
var object = { "1.1": "hello, world" };
console.log(1.1 in object, object[1.1]);
Use the includes method to test for the presence of a value in an array.
You can use the find function.
The find() method returns the value of the first element in the provided array that satisfies the provided testing function. Otherwise it returns undefined
const array = [1.1,2.1];
const status = array.find(element => element == 1.1);
console.log(status);
Arrays are quite something in JavaScript when compared with other programming languages and it's not without its full set of quirks.
Including this one:
// Making a normal array.
var normalArray = [];
normalArray.length = 0;
normalArray.push(1);
normalArray[1] = 2;
normalArray; // returns [1, 2]
normalArray.length // returns 2
So yes, the above is how we all know to make arrays and fill them with elements, right? (ignore the normalArray.length = 0 part for now)
But why is it that when the same sequence is applied on an object that's not purely an array, it looks a bit different and its length property is off by a bit?
// Making an object that inherits from the array prototype (i.e.: custom array)
var customArray = new (function MyArray() {
this.__proto__ = Object.create(Array.prototype);
return this
});
customArray.length = 0;
customArray.push(1);
customArray[1] = 2;
customArray; // returns [1, 1: 2]
customArray.length // returns 1
Not entirely sure what's going on here but some explanation will be much appreciated.
This may not be the perfect answer, but according to my understanding of Javascript arrays, they are a little bit different than usual objects. (Mainly due to the fact that it maintains a length property, and Objects don't).
So if we take your code for an example:
var normalArray = [];
This is the right way to create an array in Javascript. But what about the below one?
var customArray = new (function MyArray() {
this.__proto__ = Object.create(Array.prototype);
return this
});
Are they same? Let's see..
Array.isArray(normalArray); // true -> [object Array]
Array.isArray(customArray); // false -> [object Object]
So it is clear that although you inherit from the array prototype, it doesn't really create an object with Array type. It just creates a plain JS object, but with the inherited array functions. That's the reason why it updates the length when you set the value with customArray.push(1);.
But since your customArray is only a regular object and for a regular JS object, [] notation is used to set a property, it doesn't update the length (because Objects don't have a length property)
Hope it's clear :)
The array you are trying to create is not a pure array (as you are perhaps aware). Its basically a JavaScript object and is supposed to behave like an object.
While treating an object like an array, its up to you to maintain all it's array like features.
You specifically have to assign a length property to it and you did it correctly.
Next, the push method from Array.prototype is supposed to insert an element to the array and increment the length property (if any), so it did increment 0 to 1. There you go, the length now is 1.
Next you used the literal notation of property assignment to Object, which is similar to something like customArray['someProperty'] = 1.
While using literal notation, no method from Array.Prototype is being invoked and hence the customArray object never knows that it has to behave like an Array and its length property remains unaffected. It simply behaves like an object and you get what you got.
Remember the length is just a property on Array class and this property is appropriately incremented and decremented by every method on Array.
Note: Array like objects are not recommended and its up to you entirely to maintain the index and other Array stuff for such objects.
From what I can see, you have a problem with your function:
return this
This should be
return (this);
Just fixes any potential errors you might have. Another thing is you're not using the var keyword to declare customArray. These errors might be breaking your code.
I'm a hobby programmer, I've studied several languages and almost always find that 'length' is a method/function. I've been trained, from what I can tell, that any method call must be called with a parenthesis after, even with no arguments.
Not so in Javascript.... Why?
C# .length()
ROR .lenth()
etc...
In Javascript it's a property, not a function.
In languages like C where the length function has to loop through the entire string to find the end, it's logical to have it as a function (as it does some work). In languages where the length is kept as a separate value, it's logical to have it as a property instead (as it only reads an already existing value).
It's because it's a property, not a function.
You can find the relevant documentation here at MDN.
This property returns the number of code units in the string.
The name length is a property not a function. A property can be accessed by name while a function must be invoked with () and possibly arguments to produce a value.
For example
var x = {};
x.name = "example"; // Property
console.log(x.name); // Prints "example"
x.getName = function() { return "example"; } // Function
console.log(x.getName); // Doesn't print what you'd want here
console.log(x.getName()); // Prints "example"
In JavaScript, .length is a property of the array, not a function of the prototype. Imagine your array is represented like this:
array {
data: [ ... ],
length: 4 // 4 elements
}
This is obviously nonsense, but the point is that .length is a property of the array object, not a function of it, so it doesn't need trailing brackets.
Because its a known value on the object (a property) and not a function that needs to be evaluated.
In JavaScript, .length is a property and behaves as one:
var a = [1, 2, 3, 4, 5];
console.log(a.length); // returns 5
a.length = 3;
console.log(a.join(",")); // returns "1,2,3"
http://jsfiddle.net/GD89N/
Notice you can not only read, but also write the value of the property.
By the way, In C#, usually .Length or .Count are properties, not methods:
String.Length
Array.Length
List<T>.Count
Linq exposes a Count() method to IEnumerable<T>, but that's a relatively new addition.
There are many languages where properties can be backed by method calls including JavaScript. It is up to the implementors to decide how it will be implemented.
You can have your own properties backed by functions. I've already answered a similar question before, so won't repeat it here.
Ruby also does not require parentheses after a method call. This is valid Ruby code
[].size // size is an Array method
object.x = 42; // x= is a method (setter)
Python also also has the concept of function backed properties. Here's an example in Python:
class Foo(object):
def __init__(self):
self._x = None
#property
def x(self):
print "getter called"
return self._x
#x.setter
def x(self, value):
print "setter called"
self._x = value
f = Foo()
f.x = "20"
setter called
f.x
getter called
Parentheses is just syntax and has traditionally been used for function/method calls, but it's not a universal standard by any means.
Are there any pitfalls to code like this?
var Foo = function() {
this.bar = function() { return 'bar'; };
};
var f = new Foo();
f[0] = 'hi';
f[1] = 'there';
Note that I'm creating a new function object with some misc properties, and then I'm treating the object like an array. Also how are the array values being stored in the object? Are 0 and 1 treated like property names?
Well, yes, 0, and 1 will be just two property names.
When you assign a property with the bracket notation, the expression between the brackets will be converted to String, and that string will be used as the property name.
In fact, even the indexes for real arrays are just that, properties:
var realArray = ['a'];
realArray.hasOwnProperty('0'); // true
The difference is that real array objects on every property assignment that correspond to a valid index[1], track internally the value of their length property.
That's one of the reasons why "subclassing" array objects is difficult, even with the new ECMAScript 5 extensions, or at the moment also with the proposed ECMAScript-Harmony Proxies 2 3, can't be completely done, in a stanard way.
That can be a problem, depending on how you plan to iterate the numeric properties.
If you enumerate the properties with the for-in statement, other members will appear, not just the numeric properties.
[1] A valid array index is any unsigned 32-bit integer in the range of 0 to (2^32)-1.
I think you might have problems if you try to loop through that with a for in loop; the loop will also get bar. There are ways around this, so you just have to be careful.
If you want to extend Array behavious please use : Array.prototype.yourfunc = function()....
While reading a book about JavaScript I stumbled across an example:
var names = new Array("Paul","Catherine","Steve");
var ages = new Array(31,29,34);
var concatArray;
concatArray = names.concat(ages);
My question is, why doesn't the variable concatArray need to be define as a new Array() in order to store the concatenated data for both arrays name and ages , but when I try to treat the concatArray as an array by adding another line of code "document.write(concatArray[0])", it works just like an array and shows me the data stored in the first element. I just wonder why I'm not declaring the concatArray as a new array, yet it still works as one.
You are declaring concatArray as a new array but the declaration is implicit. The concat function returns a new array which contains concatenated copies of the original two arrays. The type of concatArray is inferred from the return type of the concat function.
Variable don’t have a specific data type in Javascript like in other languages. You can assign a variable every value you want.
That means var concatArray; declares the variable but the value is undefined:
var concatArray;
alert(typeof concatArray === "undefined");
Only when assigning the return value of names.concat(ages) (an array) to concatArray it get’s that type:
var names = new Array("Paul","Catherine","Steve");
var ages = new Array(31,29,34);
var concatArray;
alert(typeof concatArray === "undefined");
concatArray = names.concat(ages);
alert(concatArray.constructor === Array);
Javascript doesn't care what the contents of the var are when it is declared; that is why you can declare var concatArray without needing to specify it as an array. Once you assign it a value and a type (as the result of the concat() function) javascript treats the var as an array.
Simply put, w3schools says it pretty concisely:
The concat() method is used to join two or more arrays.
This method does not change the existing arrays, it only returns a copy of the joined arrays.
w3schools
Looks like Andrew and Matthew beat me to it anyway.
Because Javascript is dynamically typed. A variable doesn't have a specifuc type, and an array is an object that you can assign to any variable.
When you declare a variable without assigning it a value, it just exists with an undefined value:
var answer;
// now the variable exists, but it doesn't have a value
answer = 42;
// now the variable has the numerical value 42
answer = "hello";
// now the numerical value has been replaced with the string value "hello"
answer = [];
// now the variable contains an empty array
answer[0] = 1337;
// now the variable contains an array that contains an item with the value 1337
answer = -1
// now the array is gone and the variable contains the value -1
I would make an answer slightly different of Andrew's one.
JavaScript variables are not strongly typed. You can put a string, then a number, then an object in the same variable. When you use the variable, the interpreter checks its current type is suitable for the usage you try to make. If you write:
var a = 45;
alert(a[0]);
a = [ 5 ];
alert(a[0]);
you will get successively undefined then 5.