Perlish map() function

M

Matt Kruse

Perl's map() function is a powerful shortcut to accomplish many "loop over
an array and do X" operations.
Below is a quick hack to simulate similar functionality.
I've used it a few times and find it to be quite handy.
Any thoughts?

<script type="text/javascript">
function map(func) {
var i,j,o;
var results = [];
if (typeof(func)=="string") {
func = new Function('$_',func);
}
for (i=1; i<arguments.length; i++) {
o = arguments;
if (typeof(o)=="object" && o.length) {
for (j=0; j<o.length; j++) {
results[results.length] = func(o[j]);
}
}
else if (typeof(o)=="object") {
for (j in o) {
results[results.length] = func(o[j]);
}
}
else {
results[results.length] = func(o);
}
}
return results;
}
var o = { 'a':'a1', 'b':'b1', 'c':'c1' };
var a = [ 'a','b','c' ];

map( "alert($_)", o , a, "test" );
map( function(o){ alert("Value:"+o); } , o , a, "test" );
map( "alert($_);", map( "return $_.toUpperCase();" , o, a, "test") );
</script>

PS: The use of $_ as an identifier is carried over from Perl, in case you
aren't familiar with it.
 
T

Thomas 'PointedEars' Lahn

Matt said:
Perl's map() function is a powerful shortcut to accomplish many "loop over
an array and do X" operations.
Below is a quick hack to simulate similar functionality.
I've used it a few times and find it to be quite handy.
Any thoughts?

Array.prototype.map() exists since JavaScript 1.6 (Gecko 1.8), you are
"too late" ;-)

