3

I'm investigating some code outside my scope that's written in a style I've never seen before. I'm trying to understand the inner workings of the following property bag:

Setter:

props.Property(name) = val;

Getter:

val = props.Property(name);

What would you need to instantiate for the setter to function as above?

EDIT: Less simplification, this code IS successfully running on a BrowserWindow within a frame (similar to a phone environment).

var UI =
        {
            ready: function(oProps)
            {
                try
                {
                    if (oProps)
                    {
                        window.external.Property(UI.FrameWidth) = '1000';
                        window.external.Property(UI.FrameHeight) = '900';
                    }

                    window.external.Ready();
                }
                catch (e) { }
            }
    };

Thanks in advance,

Valchris
  • 1,451
  • 2
  • 14
  • 33
  • 4
    That setter code doesn't look legit. `props.Property(name)` isn't an Lvalue. Are you sure that's the exact code? – Jacob Sep 16 '13 at 22:18
  • My thoughts exactly. I can confirm it's without typo. – Valchris Sep 16 '13 at 22:20
  • 1
    The return value of a function call is a value, not a reference. That would result in a reference error. – Fabrício Matté Sep 16 '13 at 22:21
  • Maybe this code outside your scope simply contains errors. Have you verified the setter running successfully? – Jacob Sep 16 '13 at 22:25
  • Updated in case my simplified version cut out context. – Valchris Sep 16 '13 at 22:34
  • 1
    have you tried a window.external.Property.toString() to see its function code? – Mike 'Pomax' Kamermans Sep 16 '13 at 22:37
  • 1
    The code above is wrapped in a silent try catch block, so it *seems* to be running successfully but actually isn't. Try logging the caught exception in the `catch` block. – Asad Saeeduddin Sep 16 '13 at 22:40
  • I agree with Asad. This looks like it executes `window.external.Property(UI.FrameWidth)`, then throws an exception when the assignment is attempted. Thus `window.external.Property(UI.FrameHeight)` is more than likely never executed. The `try catch` block just hides the exception. – Travis J Sep 16 '13 at 22:41
  • I understand the silent try catch, but the property itself is updated. Is it possible that JS is executing the left hand operation before throwing an except on assignment? Thus the function on the left succeeds and then bombs out from syntax? The results I'm seeing don't line up with my expectations at all. – Valchris Sep 16 '13 at 22:42
  • @valchris No, the statement isn't executed at all. Check the value of `window.a` in a console in this demonstration: http://jsfiddle.net/6etsj/show. You can see the code here: http://jsfiddle.net/6etsj/ – Asad Saeeduddin Sep 16 '13 at 22:46
  • 3
    At first I thought, "Maybe the Property() method is returning a reference..." then I saw this: http://stackoverflow.com/a/16687027/136062 – Eric Lloyd Sep 16 '13 at 22:47
  • Thanks Eric! I'll keep reading...this seems to be along the lines of what I'm seeing. – Valchris Sep 16 '13 at 22:52
  • 2
    If that is really the code (and it is working without a reference error), you just have found an answer to my [*Real world examples of a function returing a reference* question](http://stackoverflow.com/questions/13124417/real-world-examples-of-ecmascript-functions-returning-a-reference). Please elaborate there what that `window.external` environment is… – Bergi Sep 16 '13 at 23:05

3 Answers3

8

I think it might be just some weird old JScript syntax. Steering away from the "internal function returns a reference" idea from the comments, I found a question about differences between JavaScript and JScript and the only syntax difference listed is this one:

The idiom f(x) = y, which is roughly equivalent to f[x] = y.

There isn't much too find about this idiom though. However, this book about Jscript.Net briefly mentions that

you can access any expando properties using square brackets or parenthesis.

"expando" seems to be a modifier for classes which allows you to add dynamic properties.

Community
  • 1
  • 1
kapex
  • 28,903
  • 6
  • 107
  • 121
  • 1
    I think you've found exactly what I was looking for. The target browser is using an implementation of JScript. I'll do a little more investigation before finalizing my answer. – Valchris Sep 17 '13 at 17:25
  • 2
    You're right. I actually tried searching for "differences between JScript and JavaScript" when I saw the question, but all I came across was [any number of people](http://stackoverflow.com/questions/135203/whats-the-difference-between-javascript-and-jscript) (including Douglas Crockford himself!) saying that JScript and JavaScript differ only in name. Guess I gave up that line of inquiry too soon. Edit: [The correct answer](http://stackoverflow.com/a/135256/1726343) (which mentions this difference) was buried under several other answers which say JScript === JavaScript – Asad Saeeduddin Sep 17 '13 at 19:19
3

The code above is wrapped in a silent try catch block, so it is possible that it seems to be running successfully but actually isn't.

Try logging the caught exception in the catch block. You should get a ReferenceError if this line:

window.external.Property(UI.FrameWidth) = '1000';

is ever hit (which of course depends on the value of oProps).

Asad Saeeduddin
  • 46,193
  • 6
  • 90
  • 139
1

This setter approach cannot work. No matter what the function returns, if you use a function call as sole expression left-hand side (LHS) of an assignment expression, you are getting

ReferenceError: Invalid left-hand side in assignment

and the like. As the others have said, you are not seeing the ReferenceError exception because it is caught as it is being thrown and there is no code to handle it. Functions are first-class objects, but calls to them are not valid LHS values. You will see that clearly if you insert console.log(e); in the catch block.

This getter approach can work. However, if you want getters and setters, at the latest in a conforming implementation of ECMAScript Edition 5 you can have that natively:

Object.defineProperty(props, "name", (function () {
  var _value;

  return {
    set: function (value) {
      /* setter code, simple example */
      _value = String(value);
    },

    get: function () {
      /* getter code, simple example */
      return _value;
    }
  };
}()));

/* triggers the setter */
props.name = 42;

/* triggers the getter */
var x = props.name;

/* "42" */
x

“Edit 2” –

var someObjs = [{a:"",someProp:"b"}];
(function (a) { return someObjs[a]})(0).someProp = "c";
console.log(someObjs[0].someProp);

– works because the return value of the function is used LHS, but as part of another expression that evaluates to a property access (using the dot property accessor syntax). The function returns a reference to an object (to an Object instance) whose property is then accessed. The property access being the LHS of an assignment expression, the RHS value ("c") is assigned to that property.

It is functionally equivalent to

var someObjs = [
  {a: "", someProp: "b"}
];

(function () {
  return someObjs[0];
}()).someProp = "c";

console.log(someObjs[0].someProp);

and therefore to

someObjs[0].someProp = "c";
console.log(someObjs[0].someProp);

(as you can see, good code style helps a lot with understanding code)

PointedEars
  • 14,752
  • 4
  • 34
  • 33
  • Thanks for your breakdown PointedEars. I'm planning on getting more context tomorrow and hopefully that'll help me understand if this is indeed what is happening. – Valchris Sep 16 '13 at 23:59