Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.javascript > #17918 > unrolled thread

Source code "objectifying" technique?

Started byJJ <jaejunks@nah.meh>
First post2013-01-03 10:34 +0000
Last post2013-01-04 02:33 +0000
Articles 11 — 3 participants

Back to article view | Back to comp.lang.javascript


Contents

  Source code "objectifying" technique? JJ <jaejunks@nah.meh> - 2013-01-03 10:34 +0000
    Re: Source code "objectifying" technique? Stefan Weiss <krewecherl@gmail.com> - 2013-01-03 19:32 +0100
      Re: Source code "objectifying" technique? JJ <jaejunks@nah.meh> - 2013-01-03 20:13 +0000
        Re: Source code "objectifying" technique? Stefan Weiss <krewecherl@gmail.com> - 2013-01-03 23:57 +0100
          Re: Source code "objectifying" technique? Stefan Weiss <krewecherl@gmail.com> - 2013-01-04 00:44 +0100
          Re: Source code "objectifying" technique? JJ <jaejunks@nah.meh> - 2013-01-04 02:00 +0000
    Re: Source code "objectifying" technique? Scott Sauyet <scott.sauyet@gmail.com> - 2013-01-03 10:37 -0800
      Re: Source code "objectifying" technique? Scott Sauyet <scott.sauyet@gmail.com> - 2013-01-03 10:43 -0800
      Re: Source code "objectifying" technique? JJ <jaejunks@nah.meh> - 2013-01-03 20:33 +0000
        Re: Source code "objectifying" technique? Scott Sauyet <scott.sauyet@gmail.com> - 2013-01-03 13:09 -0800
          Re: Source code "objectifying" technique? JJ <jaejunks@nah.meh> - 2013-01-04 02:33 +0000

#17918 — Source code "objectifying" technique?

FromJJ <jaejunks@nah.meh>
Date2013-01-03 10:34 +0000
SubjectSource code "objectifying" technique?
Message-ID<XnsA13DB38A51C6jj@0.0.0.55>
Sometimes I need some a library from the web, but its functions are all 
globally defined instead of object based. For example:

var config=123;
function abc(){
  //does something
}
function def(){
  //does something else
}
function ghi(a){
  a=a||config;
  abc(def(a));
}
function jkl(a){
  a=a||config;
  def(a);
}

I want to put all those functions in a self contained object so that 
accessing them would be like:

theLib.abc();
theLib.ghi();
theLib.abc();
theLib.abc(456);

Usually I would convert each functions including all of the references 
like below.

theLib={};
theLib.config=123;
theLib.abc=function(){
  return theLib.config;
}
theLib.def=function(){
  return theLib.config*10;
}
theLib.ghi=function(a){
  a=a||theLib.config;
  theLib.abc(theLib.def(a));
}
theLib.jkl=function(a){
  a=a||theLib.config;
  theLib.def(a);
}

As you can see, this is a tedious work. Even for a 2KB code. Is there a 
simpler way to do this?

[toc] | [next] | [standalone]


#17919

FromStefan Weiss <krewecherl@gmail.com>
Date2013-01-03 19:32 +0100
Message-ID<kc4ir7$bh7$1@news.albasani.net>
In reply to#17918
On 2013-01-03 11:34, JJ wrote:
> Sometimes I need some a library from the web, but its functions are all 
> globally defined instead of object based. For example:
> 
> var config=123;
> function abc(){
>   //does something
> }
> function def(){
>   //does something else
> }
> function ghi(a){
>   a=a||config;
>   abc(def(a));
> }
> function jkl(a){
>   a=a||config;
>   def(a);
> }
> 
> I want to put all those functions in a self contained object so that 
> accessing them would be like:
> 
> theLib.abc();
> theLib.ghi();
> theLib.abc();
> theLib.abc(456);

Okay, as long as you're aware of that calling abc() is _not_ the same
thing as calling theLib.abc(). At least make sure to check if any of the
functions use |this|.