Seriously, the application of your method seems more elegant for arbitrary
values than that of this built-in method (and your method is required in
JScript and JavaScript < 1.6 of course). I have included the (supposedly)
equivalent JavaScript 1.6 code below for completeness.
<script type="text/javascript">
function map(func) {
var i,j,o;
var results = [];
if (typeof(func)=="string") {

`typeof' is an operator, not a function:

if (typeof func == "string") {
func = new Function('$_',func);
}
for (i=1; i<arguments.length; i++) {

Since `i' is used only for this loop, I would declare it here:

for (var i = 1, len = arguments.length; i < len; i++) {
o = arguments;
if (typeof(o)=="object" && o.length) {


if (typeof o == "object" && o.length) {

Maybe one should test for o[0], too.
for (j=0; j<o.length; j++) {

var len;
for (j = 0, len = o.length; j < len; j++) {
results[results.length] = func(o[j]);

// since JavaScript 1.2, JScript 5.5
results.push(func(o[j]));
}
}
else if (typeof(o)=="object") {
for (j in o) {
results[results.length] = func(o[j]);

See above.
}
}
else {
results[results.length] = func(o);

See above.
}
}
return results;
}
var o = { 'a':'a1', 'b':'b1', 'c':'c1' };
var a = [ 'a','b','c' ];

map( "alert($_)", o , a, "test" );

That would be in JavaScript 1.6:

Object.prototype.map = function(f)
{
for (var i in this)
{
if (i != 'map')
{
f(this);
}
}
};

// do not inherit this from Object.prototype
// (else we handle each character of the string)
String.prototype.map = function(f)
{
f(this);
};

[o, a, "test"].map(
function(x)
{
x.map(function(y) { alert(y); });
});
map( function(o){ alert("Value:"+o); } , o , a, "test" );

[o, a, "test"].map(
function(x)
{
x.map(function(y) { alert("Value:" + y); });
});
map( "alert($_);", map( "return $_.toUpperCase();" , o, a, "test") );

This one-liner becomes quite ugly with Array.prototype.map() only:

this.object_prototype_map = Object.prototype.map;
Object.prototype.map = function(f)
{
for (var i in this)
{
if (i != 'map')
{
this = f(this);
}
}

return this;
};

this.string_prototype_map = String.prototype.map;
String.prototype.map = function(f)
{
return f(this);
};

var a2 = [o, a, "test"].map(
function(x)
{
return x.map(
function(y)
{
return y.toUpperCase();
});
});

Object.prototype.map = this.object_prototype_map;
delete this.object_prototype_map;
String.prototype.map = this.string_prototype_map;
delete this.string_prototype_map;

a2.map(
function(x)
{
return x.map(
function(y)
{
alert(x);
});
});


Regards,
PointedEars
 
M

Matt Kruse

Thomas said:
Array.prototype.map() exists since JavaScript 1.6 (Gecko 1.8), you are
"too late" ;-)

I'm aware of this, but mine has more functionality, and isn't limited to
Arrays. (And can actually be used in a WWW context!)
Particularly, for my use, I often want to act on all items in an Object.
Also, I like being able to specify a quick and simple expression rather than
a full anonymous function.
`typeof' is an operator, not a function:

I know. But I just think typeof(obj) is clearer, so I always write it that
way.
if (typeof o == "object" && o.length) {
Maybe one should test for o[0], too.

I've actually revised it to this:
if ((typeof(o)=="object" && typeof(o.length)=="number" && (!Array || (o
instanceof Array)))) {
// since JavaScript 1.2, JScript 5.5
results.push(func(o[j]));

Old habits die hard. Despite 1.2 being widespread enough to be assumed, I
tend to avoid using 1.2 array methods, since it doesn't hurt anything to do
it the old way. I suppose I should update my thinking.

mine:
your example:
[o, a, "test"].map(
function(x)
{
x.map(function(y) { alert("Value:" + y); });
});

I definitely think mine is easier to read! While the map() method in 1.6 is
no doubt useful, in general I think I would always prefer to use a method
like I've written. Which, btw, I've changed to:

function map(func) {
var i,j,o;
var results = [];
if (typeof(func)=="string") {
func = new Function('$_',func);
}
for (i=1; i<arguments.length; i++) {
o = arguments;
if ((typeof(o)=="object" && typeof(o.length)=="number" && (!Array || (o
instanceof Array)))) {
for (j=0; j<o.length; j++) {
results.push(func(o[j]));
}
}
else if (typeof(o)=="object" && (!Object || (o instanceof Object))) {
for (j in o) {
results.push(func(o[j]));
}
}
else {
results.push(func(o));
}
}
return results;
}

I found in testing that if I wanted to act on a group of Nodes, for example,
it would instead try to pull out its properties and act on each of those.
Thus the "instanceof Object" check.

Thanks for the constructive feedback.
 
T

Thomas 'PointedEars' Lahn

Matt said:
I'm aware of this, but mine has more functionality, and isn't limited to
Arrays. (And can actually be used in a WWW context!)
Particularly, for my use, I often want to act on all items in an Object.
Also, I like being able to specify a quick and simple expression rather
than a full anonymous function.

See below.
I know. But I just think typeof(obj) is clearer, so I always write it that
way.

I do not find it more clear because it makes it harder to see the method
calls. But maybe that is just me.
if (typeof o == "object" && o.length) {
Maybe one should test for o[0], too.

I've actually revised it to this:
if ((typeof(o)=="object" && typeof(o.length)=="number" && (!Array || (o
instanceof Array)))) {

`!Array' equals `false' always.
// since JavaScript 1.2, JScript 5.5
results.push(func(o[j]));

Old habits die hard. Despite 1.2 being widespread enough to be assumed, I
tend to avoid using 1.2 array methods, since it doesn't hurt anything to
do it the old way. I suppose I should update my thinking.

Array.prototype.push() is supported _since_ JavaScript 1.2 (NN 4.0),
i.e. it is supported by all later versions. That it was introduced
in that particular JavaScript version matters only insofar that it
is not supported before the corresponding NN version.

Whether you should update your thinking here or not mostly depends
on whether you want to support IE 5.0 and older or not. Iff the
MSDN Library is correct about the JScript version here.
mine:
your example:
[o, a, "test"].map(
function(x)
{
x.map(function(y) { alert("Value:" + y); });
});

I definitely think mine is easier to read! While the map() method in 1.6
is no doubt useful, in general I think I would always prefer to use a
method like I've written.

I did say quite the same, did I not?
[...]
Thanks for the constructive feedback.

You are welcome.


PointedEars
 
R

ron.h.hall

Matt said:
I'm aware of this, but mine has more functionality, and isn't limited to
Arrays. (And can actually be used in a WWW context!)
Particularly, for my use, I often want to act on all items in an Object.

And you're most definitely not alone. Worse yet, in Javascript if
you've dared to augment the Object prototype, you'll in all likelihood
often end up with:

for (j in Obj) {
if ( Obj.hasOwnproperty(j)) {

}
}

which can become irksome, tiresome and untidy. For me, that lead to
creation of an Object.prototype.Do function that, in parameterization
and in body, is almost identical to your Perl 'map' function emulation.
That object-oriented prototypical approach seems to me to more in
keeping with the Javascript programming paradigm.

However, if your goal is to to provide an emulation of Perl
capabilities within Javascript, that's a bit of a different matter, and
your choice. But it's really not something I personally would find
myself particularly keen on (even speaking as one who used to be
somewhat attached to Perl as a scripting language). I'd much rather see
extended capabilities included under the model provided by the
language, as opposed to creating some sort of graft that doesn't
necessarily fit well. It sounds to me like a perfectly good way to end
up with a camel rather than a horse. ;-)
Also, I like being able to specify a quick and simple expression rather than
a full anonymous function.


I know. But I just think typeof(obj) is clearer, so I always write it that
way.

Somewhat curiously, though, you don't find a similar need to be
"clearer" when using 'instanceof' ? ;-)

