iterating javascript objects

349 views
Skip to first unread message

Anton Kulaga

unread,
Jun 6, 2014, 3:39:42 PM6/6/14
to scal...@googlegroups.com
In javascript it is very common to iterate object properties in a loop and is widely used by a lot of javascript libs. I think it would be nice to have a method that will turn any external javascript object into a map on which one can make some simple pattern matching like defining if property is string, double, js.Object or js.Function as well as all other map operations.

Sébastien Doeraene

unread,
Jun 6, 2014, 3:54:38 PM6/6/14
to Anton Kulaga, scal...@googlegroups.com
Hi,

I believe everything you need is there:
  • Turn any object into a map: obj.asInstanceOf[js.Dictionary[A]]
  • Array of its own enumerable properties: js.Object.keys(obj), which can be used in a for comprehension:
    for (prop <- js.Object.keys(obj)) { ... }
  • Pattern matching:
    obj("someProp") match {
      case x: String => ...
      case x: Double => ...
      case x: Boolean => ...
      case x: js.Function => ...
      case x: js.Object => ... (must be after js.Function, as a js.Function *is a* js.Object)
    }
Maybe something that's not there "natively" is a wrapper that adds all the operations of Scala Maps. But that's easy enough:

Cheers,
Sébastien

import scala.collection.mutable.{ Map, MapLike }

import scala.scalajs.js
import js.annotation.JSBracketAccess

final class JSDictAsMap[A](dict: js.Dictionary[A]) extends Map[String, A]
                                                      with MapLike[String, A, JSMap[A]] {
  def this() = this(js.Dictionary.empty)

  override def empty: JSMap[A] = new JSMap[A]

  override def get(key: String): Option[A] = {
    if (dict.hasOwnProperty(key)) Some(dict(key))
    else None
  }

  override def +=(kv: (String, A)): this.type = {
    dict(kv._1) = kv._2
    this
  }

  override def -=(key: String): this.type = {
    dict.delete(key)
    this
  }

  override def iterator: Iterator[(String, A)] = {
    for {
      key <- js.Object.keys(dict).iterator
    } yield {
      (key, dict(key))
    }
  }
}

object JSDictAsMap {
  def empty[A]: JSMap[A] = new JSMap[A]
}

Cheers,
Sébastien



On Fri, Jun 6, 2014 at 9:39 PM, Anton Kulaga <anton...@gmail.com> wrote:
In javascript it is very common to iterate object properties in a loop and is widely used by a lot of javascript libs. I think it would be nice to have a method that will turn any external javascript object into a map on which one can make some simple pattern matching like defining if property is string, double, js.Object or js.Function as well as all other map operations.

--
You received this message because you are subscribed to the Google Groups "Scala.js" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-js+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Anton Kulaga

unread,
Jun 7, 2014, 9:56:32 AM6/7/14
to scal...@googlegroups.com, anton...@gmail.com
Thank you for comprehensive reponse, I will try to deal with external js.objects this way.

>Turn any object into a map: obj.asInstanceOf[js.Dictionary[A]]

One of the reasons why I asked it is because I promote scalajs in scala communities where I participate. And one of the point of criticism is that
things that are natural (like iterating js.Object) in JavaScript do not feel natural in ScalaJS.  And I agree with them, at lest partically, obj.asInstanceOf[js.Dictionary[A]] does not feel natural and it repels part of the people. I think it makes sense to consider some implicits (or even methods for js.Objects) that will be available by default

Justin du coeur

unread,
Jun 7, 2014, 10:07:34 AM6/7/14
to Anton Kulaga, scal...@googlegroups.com
On Sat, Jun 7, 2014 at 9:56 AM, Anton Kulaga <anton...@gmail.com> wrote:
>Turn any object into a map: obj.asInstanceOf[js.Dictionary[A]]

One of the reasons why I asked it is because I promote scalajs in scala communities where I participate. And one of the point of criticism is that
things that are natural (like iterating js.Object) in JavaScript do not feel natural in ScalaJS.  And I agree with them, at lest partically, obj.asInstanceOf[js.Dictionary[A]] does not feel natural and it repels part of the people. I think it makes sense to consider some implicits (or even methods for js.Objects) that will be available by default

While I can see what you're saying, I think it kind of goes against the grain a bit.  I agree that JSDictAsMap should probably become a well-known library (and should probably have implicits to obviate away the asInstanceOf), but I'd say it's appropriate to require that it be imported -- it's "library-ish" more than "language-ish", and many relatively pure Scala.js apps likely won't use it...

Li Haoyi

unread,
Jun 7, 2014, 2:37:41 PM6/7/14
to scal...@googlegroups.com, anton...@gmail.com
I think so too https://github.com/scala-js/scala-js/issues/336. Working with JSON blobs with scalajs currently is annoying, and I do a bunch of it for scala-js-fiddle, but my last attempt at implementing/robustizing it kept running into edge conditions around value classes and scalajs objects that I didn't manage to figure out. Maybe someone else can give it a shot...

Anton Kulaga

unread,
Jun 7, 2014, 3:01:11 PM6/7/14
to Li Haoyi, scal...@googlegroups.com
>Working with JSON blobs with scalajs currently is annoying

I think the main problem is that it repels some people from switching to scalajs. Many developers have legacy js code and when they see how annoying such operations are they hesitate to switch to scalajs
--
Best regards,
Anton Kulaga
Reply all
Reply to author
Forward
0 new messages