开发者

javascript unpacking an object?

coming from clojure I nee开发者_Go百科d to write some javascript functions

Lets say I have a function that acts on some spec object.. I want to refer to the variables in spec in a local scope without having to write spec.container, spec.nrow, spec.ncol. It seems there is no native support for destructuring, is this correct? If so how would I write an unpack (depth 1) function as below? - I don't really want to use eval in it either.

var spec = {container: {width: 900, height: 600}, nrow: 4, ncol: 5, vgap: "5px"}

function grid(spec) {
   // bad..
   var width = spec.container.width;
   var height = spec.container.height;
   var nrow = spec.nrow;
   etc...

   // I would prefer to write this, then have local access to nrow, width, height, etc
   unpack(spec);
   unpack(container);
}

Thanks


You can do what you want using the following:

var spec = {container: {width: 900, height: 600}, nrow: 4, ncol: 5, vgap: "5px"}

function grid(obj) {
    // I would prefer to write this, then have local access to nrow, width, height, etc
    unpack(obj, this);
    unpack(container, this);

    //do stuff here...
}

function unpack(obj, dest) {
    for (var key in obj) {
        dest[key] = obj[key];
    }
}

Here is a working example: http://jsfiddle.net/Dsaaw/


The with() { } construct was designed for this, but it's widely considered a dangerous language element, as the rules for scope-conflict are not well defined.

I'd say either use the fully-qualified object reference, or live with the one-by-one assignment.


I'm a big fan of Coffeescript, which has "native" destructuring assignment in that it compiles to the equivalent JavaScript. I don't think there's a really elegant solution that's strictly pure JS, though. The CS would look like this

{ nrow, container: { width, height } } = spec

The JavaScript that this produces when compiled will be:

var height, nrow, width, _ref;
nrow = spec.nrow, _ref = spec.container, width = _ref.width, height = _ref.height;

aroth's solution is neat, and I was going to suggest it, actually, but I think you run a risk of scope issues. Worth a try, though.


If you want to extend this with your other object, then aroth's solution is pretty okay, especially with RobG's comment, but just make sure you know what object you are extending. For deeply nested function (whose parent is not window) you would have to say this.width rather than spec.width so that doesn't help you much, in terms of typing. Or you could not pass in this and just make global variables on window (which is essentially what is going on), which may demonstrate why this approach could be dangerous-ish.

if you want locally scoped variables to the function, then I think you pretty much have to use an eval.

function decomp(obj) {
    var result = []
    for(var i in obj) {
        switch(typeof(obj[i])) {
            case "number":
            case "boolean":
            case "string":
            result.push("var "+i+"="+obj[i].constructor.name+"(\""+obj[i].valueOf()+"\");")
        }
    }

    return result.join('');
}

var someObject = {
    worker: function(obj) {
        eval(decomp(obj));
        eval(decomp(obj.container));

        alert(width);
    }
}

var spec = {container: {width: 900, height: 600}, nrow: 4, ncol: 5, vgap: "5px", test: true }

someObject.worker(spec)

Play around with it here here

I know that you said you would prefer not to use eval() but I can't think of any other way to really do what you want. Its between eval(), extending this (which may or may not be window), or writing a js pre-processor that unrolls it for you.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