../rh
 
M

Matt Kruse

Thomas said:
`!Array' equals `false' always.

Even prior to js1.2? I don't remember exactly, but I recall writing the
syntax of

if (!Array && (obj instanceof Array))

quite a long time ago, to protect against browsers which didn't have Array
defined.
I may very well be in error, though.
 
M

Matt Kruse

For me, that lead to
creation of an Object.prototype.Do function that, in parameterization
and in body, is almost identical to your Perl 'map' function
emulation. That object-oriented prototypical approach seems to me to
more in keeping with the Javascript programming paradigm.

However, you then need to extend the Array prototype, String prototype, etc.
I prefer map to look like a built-in command. Personal preference, I
suppose.
Somewhat curiously, though, you don't find a similar need to be
"clearer" when using 'instanceof' ? ;-)

No, because this:

(typeof obj == "string")

isn't as obvious about order of operations as this:

(typeof(obj)=="string")
or
(obj instanceof Object)

I also always write:

if (condition) {
statement;
}

over:

if (condition)
statement;

because I think clarity is more important than brevity.
 
R

ron.h.hall

Matt said:
However, you then need to extend the Array prototype, String prototype, etc.

That, of course, is not the case. But even if so, what is your point --
that you shouldn't prototype in a prototypal language?
I prefer map to look like a built-in command. Personal preference, I
suppose.

I suppose. Somewhat unfortunate, in that it doesn't appear that you've
really considered other options that could possibly provide better
facility and be delivered with improved integration within the
language.
No, because this:

(typeof obj == "string")

isn't as obvious about order of operations as this:

(typeof(obj)=="string")
or
(obj instanceof Object)

I also always write:

if (condition) {
statement;
}

over:

if (condition)
statement;

because I think clarity is more important than brevity.

That latter is commendable, whereas I can't say the same for the
concious act of attempting to couch a prefix operator as a function in
the name of clarity. If indication or specification of order is
necessary in an expression, that's normally done by parenthetical
grouping, but not the one you use.

You did ask for comment, by the way. ;-)

... Ron
 
V

VK

... is commendable, whereas I can't say the same for the
concious act of attempting to couch a prefix operator as a function in
the name of clarity. If indication or specification of order is
necessary in an expression, that's normally done by parenthetical
grouping, but not the one you use.

JavaScript 1.3 Language Reference, Netscape Corp. 1999

The typeof operator is used in either of the following ways:

1. typeof operand
2. typeof(operand)