> Usually I would convert each functions including all of the references 
> like below.
> 
> theLib={};
> theLib.config=123;
> theLib.abc=function(){
>   return theLib.config;
> }
> theLib.def=function(){
>   return theLib.config*10;
> }
> theLib.ghi=function(a){
>   a=a||theLib.config;
>   theLib.abc(theLib.def(a));
> }
> theLib.jkl=function(a){
>   a=a||theLib.config;
>   theLib.def(a);
> }
> 
> As you can see, this is a tedious work. Even for a 2KB code. Is there a 
> simpler way to do this?

Depends on the library, but something like this might work:

    var theLib = (function () {

      // -- start original lib content --
      var config = {...};
      function abc () {...}
      function def () {...}  // private helper
      function ghi () {...}
      // -- end original lib content --

      // this will be the public API of the library
      return {
         abc: abc,
         ghi: ghi,
         ...
      };

    })();

    theLib.abc(123);

Not every collection of functions can be contained in this way, but it
should work for your typical bunch-of-global-functions-because-
-the-author-doesn't-know-any-better library.


- stefan

[toc] | [prev] | [next] | [standalone]


#17922

FromJJ <jaejunks@nah.meh>
Date2013-01-03 20:13 +0000
Message-ID<XnsA13E219E61C5Ejj@0.0.0.55>
In reply to#17919
Stefan Weiss <krewecherl@gmail.com> wrote:
> Okay, as long as you're aware of that calling abc() is _not_ the same
> thing as calling theLib.abc(). At least make sure to check if any of 
the
> functions use |this|.

Yes, I always watch out for any of their own objects, "this" usage and 
bound functions usage. I leave them as is, if it's beyod my capability.

> Depends on the library, but something like this might work:
> ...

That'll do very nicely. Thanks. Got to get used to this.

> Not every collection of functions can be contained in this way, but it
> should work for your typical bunch-of-global-functions-because-
> -the-author-doesn't-know-any-better library.

Like bound functions?

...
Also, do this two conversions have any functionality difference? Or may 
be leads to possible error elsewhere?

//original
function abc(){}
//conversion #1
theLib.abc=function abc(){};
//conversion #2
theLib.abc=function(){};

[toc] | [prev] | [next] | [standalone]


#17926

FromStefan Weiss <krewecherl@gmail.com>
Date2013-01-03 23:57 +0100
Message-ID<kc52d9$dau$1@news.albasani.net>
In reply to#17922
On 2013-01-03 21:13, JJ wrote:
> Stefan Weiss <krewecherl@gmail.com> wrote:
>> Not every collection of functions can be contained in this way, but it
>> should work for your typical bunch-of-global-functions-because-
>> -the-author-doesn't-know-any-better library.
> 
> Like bound functions?

Bound as in Function.prototype.bind? Maybe. Off the top of my head, I
can't think of how that would cause problems, if what the functions are
bound to is also in the scope of the anonymous closure.
I was thinking more of libraries directly setting properties on the
global object, or missing variable declarations.

> Also, do this two conversions have any functionality difference? Or may 
> be leads to possible error elsewhere?
> 
> //original
> function abc(){}
> //conversion #1
> theLib.abc=function abc(){};
> //conversion #2
> theLib.abc=function(){};

Conversion #2 has the potential to cause problems in JScript, because of
the braindead way IE handles named function expressions:

http://kangax.github.com/nfe/#jscript-bugs

This is why I generally avoid NFEs. I still want most functions to have
a name, because it makes debugging so much easier in large applications.
As a result, I often prefer function declarations over function
expressions, even if it requires the "return {...API...}" bit at the and
of a "module", like in the example from my previous post.

I do use function expressions a lot, but when I find myself writing code
like this -

    button.addEventListener("click", function (evt) {
        // 10 lines of code
        connection.post(url, params, function (resp) {
            // and maybe another nested function...
        });
    });

- I tend to refactor it into something simpler:

   button.addEventListener("click", handleClick);

   function handleClick (evt) {
        // 10 lines of code
        connection.post(url, params, receiveResponse);
   }

   function receiveResponse (resp) {
       // and maybe another nested function...
   }

