How to add the "size" property to Javascript Array? - javascript

To add the size() method to the Array object I do:
if (!Array.size) {
Array.prototype.size = function() {
return this.length;
};
}
Is there a simple way to define the size property that will work like length ?
(I don't really need it, I just want to understand if this is something easily achievable in Javascript.)

With ES5 it's possible. Add a size property on the Array prototype,
Object.defineProperty(Array.prototype, "size", {
get: function() {
return this.length;
},
set: function(newLength) {
this.length = newLength;
}
});
var x = [1, 2, 3];
x.length // 3
x.size // 3
x.push(4);
x // [1, 2, 3, 4]
x.length // 4
x.size // 4
x.length = 2;
x // [1, 2]
x.size = 1;
x // [1]
It basically works as a wrapper around length. Appears like a property to the naked eye, but is backed by an underlying function.
Thanks to #Matthew's comment, this size property works like a complete wrapper around length.

I'll assume you already know this is not a real life issue.
length property is modified to suit the size of the array and reflected by methods such as shift() and pop().
So, you would need a method to get the length property.
Anurag shows you how it can be done with ES5.

if(!Array.size)
{
Array.prototype.__defineGetter__('size', function(){
return this.length;
});
}
var a = new Array();
a.push(1);
a.push(4);
console.log(a.size);
Although I'm not entirely sure how cross-browser friendly that is (should work on Chrome and FF at least).

Related

js track array length

target is to track array changes (based on length).
i found solution to one part of it, and i'm in trouble with second:
var arr = Object.create([])
, _length = 0
;
Object.defineProperty(arr, 'length', {
enumerable: true,
get: function () {
return _length;
},
set: function (length) {
//TODO: you can compare and do some action here
_length = length;
}
});
maybe this would be useful for you, as this will track all changes made to arr, using Array methods (push, pop, shift...)
but here i came to second part: if you use index to assign some values, like
arr[0] = 1;
this wouldn't work: length stay same, and tracking is not working =(
so could anyone help me?
added:
ok, MDN tells us:
When setting a property on a JavaScript array when the property is a
valid array index and that index is outside the current bounds of the
array, the engine will update the array's length property accordingly
does anyone know, how does this happens???
i sense, that this newly created arr must be instance of Array, so seems like i must do something like this.
added x2:
var _length = 0
, arr = Object.create(Array.prototype, {
length: {
enumerable: true,
get: function () {
return _length;
},
set: function (length) {
console.log('[debug] newLength/oldLength: ', length+'/'+_length);
_length = length;
}
}
})
;
now arr is instance of Array (arr instanceof Array -> true), but still arr[0] = 1 wouldn't trigger length setter =(
You might want to look at this question
It explains a few options that you might be interested in.
#2 seems like a good candidate for what you're looking for.
If you want to have some fun, there is a spec for observables objects/arrays or you can use underscore/lodash (they are interchangeable) and an extension: https://github.com/mennovanslooten/underscore-observe It's easy to use:
_.observe(some_array, function(new_array, old_array) { /* called for every change */ });

What is the equivalent of Array.any? in JavaScript?

I'm looking for a method for JavaScript that returns true or false when it's empty... something like Ruby any? or empty?
[].any? #=> false
[].empty? #=> true
The JavaScript native .some() method does exactly what you're looking for:
function isBiggerThan10(element, index, array) {
return element > 10;
}
[2, 5, 8, 1, 4].some(isBiggerThan10); // false
[12, 5, 8, 1, 4].some(isBiggerThan10); // true
JavaScript has the Array.prototype.some() method:
[1, 2, 3].some((num) => num % 2 === 0);
returns true because there's (at least) one even number in the array.
In general, the Array class in JavaScript's standard library is quite poor compared to Ruby's Enumerable. There's no isEmpty method and .some() requires that you pass in a function or you'll get an undefined is not a function error. You can define your own .isEmpty() as well as a .any() that is closer to Ruby's like this:
Array.prototype.isEmpty = function() {
return this.length === 0;
}
Array.prototype.any = function(func) {
return this.some(func || function(x) { return x });
}
Libraries like underscore.js and lodash provide helper methods like these, if you're used to Ruby's collection methods, it might make sense to include them in your project.
I'm a little late to the party, but...
[].some(x => !!x)
var a = [];
a.length > 0
I would just check the length. You could potentially wrap it in a helper method if you like.
I believe this to be the cleanest and readable option:
var empty = [];
empty.some(x => x); //returns false
JavaScript arrays can be "empty", in a sense, even if the length of the array is non-zero. For example:
var empty = new Array(10);
var howMany = empty.reduce(function(count, e) { return count + 1; }, 0);
The variable "howMany" will be set to 0, even though the array was initialized to have a length of 10.
Thus because many of the Array iteration functions only pay attention to elements of the array that have actually been assigned values, you can use something like this call to .some() to see if an array has anything actually in it:
var hasSome = empty.some(function(e) { return true; });
The callback passed to .some() will return true whenever it's called, so if the iteration mechanism finds an element of the array that's worthy of inspection, the result will be true.
Just use Array.length:
var arr = [];
if (arr.length)
console.log('not empty');
else
console.log('empty');
See MDN
If you really want to got nuts, add a new method to the prototype:
if (!('empty' in Array.prototype)) {
Array.prototype.empty = function () {
return this.length === 0;
};
}
[1, 2].empty() // false
[].empty() // true
DEMO
What you want is .empty not .empty() to fully mimics Ruby :
Object.defineProperty( Array.prototype, 'empty', {
get: function ( ) { return this.length===0 }
} );
then
[].empty //true
[3,2,8].empty //false
For any , see my answer here
Array has a length property :
[].length // 0
[0].length // 1
[4, 8, 15, 16, 23, 42].length // 6
polyfill* :
Array.prototype.any=function(){
return (this.some)?this.some(...arguments):this.filter(...arguments).reduce((a,b)=> a || b)
};
If you want to call it as Ruby , that it means .any not .any(), use :
Object.defineProperty( Array.prototype, 'any', {
get: function ( ) { return (this.some)?this.some(function(e){return e}):this.filter(function(e){return e}).reduce((a,b)=> a || b) }
} );
__
`* : https://en.wikipedia.org/wiki/Polyfill

Using array.splice inside Array prototype

Array.prototype.move = function(oldIndex, newIndex) {
var val = this.splice(oldIndex, 1);
this.splice(newIndex, 0, val[0]);
}
//Testing - Change array position
var testarray = [1, 2, 3, 4];
testarray.move(3, 0);
console.log(testarray);
This produces an error "this.splice is not a function" yet it returns the desired results. Why?
Array.prototype.move = function(oldIndex, newIndex) {
if(Object.prototype.toString.call(this) === '[object Array]') {
if(oldIndex && typeof oldIndex == 'number' && newIndex && typeof newIndex == 'number') {
if(newIndex > this.length) newIndex = this.length;
this.splice(newIndex, 0, this.splice(oldIndex, 1)[0]);
}
}
};
For some reason, the function is being called by the called by the document on load (still haven't quite figured that one out). I added a few checks to verify that this = an array, and then also reset the new index to be equal to the total size if the supplied int was greater than the total length. This solved the error issue I was having, and to me is the simplest way to move objects around in an array. As for why the function is being called onload must be something to do with my code.
You don't need the placeholder variable-
Array.prototype.move = function(oldIndex, newIndex) {
this.splice(newIndex, 0, this.splice(oldIndex, 1)[0]);
}
var a=[1,2,3,4,9,5,6,7,8];
a.move(4,8);
a[8]
/* returned value: (Number)
9
*/
Adding properties to built–in objects is not a good idea if your code must work in arbitrary environments. If you do extend such objects, you shouldn't use property names that are likely to be used by someone else doing the same or similar thing.
There seems to be more than one way to "move" a member, what you seem to be doing can be better named as "swap", so:
if (!Array.prototype.swap) {
Array.prototype.swap = function(a, b) {
var t = this[a];
this[a] = this[b];
this[b] = t;
}
}
I expect that simple re-assignment of values is more efficient than calling methods that need to create new arrays and modify the old one a number of times. But that might be moot anyway. The above is certainly simpler to read and is fewer characters to type.
Note also that the above is stable, array.swap(4,8) gives the same result as array.swap(8,4).
If you want to make a robust function, you first need to work out what to do in cases where either index is greater than array.length, or if one doesn't exist, and so on. e.g.
var a = [,,2]; // a has length 3
a.swap(0,2);
In the above, there are no members at 0 or 1, only at 2. So should the result be:
a = [2]; // a has length 1
or should it be (which will be the result of the above):
a = [2,,undefined]; // a has length 3
or
a = [2,,,]; // a has length 3 (IE may think it's 4, but that's wrong)
Edit
Note that in the OP, the result of:
var b = [,,2];
b.move(0,2);
is
alert(b); // [,2,];
which may not be what is expected, and
b.move(2,0);
alert(b); // [2,,];
so it is not stable either.

JavaScript object literal length === undefined?

I am working on this animation function but I have a problem. I can't seem to perform what should be an easy task, I can not get the length of an object. If you check out that jsFiddle you can see that I am running alert(properties.length); and it is returning undefined. Can anyone see why this might be?
This is supported in node.js and newer environments.
var obj = {a: "a", b: "b"};
Object.keys(obj).length // 2
JavaScript object simply do not have a length property, only Arrays do. If you want to know the number of properties that are defined on a object, you have to iterate over them and count them.
Also, your for in loop is prone to bugs due extension of Object.prototype since in will traverse the complete prototype chain and enumerate all the properties that are on the chain.
Example
// Poisoning Object.prototype
Object.prototype.bar = 1;
var foo = {moo: 2};
for(var i in foo) {
console.log(i); // logs both 'moo' AND 'bar'
}
You have to use the hasOwnProperty method on the object in order to filter out those unwanted properties.
// still the foo from above
for(var i in foo) {
if (foo.hasOwnProperty(i)) {
console.log(i); // only logs 'moo'
}
}
Many JavaScript frameworks out there extend the prototype, not using hasOwnProperty often leads to horrible bugs.
Update
Concerning the actual problem that your code is not animation both properties.
for(var p in properties) {
...
for(var i = 0; i <= frames; i++)
{
setTimeout((function(exti, element) {
return function() {
// p gets overriden by for outer for in loop
element.style[p] = original + (pixels * exti) + 'px';
}
// you need to pass in a copy of the value of p here
// just like you do with i and element
})(i, element), i * (1000 / 60), element);
}
....
}
If you are using Underscore.js, you can use _.size():
_.size({one : 1, two : 2, three : 3});
=> 3
Objects have no length, you'll need to use an array if you want that.
If you have to find the number of properties in an object there is only one way:
var length =0;
for(var i in obj) length++;
Here's #Junaid Qadir Shekhanzai's general function for "finding the length of an object" (which as we're told, should properly be called "counting the properties of an object"). It combines solutions from #Ivo Wetzel and #Martin Jespersen:
function countProperties(myObj){
var length = 0;
if(typeof myObj != 'object'){
return false;
}
for(var i in myObj) {
length++;
}
return length;
}

How do I add syntactic sugar in my Javascript library?

Right now the library can translate this operation
Select * from List where name = k% order by desc
to
List.filter(function(x) { return x.first_char() == 'k' }).sort().reverse());
Whats the best hack to remove the () so that the developer can write statements like:
List.filter(fn(x) { return x.first_char == 'k' }).sort.reverse;
Naive approach:
maxfn = function() {this[0]..}; Array.prototype.max = maxfn();
But with this approach I can't access 'this'.
I wanted to add a syntactic sugar for
new Array("1","2","3")
to something like :)(suggestions needed)
_("1","2" ,"3")
like we have in scheme where list -> '
I tried to clone the arguments but failed.
Thanks.
For lists you can use JSON notation:
["1", "2", "3"]
You can use JSON notation as suggested by RoBorg, if you control the list... However, there's no cross-browser way to treat a property as a method. Note: spidermonkey (firefox) does support using a getter (get method for a property).
Whats the best hack to remove the ()
Property getters/setters in JavaScript. Unfortunately it's a relatively new JavaScript feature that won't work on IE6/7 (as well as various other older browsers), so it's not really ready for prime-time yet (despite the intro of the linked article).
You could do this particular example by making a JavaScript object that wrapped a String and shadowed all String's methods, then add a static ‘first_char’ property set to the String's first character on initialisation. But it's really not worth it.
new Array("1","2","3")
to something like :)(suggestions needed)
_("1","2" ,"3")
Well that's simple enough:
function _(/* items */) {
var a= new Array();
for (var i= 0; i<arguments.length; i++)
a[i]= arguments[i];
return a;
}
There's no point in doing it nowadays, though, since the array literal syntax:
['1', '2', '3']
has been available since JavaScript 1.1-1.2 era and is available in every browser today. (It predates JSON by many, many years.)
I'll try to answer one by one:
1) Why would you want to remove parenthesis from a functon call?
2) If the "naive" approach is failing it's probably because you are calling the maxFn and assigning the results to Array.prototype.max. It should be like this:
maxfn = function() {this[0]..}; Array.prototype.max = maxfn;
3) RoBorg is correct, just use literal notation to construct arrays on the fly.
Edit:
Here's one way of implementing a max function on an array object. The optional evaluator argument is a function that takes two parameters, the current max value and current value in array. It should return the object that is "greater". Useful for non-primitives.
Array.prototype.max = function(evaluator) {
var max, i = 1; len = this.length;
if (len > 0) max = this[0];
for (; i < len; i++) {
if (evaluator) {
max = evaluator(max, this[i]);
}
else if(max < this[i]) {
max = this[i];
}
}
return max;
};
var a = [1, 3, 4, 5, 6];
alert(a.max());
var b = ["Arnold", "Billy", "Caesar"];
alert(b.max());
var c = ["Arnold", new Date(), 99, true];
alert(c.max());
var d = [1, 3, 4, 5, 6];
alert(d.max(function (max, val) { return max < val ? val : max }));

Categories

Resources