following the snippet bellow, why an array with one position is not working properly when using IN operation?
You can see that with 2 item the operation works fine.
Why this is happening?
What's the work around?
// helper function
function showResult(result) {
document.querySelector('#result').innerHTML += result+'<br/>';
}
var a = ["1"]
var b = "1"
showResult(b in a);
//false
var a = ["1","2"]
var b = "1"
showResult(b in a);
//true
<div id="result"></div>
That's not what in is for. in is not for searching an array for an element. It's for searching an object for a key.
Example:
var x = {a: 1, b: 2};
console.log('a' in x); // true
Your 2nd example works because the array (object) a contains a key called 1.
The in operator checks if an object has a key, not a value. Your second case returns true because any array with two elements has keys '0' and '1'. It doesn't matter that '1' also happens to be a value in that array; '1' in ['foo', 'bar'] is also true.
To test if an element is in an array, you should use Array.prototype.indexOf or in modern engines Array.prototype.includes. You can use the polyfill from either of those links to get support for that method in all engines:
// Most engines (IE 9+)
showResult( a.indexOf( b ) >= 0 );
// Modern engines only:
showResult( a.includes( b ) );
The first result is false because a does not have an index 1, while the second version of a has that index.
The in operator is not about affirming values, but properties (keys).
The confusion is maybe because CoffeeScript does use in for searching values. See here how it translates that into an indexOf
Related
When I use a for ... in loop like:
for(var i in object) {}
I want to know if the object in question is evaluated just once or each time the loop, well, loops.
I made a quick test in my browser (also in node) like:
for(var i in (console.log('INIT'), [1, 2, 3, 4])) { console.log('KEY', i); }
and I get:
INIT
KEY 0
KEY 1
KEY 2
KEY 3
So from this empirical evidence, I could assume that is indeed only evaluated once.
But, is this behavior standard?
From the Mozilla documentation, a for...in loop will iterate over all enumerable properties of the object itself and those the object inherits from its constructor's prototype. An (enumerable) property that is deleted before it has been visited will not be visited later. Properties added to the object over which iteration is occurring may either be visited or omitted from iteration.
In short, the outcome of the example posted by #Amit is not guaranteed, although Chrome and IE may use a different specification for the for ..in loop. However, at least deleting an element seems to prevent it from being visited in Chrome:
var obj = { a: 1, b: 2, c: 3 };
for(var k in obj) {
document.write(k);
delete obj['c'];
}
Bear in mind that (console.log('INIT'), [1, 2, 3, 4]) is an expression that evaluates to [1, 2, 3, 4] so it's not a valid evidence of the issue. A better empirical evidence can be obtained with:
var obj = { a: 1, b: 2, c: 3 };
for(var k in obj) {
document.write(k);
obj.d = 4;
}
And we don't see "d"...
The ECMAScript® Language Specification, section 12.6.4 does not say much about this, except that the expression on the right side is evaluated once and cast to an object:
Let exprRef be the result of evaluating the Expression.
Let experValue be GetValue(exprRef).
If experValue is null or undefined, return (normal, empty, empty).
Let obj be ToObject(experValue).
This says nothing about evaluating any of the keys or values of that object at that time.
In fact, the part that follows the quoted paragraph suggests the keys could be retrieved during the iterations:
Repeat
Let P be the name of the next property of obj whose [[Enumerable]] attribute is true. If there is no such property, return (normal, V, empty).
But there is no requirement in either direction. So, ... this could be implementation (browser) dependent.
When you say that the object is evaluated just once, that can be have different meanings:
The object reference is evaluated just once. This is important when that object is the outcome of an expression, such as a function call. But this is surely taken for granted and not what you mean;
The object's keys (properties) are enumerated once, but the values are retrieved on demand;
The object's keys and values are retrieved once. This could be done at 1 level or nested levels at a potential high memory cost.
This test case shows in my browser (FireFox) the second happens, not the third:
var obj = {a: 1, b: 2, c: 3};
for (key in obj) {
document.write('obj[' + key + '] = ' + obj[key] + '<br>');
if (key=='a') {
// modify a value that is still to be visited
obj["c"] = 4;
// add a key/value pair
obj["d"] = 9;
}
}
Output is (as you can probably also see in your browser):
obj[a] = 1
obj[b] = 2
obj[c] = 4
So the keys were only retrieved once, the values on demand (i.e. not at the start of the loop).
I'm working on an open source project and stumbled over bitwise operators. I do understand the principles and also that javascript evaluates non-zero integer values to true (correct me here if I'm wrong; found this statement in an accepted answer in another post).
The code in question is as follows:
function example(){
var args = arguments;
var j = 1 & args[0];
.
.
.
}
var test = {keyA: 1, keyB: 2};
example(test);
My Question is: What's the value of j?
What is the binary equivalent of an object?
As far as i understand it, j = 0 if the last bit in test is 0 and j = 1if the last bit in testis 1.
Please help me out here guys. I spend the last hour searching any nearly related post here and most topics are about numbers, one or two were about booleans and that's that.
Edit:
As the code example given above doesn't seem to be as clear as i thought, here the full function as i found it (and working):
function Extend() {
var args = arguments;
var target;
var options;
var propName;
var propValue;
var deep = 1 & args[0];
var i = 1 + deep;
target = args[i - 1] || {};
for (; i < args.length; i++) {
// Only deal with non-null/undefined values
if (options = args[i]) {
// Extend the base object
for (propName in options) {
propValue = options[propName];
if (propValue !== undefined) {
propValue = options[propName];
target[propName] = (deep && IsPlainObject(target[propName])) ? Extend(deep, {}, propValue) : propValue;
}
}
}
}
// Return the modified object
return target;
}
var _someVariable = Extend({keyA: 1, keyB: 2, keyC: 10}, _someOtherVariable);
deephas to have some meaning as it determines whether to enter the FOR-loop ... or not.
The intent of the deep variable is to detect the difference between these two calls:
Extend({keyA: {a: 1}, keyB: 2}, {keyC: 3, keyA: {b: 2}});
and
Extend(true, {keyA: {a: 1}, keyB: 2}, {keyC: 3, keyA: {b: 2}});
The first variant will return this:
{keyA: {b: 2}, keyB: 2, keyC: 3}
The second is intended to return this:
{keyA: {a: 1, b: 2}, keyB: 2, keyC: 3}
So the function in fact allows for a first, optional argument, that will make the function apply the extension recursively so you get a deep instead of a shallow extended object.
You can also see this intent by analysing the recursive call, where the first argument is deep, the second is the object to extend, and the third the object to extend with.
The following line also shows this:
var i = 1 + deep;
As i is point where the loop will start from, you can see that if deep is set to 1 instead of 0, the loop will start processing from argument #2 onwards, which makes sense, as argument #0 was recognised as being the optional argument, and the next one is the target object.
Note that the function accepts a variable number of additional arguments which it will use to extend the target object with. It is over these arguments that the i variable loops.
As a side note: because of a bug, the second version returns the same as the first. To fix the bug, replace
target[propName] = (deep && IsPlainObject(target[propName]))
? Extend(deep, {}, propValue) : propValue;
with:
target[propName] = (deep && IsPlainObject(target[propName]))
? Extend(deep, target[propName], propValue) : propValue;
Now, coming to the essence:
var deep = 1 & args[0];
The use of the bitwise operator must have been an idea to have efficiency rule over clarity. The intent was to set deep to 1 if the first argument represented the optional argument, which should be a boolean indicating whether the extending should happen shallow or deep. As objects will make this expression evaluate to 0, it seemed like a nice trick.
But there is an issue with this. If one would like to do this:
Extend(["3"], {myattr: 2});
One would expect to get back an array-like object with an additional custom property myattr:
{0: "3", length: 1, myattr: 2}
However, the current Extend function will misinterpret the first argument as an instruction to perform a deep extension. This is because
1 & ["3"] will evaluate to 1 & 3, which evaluates to 1. And so the result will be the second argument without any extension happening:
{myattr: 2}
Conclusion: it is better to avoid such cryptic use of bitwise operators, and do something like this:
var deep = args.length > 0 && typeof args[0] === 'boolean' && args[0];
In common language: let deep be true (1) when there is at least one argument and that argument is a boolean and its value is true. In all other cases let it be false (0).
Note that one cannot pass false as the first argument, thinking that it will make the function perform a shallow extension. In this case,
that argument will be taken as the object to extend, which will fail. So the optional first argument, if provided, must be a boolean with value true.
This is true both for the original Extend function and the corrected one.
Finally, it would be good to add comments to this function to clarify the use of the first optional argument.
Bitwise operators do work on 32bit (un)signed integers. If you pass in anything that is not a number, it is implicitly coerced to a number. This is done using the valueOf/toString methods of the object as usual, and for your object {keyA: 1, keyB:2} will yield NaN. Then, this number is casted to an (U)int32, which gives 0 for NaN.
Check the spec for toUint32, follow it to ToNumber and on from there.
I have built an example using a couple of js classes for declaring Flag Enum and Flag Selections.
The source code is here in my github repo.
Basically to answer the question, and as mentioned by #Bergi, your class should implement valueOf() to return the value of the 'selections'.
// Example:
_w.Feature = new FlagEnum("Feature", {
CUSTOMER : "customer info" // 2
, ORDER : "order details" // 4
, DELIVERY : "delivery details" // 8
, DELIVERY_LIST : "listing of all deliveries" // 16
, DRIVER : "driver details" // 32
})
let [CUSTOMER, ORDER, DELIVERY, DELIVERY_LIST, DRIVER] = Feature.get_values()
features = new FlagSel(Feature, CUSTOMER | ORDER | DELIVERY)
// -or-
features = new FlagSel(Feature, [CUSTOMER, ORDER, DELIVERY])
// Using in code
// Check feature using bitwise mask:
if (features & ORDER){
pc("features includes ORDER")
}
// -or-
// Check feature using has method:
if (features.has(ORDER)){
pc("features includes ORDER")
}
// Managing values:
features.add(CUSTOMER)
features.rem(ORDER)
// Print available options
console.log(Feature)
// output: <FlagEnum - Feature> options: CUSTOMER, ORDER, DELIVERY, DELIVERY_LIST, DRIVER
// Print selected options
console.log(features)
// output: <FlagSel - Feature> CUSTOMER, ORDER, DELIVERY
Please help me out to understand this example.
function fun(a){
this.length = 1;
this.splice = [].splice;
this[0] = a;
return this;
};
Now, when I execute this function the result is an array.
f = new fun('hi');// result will be : ["hi"]
Why is that?
If I remove this.length=1 OR this.splice = [].splice, the result will be different.
f = new fun('hi'); // result will be : fun {0: "a", splice: function}
Why is that?
I also see this technique used in jQuery. Please describe to me how this is working programmatically.
There is nothing programmatical about it. It's just the way a browser/js engine chooses to show you some variable in the console.
The console is generally for developers as they are the ones who open those things. So the browser does a little sniffing to show the developer what this object he's/she's dealing with is. If it looks like an array, it probably should be printed like an array.
Like the following list shows, there are some differences between the browsers. Namely, IE and node do nothing. My interpretation is that printing in node should yield the complete view and not just the sniffed view. The length seems to satisfy Opera 12 to show it as an array.
Why browsers use index, length and splice is an entirely different story. It's probably the smallest set of properties that denote an array with high probability. Look at it, what else would it be, if not an array?
Chrome 36, Firefox 30 and Opera 18 behave the same way:
fun as-is is ["hi"]
fun without length is fun { 0: 'hi', splice: function}
fun without splice is fun { 0: 'hi', length: 1}
Opera 12 shows:
fun as-is is Object ["hi"]
fun without length is Object
fun without splice is Object ["hi"]
IE 9 and node v0.8 did no sniffing at all (here IE output, node output very similar):
fun as-is is {0 : "hi", length : 1, splice : function splice() { [native code] }}
fun without length is {0 : "hi", splice : function splice() { [native code] }}
fun without splice is {0 : "hi", length : 1}
What you construct is not an array. I believe that your object may have a few features that let console recognize whether a given object is an array or not.
var arr = [];
var f = new fun('asd');
typeof arr; // "object"
typeof f; // "object"
arr instanceof Array; // "true"
f instanceof Array; // "false"
I'm not sure, how you can get that only "hi" result, because when I tried below code in a Fiddle, I get Object { 0: "hi", length: 1, splice: splice() }. Which is make sense because what it does is creating an object which has 3 attributes(length, splice, and index[0]).
function fun(a){
this.length = 1;
this.splice = [].splice;
this[0] = 'hi';
return this;
}
f = new fun('hi');
console.log(f); //get the object f
console.log(f[0]); //get the string inside index-0
console.log(f.length); //get the length value which is already assigned before
console.log(f.splice); //it returns a function, which I believe a splice function
Can some one please explain to me in a layman's what is happening in the loop as it iterates to produce the statement (the objects properties are in an array).
var o = {x:1, y:2, z:3};
var a = [], i = 0;
for (a[i++] in o)
{
console.log(o);
}
This is how the for/in loop is evaluated:
for each property in object o
assign the property name to the left hand side, that is a[i++]
Initially i = 0, so:
a[0] will get x. // notice it gets the property name, not its value
a[1] will get y.
a[2] will get z.
NOTE: i++ is equal to i = i + 1.
The previous code is equivalent to the following:
var o = {x:1, y:2, z:3};
var a = []
var i = 0;
for (propertyName in o)
{
a[i] = propertyName;
i = i + 1;
console.log(o);
}
It assigns an object with three keys (x,y,z) to o. It assigns an empty array to a, and the number 0 to i.
The for ( in ) loop will iterate over an object's properties, but first the condition is evaluated.
i++ is evaluated first. The ++ is a post-increment operator and is notorious for people getting the damn thing wrong. Douglass Crockford (search for him) suggests not using it. It returns the value stored in i (which was 0) then increments it.
So now i is storing 1, and we're evaluating a[0], which is accessing an element in an array, except... that array is empty (we're accessing an undefined value).
It now looks at in o, which iterates through the keys in o, which there are 3 of. Thus, it iterates the loop three times. Each time it then logs the object to the console.
Whatever this code is, I'd suggest replacing it. It shouldn't be something you want to see in code. It's confusing and surely doesn't do anything meaningful.
Having an object like this:
var a = {
b: "string",
c: function(){
return "i return a string";
}
}
Doing
for (var key in a) {
console.log(typeof key);
};
Returns "string", "string" since b is a string and c returns a string.
Is there afunction that returns c -> function?
Returns "string", "string" since b is a string and c returns a string.
No. The reason it returns string, is that the attribute name b and the attribute name c are both strings; you're iterating over the keys of the object, not their values right now.
You could introduce attribute d, which was a function which returned a number or boolean, and you'd still get string.
Instead, enumerate over the values themselves;
for (var x in a) {
console.log(typeof a[x] );
};
If you want to see the type of the property instead of its key, should use the value together with the typeof operator.
for (var key in a) {
console.log(typeof a[key] );
};
Basically you will always get strings by iterating trough the keys of your object since they are represented as such.
But if you for example do console.log(typeof a[key]); Then you will get the expected output.
Change to:
for (var key in a) {
console.log(typeof a[key]);
};​
Live DEMO
console.log(typeof key); // gives you the key - "c"
console.log(typeof a[key]); // gives you the value of the "c" key - function.
Let me explain this little bit, so it's easy to understand to anyone. (its my first post here anyway.)
Try the following code, it says its a function.
console.log(typeof(a.c))
But what you have written is reading the property names. Try the following code to understand what's wrong with your code.
for (var key in a) {
console.log(key);
};
So basically what you are getting is correct. Because all property names are string.
Remember JSON objects have several restrictions, such as case sensitive, full path needed to traverse to properties etc..
Change your code as follows to get the typeof your properties,
Solution 1:
console.log(typeof(a[key]));
Solution 2:
console.log(typeof(eval('a.'+ key)));