The parentheses are optional.


The void operator is used in either of the following ways:

1. void(expression)
2. void expression
The parentheses surrounding the expression are optional, but it is good
style to use them.

So it *was* good style for typeof either. It even was specially
mentioned and accounted in ECMAScript specs. Again if something *was*
good style in 1998-1999 doesn't have to be good style in 2006. Fashions
for code "layout" change like dress fashions :)
I personally still use typeof(obj) unless posting in clj : only to not
get kicks at least fot this one :)

Still as this type of coding has a very long tradition and as it is
clearly described in ECMAScript I would move this question out of the
"code quality" category. It's merely the same issue as the evelasting
discussion where to place brakets:

function f() {
}

or

function f()
{
}
 
M

Matt Kruse

That, of course, is not the case.

Well, then, you'll internally examine and switch logic depending on the
actual object.
In general, I think that extending the Object prototype is not the best
approach because it gets applied so widely.
But even if so, what is your point
-- that you shouldn't prototype in a prototypal language?

No, just that in this case it doesn't seem to make anything easier.
What if, for example, I want to call map() on 5 static values, like

map( "alert($_);" , 'a','b','c','d','e' );

Doing this by extending Object() would be a pain and counter-intuitive, IMO.
I suppose. Somewhat unfortunate, in that it doesn't appear that
you've really considered other options that could possibly provide
better facility and be delivered with improved integration within the
language.

I've considered other options - in fact, Pointy Boy posted an example of how
to implement it with prototypes. The end result was messy, IMO.
 
R

ron.h.hall

That was probably supposed to be "conscious" above. :)
JavaScript 1.3 Language Reference, Netscape Corp. 1999

The typeof operator is used in either of the following ways:

1. typeof operand
2. typeof(operand)

The parentheses are optional.

My recollection is that the cited reference was very good, but not
perfect (including full undestanding by the authors).

[..]
So it *was* good style for typeof either. It even was specially
mentioned and accounted in ECMAScript specs.

Here's one mention from 11.1.6:

"NOTE
This algorithm does not apply GetValue to Result(1). The principal
motivation for this is so that operators such as delete and typeof may
be applied to parenthesised expressions."

It seems pretty clear to me that the pupose of allowing parentheses is
not so you can make 'typeof' appear to be a function.

../rh
 
R

ron.h.hall

Matt said:
(e-mail address removed) wrote: [..]
In general, I think that extending the Object prototype is not the best
approach because it gets applied so widely.

I agree that universal augmentation can introduce its own frustrations.
But it doesn't necessarily mean that you write it off. In general,
there are tradeoffs to be weighed.
No, just that in this case it doesn't seem to make anything easier.
What if, for example, I want to call map() on 5 static values, like

map( "alert($_);" , 'a','b','c','d','e' );

Wouldn't that then be:

['a','b','c','d','e'].map("alert($_)");

?

../rh
 
T

Thomas 'PointedEars' Lahn

Matt said:
Even prior to js1.2?