This will give all functions a name, making debugging, documenting, and
visually scanning the code easier. It also keeps the function bodies
short and avoids the typical >-shape of highly nested functions
(callback hell).

All of that is just my personal preferred style, not a general
recommendation, but it has served me well over the years.


- stefan

[toc] | [prev] | [next] | [standalone]


#17928

FromStefan Weiss <krewecherl@gmail.com>
Date2013-01-04 00:44 +0100
Message-ID<kc5550$i9f$1@news.albasani.net>
In reply to#17926
On 2013-01-03 23:57, Stefan Weiss wrote:
>> //conversion #1
>> theLib.abc=function abc(){};
>> //conversion #2
>> theLib.abc=function(){};
> 
> Conversion #2 has the potential to cause problems in JScript

Typo - that should have read "Conversion #1".

- stefan

[toc] | [prev] | [next] | [standalone]


#17933

FromJJ <jaejunks@nah.meh>
Date2013-01-04 02:00 +0000
Message-ID<XnsA13E5C583F660jj@0.0.0.55>
In reply to#17926
Stefan Weiss <krewecherl@gmail.com> wrote:
> Bound as in Function.prototype.bind? Maybe. Off the top of my head, I
> can't think of how that would cause problems, if what the functions are
> bound to is also in the scope of the anonymous closure.
> I was thinking more of libraries directly setting properties on the
> global object, or missing variable declarations.

Yes, including "call" and "apply". OK. Maybe I'm just too worried.

> Conversion #1[edited] has the potential to cause problems in JScript, 
because of
> the braindead way IE handles named function expressions:
> 
> http://kangax.github.com/nfe/#jscript-bugs

Didn't know that, and that it can cause many problems. I'll keep that for 
reference, thanks.

[toc] | [prev] | [next] | [standalone]


#17920

FromScott Sauyet <scott.sauyet@gmail.com>
Date2013-01-03 10:37 -0800
Message-ID<efe2e252-786f-4956-8d17-237cdeb6681e@f8g2000yqa.googlegroups.com>
In reply to#17918
JJ  wrote:
> Sometimes I need some a library from the web, but its functions are all
> globally defined instead of object based. For example:
>
> var config=123;
> function abc(){
>   //does something
> }
> [ ... ]
> function ghi(a){
>   a=a||config;
>   abc(def(a));}
> [ ... ]
> I want to put all those functions in a self contained object so that
> accessing them would be like:
>
> theLib.abc();
> theLib.ghi();
> theLib.abc(456);
>
> Usually I would convert each functions including all of the references
> like below.
>
> theLib={};
> theLib.config=123;
> theLib.abc=function(){
>   return theLib.config;}
> [ ... ]
> theLib.ghi=function(a){
>   a=a||theLib.config;
>   theLib.abc(theLib.def(a));}
>[ ... ]
> As you can see, this is a tedious work. Even for a 2KB code. Is there a
> simpler way to do this?

My first question would be how you would distinguish between the
global variables that you do want to convert and those (possibly)
accidental ones like `a` in `ghi()` and `jkl()` above.

But if you want to pursue this, I would suggest you look at Javascript
parsers.  There are a number of them written in Javascript, including
Uglify, Narcissus, Esprima, and Acorn.  I'm sure you can find them all
quickly with a web search.  Once you have the abstract syntax tree
representation of this code, especially if they tie all statements to
lines/columns in the code, perhaps you would be able to use this to
create a new representation that simply inserted "theLib." in all the
correct spots.

It's just a thought.  I've never tried anything like this.

Best of luck,

  -- Scott

[toc] | [prev] | [next] | [standalone]


#17921

FromScott Sauyet <scott.sauyet@gmail.com>
Date2013-01-03 10:43 -0800
Message-ID<f0b05c11-efed-4c03-9660-a71f26e33895@x3g2000yqo.googlegroups.com>
In reply to#17920
Scott Sauyet wrote:
> JJ  wrote:
>> Sometimes I need some a library from the web, but its functions are all
>> globally defined instead of object based. [ ... ]
>> I want to put all those functions in a self contained object [ ... ]
> [ ...] I would suggest you look at Javascript parsers.

