Home > JavaScript > Duck Typing on JavaScript, and getter/setter

Duck Typing on JavaScript, and getter/setter

My friend Mauvis brought me (ahem) an interesting problem again.

Write a one-line piece of JavaScript code that concatenates all strings passed into a function: 

function concatenate (/*any number of strings*/) {
  var string = /*your one line here*/
  return string;
}

So, the first thing I’ve tried was as follows:

function concatenate () {
  var string = (function (a) {var r = [];for (var i = 0, len = a.length; i < len; ++i}{ r[i] = a[i]}return r.join('');)(arguments);
  return string;
}

I know that doesn't look good. And it's just in one line, but it's actually a few lines.

Then Mauvis replied me back..

function concatenate () {
  var string = function(a){return Array.prototype.slice.call(a).join('');}(arguments);
  return string;
}

and eventually it bacame like this.

function concatenate () {
  var string = Array.prototype.join.call(arguments, '');
  return string;
}

This is a pretty interesting topic in JavaScript. The first one I did is pretty straight forward, right? Arguments object is an array-like object, that each local (function) space has automatically. You can iterate like an array. So I loop through each value, put it all together in a different array, then construct a new string.

The second one and third one are a bit unusual for the first look. What it does is apply Arguments object as an array in order to call slice or join method, which both of them are originally Array's prototype methods.

If you are fuzzy about it, Let's take a look the specification of JavaScript.

It's a little too long, but I quote an entire section of slice (Page 105 - 106) here.

15.4.4.10 Array.prototype.slice(start, end)

The slice method takes two arguments, start and end, and returns an array containing the elements of the array from element start up to, but not including, element end (or through the end of the array if end is undefined). If start is negative, it is treated as (length + start) where length is the length of the array. If end is negative, it is treated as (lengt+ end) where length is the length of the array. The following steps are taken:

  1. Let A be a new array created as if by the expression new Array().
  2. Call the [[Get]] method of this object with argument "length".
  3. Call ToUint32(Result(2)).
  4. Call ToInteger(start).
  5. If Result(4) is negative, use max( (Result(3) + Result(4)), 0 ); else use min( Result(4), Result(3) ).
  6. Let k be Result(5).
  7. If end is undefined, useResult(3); else use ToInteger(end).
  8. If Result(7) is negative, use max( (Result(3) + Result(7)),0 ); else use min( Result(7), Result(3) ).
  9. Let n be 0.
  10. If k is greater than or equal to Result(8), go to step 19.
  11. Call ToString(k).
  12. If this object has a property named by Result(11), go to step 13; but if this object has no property named by Result(11), then go to step 16.
  13. Call ToString(n).
  14. Call the [[Get]] method of this object with argument Result(11).
  15. Call the [[Put]] method of A with arguments Result(13) and Result(14).
  16. Increase k by 1.
  17. Increase n by 1.
  18. Go to step 10.
  19. Call the [[Put]] method of A with arguments "length" and n.
  20. Return A.

The length property of the slice method is 2.

NOTE

The slice function is intentionally generic; it does not require that its this value be an Array object. Therefore it can be transferred to other kinds of objects for use as a method. Whether the slice function can be applied successfully to a host object is implementation-dependent.

And here's join section (page 103). This one is snippet.

15.4.4.5 Array.prototype.join (separator)

The elements of the array are converted to strings, and theses trings are then concatenated, separated
by occurrences of the separator. If no separator is provided, a single comma is used as the separator. The join method takes one argument, separator, and performs the following steps..

...(snip)...

NOTE

The join function is intentionally generic; it does not require that its this value bean Array object. Therefore, it can be transferred to other kinds of objects for use as a method. Whether the join function can be applied successfully to a host object is implementation-dependent.

Both sections consist of definition, procedures, and note. And interesting thing is on the Note: intentionally generic and implementation-dependent. So it depends on Browser dev, to implement it generic or not..

I made a page to try out those things: Duck Typing test.

And acutally, as it's written on SPEC, you can use slice/join for your own object. What it's written on 2 and 14 on Array.prototype.slice procedure, it needs to access [[Get]], which is an internal method for each object (page 26 - 28). According to John Resig's JavaScript Getters and Setters, it can be used in Firefox, Safari and Opera. But as far as I tried, it doesn't work in Opera. If IE has the other way to do it, I will be more interested in...

Comments:4

Mauvis 08-10-31 (Fri) 13:11

In hindsight there was no reason for me to use a closure in my response and it should have been more like:

function concatenate(){
var string = Array.prototype.slice.call(arguments).join(”);
return string;
}

Still the third response is better since we’re just borrowing the join prototype off the Array object instead of converting the arguments object to an array and then calling it’s join method.

Nice writeup!

beatak 08-10-31 (Fri) 19:23

What I really think interesting about is that this is somehow tricky and you don’t have to know to do the things in JavaScript (unless you need a speed), but on the other hand it gives such a simplicity and potential. Thanks for letting me know!

Daniel 08-11-25 (Tue) 19:36

What about a recursive function? I’m not familiar with javascript (so this is probably not valid syntax), but the concatenation function could potentially look like:

var string = (c: function(a, len) {if (len > 0) {return a[len].join(c(a, len – 1));} else {return a[0];}});

beatak 08-11-25 (Tue) 19:56

I’m not 100% sure what Daniel means by that code… it looks like a using String as Array-like access? It should work if you fix as below, but I think it less efficient.


var c = function(a, len)
{
if (len > 0)
{
return a[len].join( c(a, len - 1) );
} else {
return a[0];
}
};
var string = c(target, target.length);

Comment Form
Remember personal info

Trackbacks:0

Trackback URL for this entry
http://blog.nydd.org/2008/10/duck-typing-on-javascript-and-gettersetter/trackback/
Listed below are links to weblogs that reference
Duck Typing on JavaScript, and getter/setter from Vantage Point of Queens

Home > JavaScript > Duck Typing on JavaScript, and getter/setter

Search
Feeds
Meta
Links
Ads!

Return to page top