After further investigation (see below), I see that my statement is
incorrect, but to answer your question properly: not always. According to
the reference material, the Array constructor was introduced in JavaScript
1.1, so it would evaluate to `false' in that version, too. And in
J(ava)Script 1.0, where `Array' is not defined, it would most certainly
not evaluate to anything (not even `true'), instead it would result in
an error.

However, in J(ava)Script 1.0 the (Syntax)Error would occur before because
`typeof' was not introduced before JavaScript 1.1, JScript 2.0. But either
aspect strikes me as being completely academical nowadays.
I don't remember exactly, but I recall writing the syntax of

if (!Array && (obj instanceof Array))

quite a long time ago, to protect against browsers which didn't have
Array defined. I may very well be in error, though.

In fact, the above does not protect against anything because if there was
no Array constructor, the base object of the reference is `null', and
evaluation would result in a ReferenceError (exception).

This was stated on similar occasions (with different identifiers) several
times in discussions the last days. Testing with any not defined
identifier shows that it is true.

However, to have it not only stated but also explained once (and please
CMIIW), here it is in detail for those who are interested in the language's
inner workings (including curious me who found that investigation quite
interesting). Everybody else please just ignore the following section :)
___________________________________________________________________________

,-[ECMAScript 3 Final]
|
| 11.4.9 Logical NOT Operator ( ! )
|
| The production UnaryExpression : ! UnaryExpression is evaluated as
| follows:

(First let us [the script engine] make sure that this production can be
used and there is no syntax error. The productions for `Array' are:

Program --> SourceElements --> SourceElement --> Statement
--> ExpressionStatement
--> [lookahead !elementOf {{, function}] Expression --> Expression
--> AssignmentExpression --> ConditionalExpression
--> LogicalORExpression --> LogicalANDExpression
--> BitwiseORExpression --> BitwiseXORExpression --> BitwiseANDExpression
--> EqualityExpression --> RelationalExpression --> ShiftExpression
--> AdditiveExpression --> MultiplicativeExpression
--> UnaryExpression --> PostfixExpression --> LeftHandSideExpression
^^^^^^^^^^^^^^^
--> NewExpression --> MemberExpression --> PrimaryExpression
--> Identifier
^^^^^^^^^^
(--> IdentifierName /but not/ ReservedWord --> IdentifierName
<--> {IdentifierStart, IdentifierName IdentifierPart}
<--> IdentifierPart --> {Unicode*}.)

Obviously `Array' is also a UnaryExpression. Therefore, we [the script
engine] can continue with evaluation.)

| 1. Evaluate UnaryExpression.
| 2. Call GetValue(Result(1)).
| 3. Call ToBoolean(Result(2)).
| 4. If Result(3) is true, return false.
| 5. Return true.

Executing step 1, following the productions of the grammar for `Array'
above, we see that an Identifier token has to be evaluated:

| 11.1.2 Identifier Reference
|
| An Identifier is evaluated using the scoping rules stated in section
| 10.1.4. The result of evaluating an Identifier [is] always a value of
| type Reference.

| 10.1.4 Scope Chain and Identifier Resolution
| [...]
| During execution, the syntactic production PrimaryExpression : Identifier
| is evaluated using the following algorithm:
|
| 1. Get the next object in the scope chain. If there isn't one, go to
| step 5.
| 2. Call the [[HasProperty]] method of Result(1), passing the Identifier
| as the property.
| 3. If Result(2) is true, return a value of type Reference whose base
| object is Result(1) and whose property name is the Identifier.
| 4. Go to step 1.
| 5. Return a value of type Reference whose base object is null and whose
| property name is the Identifier.
|
| The result of evaluating an identifier is always a value of type
| Reference with its member name component equal to
| the identifier string.

It should be obvious that if not even the Global Object (the last object in
any scope chain, see section 10.2) has an `Array' property, i.e. there is
no `Array' constructor, `null' is returned as base object of the `Array'
reference. (For brevity, I will write `Reference(X, Y)' for a value of
type Reference with base object component X, and member name component Y.
So the Reference value here is Reference(null, Array).)

Let us get back to the evaluation of the Logical NOT operator:

| 1. Evaluate UnaryExpression.

Because of the above, Result(1) := Reference(null, Array)

| 2. Call GetValue(Result(1)).

Result(2) := GetValue(Reference(null, Array))

| 8.7.1 GetValue (V)
|
| 1. If Type(V) is not Reference, return V.

It was established that V is of type Reference, so nothing is done here.

| 2. Call GetBase(V).

| GetBase(V). Returns the base object component of the reference V.

It was established that the base object component of V is `null':

Result(2) := null

| 3. If Result(2) is null, throw a ReferenceError exception.

Since the condition applies, the named exception is thrown. q.e.d.

| 5.2 Algorithm Conventions
| [...]
| If an algorithm is defined to "throw an exception", execution of the
| algorithm is terminated and no result is returned.
| The calling algorithms are also terminated, until an algorithm step is
| reached that explicitly deals with the exception, using terminology such
| as "If an exception was thrown...". Once such an algorithm step has been
| encountered the exception is no longer considered to have occurred.

BTW: There is a truly marvelous proof that the `!' operator does not
matter regarding this, which this posting is too short to contain ;-)
___________________________________________________________________________