Or just do as Stefan suggested.  His idea is slightly less general
than mine, and requires you to actually distinguish the public API you
want to supply.  But that's probably for the better.  And it's a heck
of lot simpler!

  -- Scott

[toc] | [prev] | [next] | [standalone]


#17923

FromJJ <jaejunks@nah.meh>
Date2013-01-03 20:33 +0000
Message-ID<XnsA13E24E26DB86jj@0.0.0.55>
In reply to#17920
Scott Sauyet <scott.sauyet@gmail.com> wrote:
> My first question would be how you would distinguish between the
> global variables that you do want to convert and those (possibly)
> accidental ones like `a` in `ghi()` and `jkl()` above.

The "a" is a function parameter. It's practically a local object of that 
function rather than a global object. The code are merely examples that 
some functions depends on their own library's variable.

> But if you want to pursue this, I would suggest you look at Javascript
> parsers.  There are a number of them written in Javascript, including
> Uglify, Narcissus, Esprima, and Acorn.  I'm sure you can find them all
> quickly with a web search.  Once you have the abstract syntax tree
> representation of this code, especially if they tie all statements to
> lines/columns in the code, perhaps you would be able to use this to
> create a new representation that simply inserted "theLib." in all the
> correct spots.

Isn't Uglify a code compressor? I do have an "uglify.js", but it's based 
on simple regex search+replace. It's not aware of code syntax nor 
context. The other three are new to me. I'll check them out. Thanks.

[toc] | [prev] | [next] | [standalone]


#17924

FromScott Sauyet <scott.sauyet@gmail.com>
Date2013-01-03 13:09 -0800
Message-ID<3004f774-dc8d-4e87-9d3c-9f0d6f4930f8@x20g2000vbf.googlegroups.com>
In reply to#17923
JJ wrote:
> Scott Sauyet  wrote:
>> My first question would be how you would distinguish between the
>> global variables that you do want to convert and those (possibly)
>> accidental ones like `a` in `ghi()` and `jkl()` above.
>
> The "a" is a function parameter. It's practically a local object of that
> function rather than a global object. The code are merely examples that
> some functions depends on their own library's variable.

So, I'm blind.  So what?  :-)

>> But if you want to pursue this, I would suggest you look at Javascript
>> parsers.  There are a number of them written in Javascript, including
>> Uglify, Narcissus, Esprima, and Acorn. [ ... ]
>
> Isn't Uglify a code compressor? I do have an "uglify.js", but it's based
> on simple regex search+replace. It's not aware of code syntax nor
> context. The other three are new to me. I'll check them out. Thanks.

It must be a later version of Uglify that's based on creating an
Abstract Syntax Tree first; I think he might have released the parser
independently as well.  But I wouldn't bother with that one, as the
author later wrote Acorn as a better, faster, more standards-compliant
parser.  There's also another one I forgot to mention, called
ZeParser.

Good luck,

  -- Scott

[toc] | [prev] | [next] | [standalone]


#17934

FromJJ <jaejunks@nah.meh>
Date2013-01-04 02:33 +0000
Message-ID<XnsA13E620EF9D3Fjj@0.0.0.55>
In reply to#17924
Scott Sauyet <scott.sauyet@gmail.com> wrote:
> So, I'm blind.  So what?  :-)

Dunno... :D

> It must be a later version of Uglify that's based on creating an
> Abstract Syntax Tree first; I think he might have released the parser
> independently as well.  But I wouldn't bother with that one, as the
> author later wrote Acorn as a better, faster, more standards-compliant
> parser.  There's also another one I forgot to mention, called
> ZeParser.

I rechecked my "uglify.js" with other popular uglify-ers I could find. 
Turned out that mine is entirely different library. A lightweight library 
for compression only. Figures...-_-

I think I got enough libraries to check, thanks. Time for research...

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.javascript


csiph-web