0

I'm trying to implement a dictionary much like Python. So, I would like to have a keys() method that returns keys added to the subclass Dict, but not properties such as the Object's method "keys"

EDIT AGAIN Basically, I'm making a class to pass settings to a function like function(arg1, arg2, myObj) where my object is {map: texMap, alphaMap: aTexMap}. It's for Three.js, and I have to wait on images to download before I can create settings on 3D objects. So, interface like one would expect with d in var d = { a: aData b: bData }, but hide the methods etc that are not added by the user.

ie don't return this.prototype.propertyName when own is passed

Here's what I have so far:

function Dict(){
    this.prototype = {};
    var _keys = this.prototype.keys;
    this.keys = function(own){
        if(typeof own === 'undefined') { return _keys(); }
        var ownKeys = [];
        for(var key in _keys()){
            if(this.hasOwnProperty(key)) {
                ownKeys.push(key);
            }
        }
        return ownKeys;
    }
}

Will this work as follows? Is there a better or already existent way to do it?

  • save the overloaded keys() method to a private var
  • return everything as usual, unless own is something that resolves to true.
  • if own == true, get the usual keys and filter out those belonging to the superclass.

On the subject, I'm likely most concerned about saving back the prototype method as a way to get all of the keys and filter out proto keys.

Also, I've read overloading isn't built into Javascript. But, much of what I've found deals with standalone functions such as this Q&A on best practices. I don't need a built in way, but I'll take advantage of whatever's available (Hence, using Object as a Dict).

Any feedback is appreciated!

EDIT In Python, we get this:

In[2]:  d = {}
In[3]:  'has_key' in d.keys()
Out[3]: False
In[7]:  'has_key' in d.__class__.__dict__.keys()
Out[7]: True
In[8]:  d.has_key('has_key')
Out[8]: False
In[9]:  d['newKey'] = 5
In[10]: d.newKey  # ERROR

Python has a dict attribute contained in its class where the functions are accessed via a dot (see In[8]...). So, those standard {} or dict() functions and operators are hidden (not private) while keys/data are added to the user's dict are accessed via []. d['newKey'] = 5 adds a new key or overwrites the old and sets the data to 5.

I don't need all of that to work, though it would be great. keys() returning Python-like keys would be fine for now.

Community
  • 1
  • 1
Lab Hatter
  • 13
  • 4
  • Is there a deeper meaning to this "I want JavaScript to work like Python"? – Tomalak Nov 25 '15 at 21:56
  • It's a little confusing what you're asking. JavaScript has a [getOwnPropertyNames](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyNames) method that will get the property names of the current object, and not those of others in the prototype chain... – Heretic Monkey Nov 25 '15 at 21:59
  • This looks like a classic XY-problem. Instead of describing the anticipated solution you should describe the job you are trying to do. – Tomalak Nov 25 '15 at 22:01
  • Please provide an intended usage of `Dict`. Who cares about the implementation? The best benefit there is to creating a new class is you get the make the API whatever you want to be. Is the goal to just copy Python's Dictionary class? The code you have right now is completely atrocious as far as idiomatic JS goes. – Mulan Nov 25 '15 at 22:02
  • @MikeMcCaughan If getOwnPropertyNames is all that's needed to be reliable why do I read so many solutions like http://stackoverflow.com/questions/135448/how-do-i-check-if-an-object-has-a-property-in-javascript ? Why not just call your function and check for presence? – Lab Hatter Nov 25 '15 at 22:32
  • That article is from 2008. Things have changed since then :). I suggest learning more about how objects work in JavaScript before endeavoring to bring language features from another language into it. – Heretic Monkey Nov 25 '15 at 22:46
  • @MikeMcCaughan Thanks for the good news! and the advice. – Lab Hatter Nov 25 '15 at 23:13

1 Answers1

0

There seem to be multiple issues here.

You seem to want to pass variable arguments to a function:

I'm making a class to pass settings to a function like function(arg1, arg2, myObj) where my object is {map: texMap, alphaMap: aTexMap}.

JS function arguments are very flexible.

  • You can either set up names for every one of them:

    function foo(arg1, arg2, map, alphaMap)
    

    and pass values directly. This style is preferred for functions that work on a fixed set of arguments.

  • Or you can set up an "options" object that collects keys and values:

    function foo(options)
    

    and pass {arg1: val1, arg2: val2, map: valMap, alphaMap: valAlphaMap}. This style often occurs on constructor functions that initialize objects with a certain set configuration options.

  • Or you can set up an empty function signature

    function foo() 
    

    and work with the arguments collection inside the function. This is found in functions that work with a variable number of uniform arguments (imagine add(1, 2, 3, 4, 6)) or strictly positional arguments instead of named ones.

In any case, passing arguments to a function is optional in JavaScript, even when there is an argument list in the function signature. You are free to pass none, less or more arguments. Of course all these approaches can be combined if it suits you.


It's for Three.js, and I have to wait on images to download before I can create settings on 3D objects.

This is a problem caused by the asynchronous nature of the web. The solution is to use event handlers. These are either callbacks or - as an abstraction over callbacks - promises.


So, interface like one would expect with d in var d = { a: aData b: bData }, but hide the methods etc that are not added by the user.

This can be solved by not adding methods etc to data objects, or at least not directly. Add them to the prototype if your data objects must have behavior.


The direct equivalent to a Python Dict is a plain object in JavaScript.

var dict = {};

The direct equivalent of Python's keys() method is the Object.keys() static method in JavaScript.

var keys = Object.keys(dict);

To iterate the keys you can either use an imperative approach:

var i, key;
for (i = 0; i < keys.length; i++) {
    key = keys[i];
    doSomething(key, dict[key]);
}

or a functional one

keys.forEach(function (key) {
    doSomething(key, dict[key]);
});

The direct equivalent of Python's in is .hasOwnProperty() in JavaScript:

if ( dict.hasOwnProperty('foo') ) ...

or, if it is a pure data object with no prototype chain, you can use in as well.

if ('foo' in dict)

Using in in for loops is not recommendable because it iterates the prototype properties as well. The way to guard against this is by using Object.keys() instead or by combining it with .hasOwnProperty(), as you did.

var key;
for (key in dict) {
    if ( dict.hasOwnProperty(key) ) ...
}

Your question indicates that you are missing basic puzzle pieces about JS and try to substitute them with more familiar Python constructs. I would recommend not doing that.

I also suspect that you try to shoehorn Python's class-based inhertiance pattern into JS' prototype-based inheritance pattern. I strongly recommend that you don't do that, either.

Tomalak
  • 332,285
  • 67
  • 532
  • 628
  • Thanks! You've answered many questions I thought unrelated, even a basic definition of promises. Not that this is the only way to go, yet it seems this will eventually lead me into [Functional Reactive Programming](http://stackoverflow.com/questions/33927034/javascript-how-to-overload-a-method-and-handle-keys/33932943#33932943) – Lab Hatter Nov 27 '15 at 23:02
  • Sounds like you've made quite some progress in these few hours! Thanks for the feedback. – Tomalak Nov 28 '15 at 09:27