Is it a standard way to assign to multiple variables from an array in JavaScript?
In Firefox and Opera, you can do:
var [key, value] = "key:value".split(":");
alert(key + "=" + value); // will alert "key = value";
But it doesn't work in IE8 or Google Chrome.
Does anyone know a nice way to do this in other browsers without a tmp variable?
var tmp = "key:value".split(":");
var key=tmp[0], value=tmp[1];
Is this something that will come in an upcoming JavaScript version, or just custom implementation in FF and Opera?
Destructuring assignment was standardized in ECMAScript 2015 (a.k.a. ES6). But not all browsers have implemented destructuring yet (as of March 2016), and even when they do it will take a while before users update to a browser with support. See examples in the spec for all the awesome things you can do. Here are some:
// Assign from array elements
var [key, value] = "key:value".split(":");
// key => 'key'
// value => 'value'
// Assign from object properties
var {name: a, age: b} = {name: 'Peter', age: 5};
// a => 'Peter'
// b => 5
// Swap
[a, b] = [b, a]
// a => 5
// b => 'Peter'
Because this feature breaks backwards compatibility, you'll need to transpile the code to make it work in all browsers. Many of the existing transpilers support destructuring. Babel is a very popular transpiler. See Kangax´s table of browser and transpiler ES6-support.
More info:
Compatibility table for ES6 browser support
Exploring ES6 - Destructuring chapter
If you want to know what's coming, read the section on Destructuring Assignment.
https://developer.mozilla.org/en/New_in_javascript_1.7
What language features you can use is always dependent on your environment.
Developing for Mobile Safari (or a web stack for other browsers like the Palm Pre, Android, etc.) or AIR, for example, is more predictable than developing for the web at large (where you still have to take even IE6 into account).
A cross-browser solution to the problem at hand would be to initialize an array that had a list of the variables you want to fill in window.variable format, then just loop through. Can't imagine why you'd do it though. Seems like there would always be a better solution.
Use destructuring assignment, a feature of ES6:
var [x, y] = [1, 2];
console.log(x, y); // 1 2
I just had exactly same question, and as an exercise for myself came up with the following:
var key, value;
(function(arr){
key=arr[0];
value=arr[1];
})("key:value".split(":"));
alert(key + "=" + value);
Looks ugly to me, I'd rather use temp var (technically, I'm using here a temp variable anyway).
Edit: chrome supports that now. As for IE8: do we still care about it?
I don't think this is possible in a cross browser way. The best that I know which might help in a few circumstances is this:
// we'll pretend you don't need the key.
var value = "key:value".split(":")[1];
I think it should be a part of the new spec., then again it's a long read... :p
key = "key:value".split(":")[0];
value = "key:value".split(":")[1];
Only alternative I can think off.
I don't know how you are using this, but if I was able to determine my own format for the "key:value" string, I'd be tempted to use json to just eval the string into the necessary object:
var obj = eval("{'key':'key_str', 'value':'val_str'}");
alert(obj.key + "=" + ojb.value); //alerts "key_str=value_str
Related
I am wondering if JavaScript has an enhanced for loop syntax that allows you to iterate over arrays. For example, in Java, you can simply do the following:
String[] array = "hello there my friend".split(" ");
for (String s : array){
System.out.println(s);
}
output is:
hello
there
my
friend
Is there a way to do this in JavaScript? Or do I have to use array.length and use standard for loop syntax as below?
var array = "hello there my friend".split(" ");
for (i=0;i<array.length;i++){
document.write(array[i]);
}
JavaScript has a foreach-style loop (for (x in a)), but it is extremely bad coding practice to use it on an Array. Basically, the array.length approach is correct. There is also a a.forEach(fn) method in newer JavaScripts you can use, but it is not guaranteed to be present in all browsers - and it's slower than the array.length way.
EDIT 2017: "We'll see how it goes", indeed. In most engines now, .forEach() is now as fast or faster than for(;;), as long as the function is inline, i.e. arr.forEach(function() { ... }) is fast, foo = function() { ... }; arr.forEach(foo) might not be. One might think that the two should be identical, but the first is easier for the compiler to optimise than the second.
Belated EDIT 2020: There is now for (const item of iterable), which solves the downsides of using for (item in iterable).
Using the latest versions of JavaScript available to most modern browsers, you can do this:
array.forEach(function(x){
document.write(x);
});
Details are at https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/forEach. If you're worried that a browser may not have support for this, you can add it yourself, using a (hopefully minified) version of the implementation that they have listed under "Compatibility".
This is a bit outdated, but this is a minified compatibility version of forEach that I derived from Mozilla's page a few years ago:
if(!Array.prototype.forEach){Array.prototype.forEach=function(b){if(typeof b!="function"){throw new TypeError()}var a=this.length,d=arguments[1],c;for(c=0;c<a;c++){if(c in this){b.call(d,this[c],c,this)}}}};
I've never run into any issues with this, but the implementation on Mozilla's page has since been expanded with some additional checks and code to make it compatible with ECMA-262, Edition 5, 15.4.4.18.
I have a file called common.js that I use and include on all of my pages to include this, as well as all of the other "Array extras" that were introduced with JavaScript 1.6, as listed at https://developer.mozilla.org/en/JavaScript/New_in_JavaScript/1.6#Array_extras. (I've been meaning to get this updated and published for public use.)
This may not be the fastest approach (see http://jsperf.com/for-vs-foreach/15 for some specifics - thanks for the link, Amadan) - but there is something to be said for conciseness and maintainability, etc. Additionally, it'll be very interesting to see how much of this disparity is optimized away by further JavaScript engine improvements over the next few months and years. :-)
In ES2015(ES6), you can use the for-of loop. It's supported in most browser with the exception of IE.
let array = [10, 20, 30];
for (let value of array) {
console.log(value);
}
See the Mozilla explanation here
You can do for(s in array), but be careful, it's not the same as a foreach.
In this case s is the key (index), not the value. You also need to use hasOwnProperty because in loops though the object's prototype also.
for(s in array){
if(array.hasOwnProperty(s)){
console.log(array[s]);
}
}
EDIT: As #Amadan pointed out, hasOwnProperty does iterate properties when they're added like this: array.test = function(){}. I suggest not using for...in.
EDIT2: If your using a modern web browser (anything that isn't IE < 9), you can use Array.forEach). #ziesemer points out that Mozilla has a shim for this if you need to support IE < 9.
array.forEach(function(s){
console.log(s);
});
NOTE: Personally I use jQuery for my JavaScript projects, and I use $.each.
$.each(array, function(i,s){
console.log(s);
});
There's the "forEach" method on the Array prototype in newer JavaScript engines. Some libraries extend the prototype themselves with a similar method.
Try this:
var errorList = new Array();
errorList.push("e1");
errorList.push("e2");
for (var indx in errorList) {
alert(errorList[indx]);
}
x = [1,2,3];
for (i in x) {
console.log(i);
}
This question is almost identical to How to efficiently count the number of keys/properties of an object in JavaScript?.
I want to know one extra piece of information: what is a "constant-time" way of determining the number of keys in an Object? I am mostly concerned with doing this in Node.JS, as most Objects on the browser aren't too large to be of great concern.
EDIT:
It appears that Object.keys(obj).length returns in linear time O(n) in Google Chrome and in Node.JS (i.e. dependent on the number of keys in obj). Is there a better O(1) method?
I did some testing in Node.JS (source is below)
var tests = [10e3, 10e4, 10e5, 10e6]
for(j in tests) {
var obj = {};
for(i = 0; i < tests[j]; i++)
obj[i] = i;
console.time('test' + tests[j]);
Object.keys(obj).length;
console.timeEnd('test' + tests[j]);
}
For n = 10e3, 10e4, 10e5, 10e6... results are:
test10000: 5ms
test100000: 20ms
test1000000: 371ms
test10000000: 4009ms
After a bit of research, there is no way to determine the number of keys in a JavaScript Object in constant time, at least not in Node... and not quite yet. Node internally keeps track of this information, but it does not expose it, since there is no method to do so in ECMA-262 5th.
It's worth noting that Harmony (ECMA version 6) may natively support Maps and Sets. Not sure what the spec for these will turn out to be.
I am told that we need to bring this up with TC39 committee.
Bug report for V8: http://code.google.com/p/v8/issues/detail?id=1800
ECMA 6 harmony introduces Map and Set classes which you can probably utilize (in the future :)
var map = new Map;
map.set('a', 'b');
console.log(map.size); // prints 1
I believe it should have complexity O(1), not tried though. You can run it in node 0.11+ via node --harmony script.js.
Another way is to use Proxy class which also has been added in harmony.
See the source, specifically GetLocalElementKeys
v8 objects.cc
Note: I’m going to use a specific object as an example here, but please don’t post answers specific to this example; the question is more general.
Specific example
I wrote some jQuery code like this...
$('#some_button').click(function(event) {
$.post('<some URL>', { <some parameters> },
function() { <do something on success> })
.error(function(x) {
// What is x?
});
event.preventDefault();
});
Now, for the purpose of this question, let’s assume that there is no documentation about that object x that is passed in.
An obvious thing to do might be
alert(x);
but all that will output is [object Object].
General question
What might be an easy way to find out what properties/methods an unknown object has? I’m thinking something that I’d just write during the debugging phase, no production code of course.
You may assume that jQuery is available.
Edit:
I’m fully aware of for (...), but surely that doesn’t mean there can’t be a better/easier way — I thought jQuery might have something built-in...
A general and single level basic javascript solution
Basic functionality looks like this:
var s = "";
for(var p in obj)
{
s += p + " = " + obj[p] + "\n";
}
alert(s);
Object graph issue
It will enumerate over all properties of an object. If this particular object has deep object trees you should better put this into a function and then recall it on sub object. enumerate internal sub object using the same technique. Arrays are a similar issue.
But I suppose you'll be able to provide this kind of functionality from this starting example code.
Browser console solution
If you have development console open in your browser (in Firefox that would be Firebug) then you can easily just call this:
console.log(obj);
But there's a problem with IE, because when it comes to a complex object is just displays {...} which isn't really helpful. So this approach can only be used in Chrome and Firefox+Firebug.
A jQuery plugin for any browser
This is a small and simple plugin I've come up to enumerate an arbitrary object and display its content in browser's console:
$.extend({
inspect: function(obj,n){
n = n || "this";
if ($.isArray(obj)) {
for (var x = 0; x < obj.length; x++) {
$.inspect(obj[x], n + "[" + x + "]");
}
return;
}
if ($.isPlainObject(obj)) {
for (var p in obj){
$.inspect(obj[p], n + "." + p);
}
return;
}
console.log(n + " = " + obj.toString());
}
});
This code works with any browser (I actually needed it for IE, because of the previously mentioned issue with {...} display.
It parses an object graph into console provided that your browser's console is open. In IE and Chrome that's the built in development console and in Firefox it's Firebug console.
You can use it as:
$.inspect(yourObject);
or
$.inspect(yourObject, "person");
The second optional parameter is used to give your object a name when displaying it. If you don't provide the name it will be set as "this". Your object will be displayed as:
this.name = "John"
this.lastname = "Doe"
console.log was built for that.
Alternatively (although I'm not sure what could be better than the first option) your own recursive implementation that loops through the objects properties with a simple for(parameter in obj){ ... }
console.log
will usually give you a better idea of the properties an object has.
Your best bet would be to use a browser like Google Chrome or Firefox with the Firebug plugin then you can add a breakpoint and inspect the object. If it is just a simple Javascript object you could just loop through the properties like so:
for(name in object) {
alert("name: " + name + "value:" + object[name]);
}
Another option might be to serialize to JSON and output that. A solution for doing that can be found here.
It is difficult in javascript to write a general function to determine whether an identifier references any particular type of value. Most such functions are limited to specific cases. A general "what is this" function is practically impossible if not limited to specific bounds.
If such a function was available, what would you do with it?
The general approach in javascript is to test for the properties or capabilities that are required for a particular purpose. What is the point in going further?
console.log
and typeof obj
will suffice.
Does Javascript supports Sets(list with unique objects only) ?
I have found this link, but from what I remember foreach in JS in not supported by every browser.
Are your keys strings?
Every JavaScript object is a map, which means that it can represent a set.
As illustrated in the page you mentioned, each object will accept only one copy of each key (attribute name). The value for the key/attribute doesn't matter.
jshashtable would allow you to store any object as a key, and use the same pattern as in the link you gave. In addition it supplies a method to get an array of keys, which you can then iterate over. It also has good cross-browser support, so should fit nicely into any environment.
Now with ES6 (and polyfills/shims like corejs) you have them:
Set - JavaScript | MDN
Example:
var mySet = new Set([1, 2, 3, 2, 1]); // => [1, 2, 3]
console.log(mySet.size);
console.log(mySet.has(3));
mySet.forEach(function(x){console.log(x)});
The Polifill is required since it is not supported by older browsers, so you can ignore it if you are aiming only at the latest ones.
You probably remember the Array.forEach() that is indeed not supported by older Opera and all IE browsers - the for (var x in ...) is part of the "native" JS as far as I know and is supported by all browsers.
JavaScript do support Set. Here is the link to canIuse website. It is supported by Chrome, Edge, Safari, Firefox, Opera and even IE. To declare set you can use Set() constructor.
let set = new Set();
set.add("John);
In this way you can use sets.
I have this javascript code working in firefox, chrome, and safari
for (idx in all_auction_ids){
alert(all_auction_ids[idx]);
};
for the above, instead of getting the values in all_auction_ids, the first value I get is text of type function that looks like a for loop!
But if I run the code below, it works fine.
for (idx=0;idx<all_auction_ids.length;idx=idx+1){
alert(all_auction_ids[idx]);
};
edit: updates
I did some debugging and found out that, adding Orbited and stomp.js is probably doing something with the array!
for now i am using Tracker1's suggestion jquery's $.each.
more info:
http://groups.google.com/group/orbited-users/browse_thread/thread/7fd658cfb166e9fa
array with the problem
http://bayimg.com/fAnhaAaBb
array without the problem
http://bayimg.com/FaNhEAabb
JavaScript's for/in construct is traditionally for iterating over object member names, not array indices. The more forward-thinking browsers have added features like hidden properties to help cases like Array enumerate in the way you would expect, but IE stilll does it the old-school way and gives you Object members like the 'toString' method when you use for/in over an Array.
The indexed-for is still the canonical JavaScript array loop. (Although you probably mean 'for (var idx=...', and 'idx++' is more common.)
It's worth noting that some libraries such as prototype.js extend Array, so that they have additional properties beyond the internal indexes. This breaks for x in y notation beyond, as other mentioned, that IE will iterate properties. for i=0...i++ is preferred.
Also worth noting is jQuery, prototype and others offer a .each(fn) notation that I actually prefer.
I agree with #bibince that you probably should be using the "for(var i = 0..." syntax, but there is no reason that the syntax you chose should not work unless you have done something strange in your creation of all_auction_ids. How are you initializing your array?
Arrays in JavaScript are just objects with a special auto-incrementing feature, but in reality they are not much different that an anonymous object. Try this in Firebug:
var a = ['a','b','c'];
a.d = 'd';
for(var i in a) console.log(i, a[i]);
or paste this into your address bar in IE and hit enter:
javascript:var a = ['a']; a.d = 'd'; for(var i in a) alert(a[i]); alert(a.length);
EDIT:
I doubt this is your problem, but do you have the same problem if you use:
var all_auction_ids = [];
rather than
var all_auction_ids = new Array();
If that doesn't help then could you post a little more of your code to give us a better idea of how you are populating all_auction_ids?
This topic on the YUI blog is germane to your problem.
I've been having similar problems lately creating "select all / clear all" buttons for lists of checkboxes. In Firefox and Chrome they work fine, but in IE7/8 they don't. I'm not using any frameworks or external libraries, all the JavaScript is my own, it's fairly straightforward stuff, and there isn't much of it. I build the array of input elements using getElementsByTagName, then loop through:
var allClearInputs = document.getElementsByTagName("input");
for(ac=0;ac<allClearInputs.length;ac=ac+1){
if(allClearInputs[ac].id){
var thisNameArr = allClearInputs[ac].id.split("-");
var thisName = thisNameArr[0];
if(thisName == checkName){
if((actionType == 'all' && allClearInputs[ac].checked == false) || (actionType == 'clear' && allClearInputs[ac].checked == true)){
allClearInputs[ac].click();
}
}
}
}
Works perfectly with: for(ac=0;ac<allClearInputs.length;ac=ac+1){
Fails miserably with: for(var ac in allClearInputs)