Back to your code. Your expression was:

Let us assume that the first two subexpressions were evaluated to `true'.
This forces the evaluation of the third subexpression:

(!Array || (o instanceof Array))

If the Array constructor exists (JavaScript/JScript > 1.0), the first
operand evaluates to `false', which forces the evaluation of the second
operand. However, `instanceof' is an operator specified in ECMAScript
Edition 3, not introduced before JavaScript 1.4. A SyntaxError exception
would be thrown in JavaScript 1.1 to 1.3.

If the Array constructor does not exist (JavaScript 1.0, JScript < 3.0),
and we assume that for some reason (which leaves only being JScript 2.0,
see above) the implementation supports the previous `typeof' operator, a
ReferenceError exception is thrown here, as explained in detail above.

Therefore, I would drop this subexpression completely and look for something
more generic regarding objects with numerically iterable properties. I do
not think that this can be done without giving up at least partially
backwards compatibility to JavaScript versions prior to 1.5, and JScript
versions prior to 5.5, though.

I see the following solutions to this dilemma:

A) Forget about backwards compatibility and use o.hasOwnProperty()
(JavaScript 1.5+) to determine if the object with a `length' property
has a property with numerical name that corresponds to the value of
the former. That is, if o.length == 2, test if o[1] exists; if yes,
assume that the object is numerically iterable.

B) Handle only Array objects, test for them with o.constructor == Array
(JavaScript/JScript > 1.0).

C) Handle all objects with a `length' property except String objects,
test with o.constructor == String (JavaScript/JScript > 1.0).

D) Handle all objects with a `length' property of type `number'
(JavaScript 1.1+). In JavaScript, each character of the string
value of String objects would be handled individually (which may be
inefficient); a workaround would have to be found for JScript, where
String objects have no properties with numerical names that
correspond to the characters of the string value.

Therefore, my untested suggestion, which should work in JavaScript 1.1+ /
JScript 2.0+, where collections are not supported before JavaScript 1.5 /
JScript 5.5:

var bHasOwnProperty;
if (typeof o == "object"
&& o.constructor != String
&& typeof o.length == "number"
&& (((bHasOwnProperty = (typeof o.hasOwnProperty == "function"))
&& o.hasOwnProperty(o.length - 1))
|| (!bHasOwnProperty && o.constructor == Array)))
{
for (var j = 0, len = o.length; j < len; j++)
{
// ... o[j] ...
}
}


PointedEars
 
T

Thomas 'PointedEars' Lahn

Matt said:
(e-mail address removed) wrote: [..]
In general, I think that extending the Object prototype is not the best
approach because it gets applied so widely.

I agree that universal augmentation can introduce its own frustrations.
But it doesn't necessarily mean that you write it off. In general,
there are tradeoffs to be weighed.
No, just that in this case it doesn't seem to make anything easier.
What if, for example, I want to call map() on 5 static values, like

map( "alert($_);" , 'a','b','c','d','e' );

Wouldn't that then be:

['a','b','c','d','e'].map("alert($_)");

?

If you are talking about JavaScript 1.6: No, it would be

['a','b','c','d','e'].map(function(x) { alert(x); });

The complexity is introduced by variant values with properties, requiring

['a', {b: 42}, ['c'], /d/, new Error("e")].map(
function(x)
{
x.map(
function(y)
{
alert(y);
});
});

That would require every value to have a map() method. However, I find the
idea of the generic approach of only augmenting the Object prototype object
instead of augmenting all prototype objects of all Core objects (except
Array, in JavaScript 1.6) with map() quite nice. Perhaps something like
this:

Object.prototype.map = function(callback, thisObject, bSetValue)
{
if (typeof thisObject != "object"
&& typeof thisObject != "function")
{
bSetValue = thisObject;
thisObject = this;
}

if (thisObject.constructor != String)
{
for (var p in thisObject)
{
if (p != 'map')
{
if (bSetValue)
{
thisObject[p] = callback(thisObject[p]);
}
else
{
callback(thisObject[p]);
}
}
}
}
else
{
if (bSetValue)
{
return callback(thisObject);
}
else
{
callback(thisObject);
}
}
}


PointedEars
 
R

ron.h.hall

Thomas said:
Matt said:
(e-mail address removed) wrote: [..]
No, just that in this case it doesn't seem to make anything easier.
What if, for example, I want to call map() on 5 static values, like

map( "alert($_);" , 'a','b','c','d','e' );

Wouldn't that then be:

['a','b','c','d','e'].map("alert($_)");

?

If you are talking about JavaScript 1.6: No, it would be

['a','b','c','d','e'].map(function(x) { alert(x); });

Well, I wasn't ;-). Matt allowed the option of a "string" or a
"function" type as the first argument to 'map', and I chose to remain
consistent with his example. The choice would generally be made based
on process complexity and/or the requirement to maintain execution
context during the mapping process.

The point mostly was that there doesn't seem to be a lot to be gained
by passing a list as arguments to the 'map' function, having those
internally converted to an Array-like 'arguments' object, and then
processing the list from there. Especially since you would usually
already have the list resident in an object.
The complexity is introduced by variant values with properties, requiring

['a', {b: 42}, ['c'], /d/, new Error("e")].map(
function(x)
{
x.map(
function(y)
{
alert(y);
});
});

That would require every value to have a map() method.

I'm not sure you're stating that exactly as intended, but you could
recurse when an object is encountered in the list (although I haven't
really thought about whether that would be consistent with expected
behavior of 'map').
However, I find the
idea of the generic approach of only augmenting the Object prototype object
instead of augmenting all prototype objects of all Core objects (except
Array, in JavaScript 1.6) with map() quite nice. Perhaps something like
this:

Object.prototype.map = function(callback, thisObject, bSetValue)
{
if (typeof thisObject != "object"
&& typeof thisObject != "function")
{
bSetValue = thisObject;
thisObject = this;
}

if (thisObject.constructor != String)
{
for (var p in thisObject)
{
if (p != 'map')
{
if (bSetValue)
{
thisObject[p] = callback(thisObject[p]);
}
else
{
callback(thisObject[p]);
}
}
}
}
else
{
if (bSetValue)
{
return callback(thisObject);
}
else
{
callback(thisObject);
}
}
}

Is there a reason you've chosen not to use 'apply' in the callback's
(other than lack of inherent availability in some browsers)?

../rh
 
T

Thomas 'PointedEars' Lahn

Matt said:
I've considered other options - in fact, Pointy Boy posted an example of ^^^^^^^^^^
how to implement it with prototypes. The end result was messy, IMO.

So this is the extent to what you *really* appreciate my thoughts "behind
my back".


Score adjusted

F'up2 PointedEars
 
M

Matt Kruse

Thomas said:
So this is the extent to what you *really* appreciate my thoughts
"behind my back".

Eh, lighten up. It's just an attempt at humor. Humor sometimes doesn't
translate well or is misunderstood in print, unfortunately.

I appreciated your in-depth description of why !Array is flawed. I read it
twice, in fact. This thread has certainly been helpful to me, and I would
love to see more threads like it in this group.
Score adjusted

I still have no idea what this means.
 
T

Thomas 'PointedEars' Lahn

Matt said:
Eh, lighten up. It's just an attempt at humor. Humor sometimes doesn't
translate well or is misunderstood in print, unfortunately.

ACK. This is what smileys are for:

I appreciated your in-depth description of why !Array is flawed. I read it
twice, in fact. This thread has certainly been helpful to me, and I would
love to see more threads like it in this group.

ACK :)
I still have no idea what this means.

<URL:http://en.wikipedia.org/wiki/Scorefile>


HTH

PointedEars
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Staff online

Members online

Forum statistics

Threads
473,775
Messages
2,569,601
Members
45,182
Latest member
BettinaPol

Latest Threads

Top